I'm having a problem writing event handling code for a custom checkbox control, and I'm hoping that someone here might be able to help.
The basic event handling for toggling the checkbox works fine; the problem lies with trying to match behaviour of proper checkbox controls as closely as possible, specifically in relation to interaction with other event handlers that may be attached to one of my checkboxes and which may call preventDefault().
Experimenting with a proper checkbox, with both an event handler attached directly to the control, and a delegate one created with .on(), if preventDefault() is called, it blocks the toggle of the checkmark. If one of these event handlers calls a function with setTimeout(), which calls preventDefault(), this is ignored and the checkmark is toggled. This is the behaviour I wish to emulate.
As can be seen with the code below, I tackle this by toggling the checkbox state, then doing a check of isDefaultPrevented() on the event within a setTimeout() call, which should execute immediately after all event handlers have executed (including bubbling). If any event handler called preventDefault() then I toggle the checkmark back again.
When an event handler (test #1) is attached directly to the checkbox, and calls preventDefault(), this works perfectly as intended. The problem lies with the delegated event handler, as in test #2. With the delegated event handler, if I click on the checkbox's label, it works perfectly as intended (change cancelled), however if I click directly on the checkbox, or set focus to it and press the space bar, it does not, the checkmark is toggled...
Behaviour is identical across Firefox, Chrome, Opera, IE8 and IE9, so it must be either something I'm doing or a bug in jQuery.
$cm.on('keydown', {cm:$cm}, function(event) { if (keyPressFilter(event, event.data.cm)) { action(event, event.data.cm); } }); //Certain key presses (SPACE key) when checkmark has focus should toggle it!
$cm.on('keypress', {cm:$cm}, function(event) { if (keyPressFilter(event, event.data.cm)) { return false; } }); //Cancel default action for keypress events, else pressing SPACE to toggle a checkmark jumps the page around also
$cml.on('click', {cm:$cm}, function(event) { event.data.cm.trigger('click'); }); //Clicking on label should trigger action on checkmark (best to trigger click event so all event handlers run)
// Register hover events
// These are registered on the label and should change the appearance of the checkbox on hovering over the label
$cml.on('mouseenter', {cm:$cm}, function() {
if ($cm.hasClass('w-checkbox-disabled')) { return; }
$cm.addClass('w-checkbox-hover');
});
$cml.on('mouseleave', {cm:$cm}, function() {
if ($cm.hasClass('w-checkbox-disabled')) { return; }
$cm.removeClass('w-checkbox-hover');
});
var keyPressFilter = function(event, $cm) {
if (event.keyCode && event.keyCode === $.ui.keyCode.SPACE) { return true; }
return false;
};
var action = function(event, $cm) {
// Ignore event if checkbox disabled
if ($cm.hasClass('w-checkbox-disabled')) { return; }
var $control = $cm.closest('div.w-checkbox');
var $cmv = $control.find('input.w-checkbox-value').eq(0);