Opened 22 months ago
Last modified 6 months ago
#18590 new enhancement
Swap out "return false" JS calls for preventDefault
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Administration | Version: | 3.3 |
| Severity: | normal | Keywords: | needs-testing has-patch |
| Cc: | dkikizas@…, solaris.smoke@…, r@… |
Description
While trying to hook into someone clicking the expand/collapse arrow in the nav menu UI, I realized that the existing Javascript is using return false; to abort the hyperlink click from going through.
We should be using object.preventDefault() instead so that other bound functions aren't aborted.
Attachments (2)
Change History (13)
comment:3
in reply to:
↑ 2
;
follow-up:
↓ 8
Viper007Bond
— 22 months ago
Replying to azaozz:
We are (should be) using return false to do both which is usually the case. Note that this doesn't stop the 'immediate propagation', i.e. if there are several 'click' handlers on the same element they all fire.
Yes, if my code does $('#foo').click( ... ) it will work, but the return false blocks $('#foo').live('click', ... ) from working (i.e. attaching the click event to subsequently added items).
I ended up having to use $('#foo').live('mouseover', ...) to hack around it.
comment:4
Viper007Bond
— 22 months ago
Here's my code incase things are unclear:
jQuery(document).ready(function($) {
// ID tracker field
var IDtracker = $('<input>').attr({
type: 'hidden',
id: ADASIParams.idtracker,
name: ADASIParams.idtracker,
value: ''
}).prependTo('#update-nav-menu');
function adasi_add_checkbox( item ) {
// Skip items that are known not to be hierarchical post types or that we already modified
if ( $(item).is('.adasi-checked, .menu-item-custom, .menu-item-category, .menu-item-post_tag') ) {
return;
}
// Don't check this item again
$(item).addClass('adasi-checked');
var itemID = parseInt( $(item).attr('id').replace('menu-item-', ''), 10 );
// Gotta figure it out in PHP, so use an AJAX call
jQuery.post(
ajaxurl,
{
action: ADASIParams.ajaxaction,
id: itemID
},
function( response ){
if ( response && response.add ) {
// Track IDs to check the POST for
IDtracker.val( IDtracker.val() + ',' + itemID );
// Add the checkbox
var checkboxid = ADASIParams.checkboxprefix + itemID;
$(item).find('.menu-item-actions .link-to-original').after('<p><label><input type="checkbox" id="' + checkboxid + '" name="' + checkboxid + '" value="1" /> ' + ADASIParams.checkboxdesc + '</label></p>');
if ( response.checked ) {
$('#' + checkboxid).prop('checked', true);
}
}
},
'json'
);
}
// Try adding checkboxes to all existing menu items
$('.menu-item').each(function(){
adasi_add_checkbox( this );
});
// When hovering over a menu item added using Javascript, try adding a checkbox to it.
// Props DD32 for mouseover hack to get around return false; inside other click bound event.
$('.menu-item.pending').live('mouseover', function(){
adasi_add_checkbox( this );
});
});
comment:5
Viper007Bond
— 22 months ago
comment:6
sanchothefat
— 22 months ago
@Viper have you tried using jQuery's namespaced event bindings?
My approach for hooking onto elements with a click handler attached is to use the syntax described here http://docs.jquery.com/Namespaced_Events
For example you would use:
$( '#foo' ).live( 'click.myplugin', function() { ... } );
Essentially this approach sandboxes your plugin code from the default code. There is a big advantage to this in that it means that people can unbind and rebind specific handlers - useful for plugin/theme authors who need a little extra control or a different behaviour. Think of it as the action/filter API but for jquery events. In some cases I unbind the standard wordpress click handler and add some of my own code before it eg. for pre-processing some data before widgets are saved.
comment:7
solarissmoke
— 22 months ago
- Cc solaris.smoke@… added
comment:8
in reply to:
↑ 3
nacin
— 19 months ago
Replying to Viper007Bond:
I ended up having to use $('#foo').live('mouseover', ...) to hack around it.
For that matter, we also should kill all uses of .live().
I would not mind an audit of current return false statements in our JS.
comment:9
robmiller
— 6 months ago
Attached is an audit of current uses of return false; it naturally doesn't attempt to make a distinction between logical uses and ones where it's being used to suppress default event handlers. I'm going to nip through and grab the low-hanging fruit (i.e. the most obvious uses where preventDefault is the correct option).
comment:10
robmiller
— 6 months ago
- Cc r@… added
- Keywords needs-testing added
Aaand here's a patch of the low-hanging fruit. I've not changed anything where there was even ambiguity about whether the return false was necessary, but testing would still be good.
comment:11
robmiller
— 6 months ago
- Keywords has-patch added; needs-patch removed
The linked article explains this well (although in quite a few words): "Only use return false when you want both preventDefault() and stopPropagation()".
We are (should be) using return false to do both which is usually the case. Note that this doesn't stop the 'immediate propagation', i.e. if there are several 'click' handlers on the same element they all fire.