Reputation: 270
I have a jsfiddle Here: http://jsfiddle.net/zAFND/616
Now if you open up fiddle in IE (I use IE9) and firefox, if you double click on a check box button, it turns it on but does not turn it off. But if you open it up in opera, safarai and chrome, it works fine if you double click or click in quick succession.
My question is how to allow quick succession clicks to work correctly in firefox and IE9?
Code:
HTML:
<div id="ck-button"><label>
<input type="checkbox" name="options[]" id="optionA" value="A" /><span>A</span></label>
</div>
CSS:
#ck-button {
margin:8px;
background-color:#EFEFEF;
border:1px solid #D0D0D0;
overflow:auto;
float:left;
position: relative;
}
#ck-button label {
float:left;
width:4.0em;
cursor:pointer;
}
#ck-button label span {
text-align:center;
padding:3px 0px;
display:block;
}
#ck-button label input {
position:absolute;
top:-20px;
}
#ck-button input:checked + span {
background-color:green;
color:white;
}
Jquery/javasscript:
$(document).ready(function(){
$("body").css("-webkit-user-select","none");
$("body").css("-moz-user-select","none");
$("body").css("-ms-user-select","none");
$("body").css("-o-user-select","none");
$("body").css("user-select","none");
});
Upvotes: 3
Views: 4120
Reputation: 70189
This is a bug in Firefox. See Bug 608180 - Double/rapid clicking a checkbox label does not work as expected
IE has, for historical reasons (but fixed in more recent versions), a bugged event model that skips the second mousedown
and click
events on a double click. See bug 263 - beware of DoubleClick in IE.
I've made a plugin that fixes some bugs in jQuery UI button widget as well as working around the Firefox bug not long ago, shouldn't be hard to adapt it to your non-jQuery UI buttons.
Extracted the important part and adapted it for nested checkboxes inside label
s:
(function () {
var mdtarg, //last label mousedown target
mdchecked, //checked property when mousedown fired
fixedLabelSelector = '.fixedLabelCheckbox'; //edit as you see fit
$(document).on('mousedown', fixedLabelSelector, function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
mdtarg = this;
mdchecked = this.control ? this.control.checked : $(this).find('input')[0].checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', fixedLabelSelector, function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = this.control || $(this).find('input')[0];
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}());
Fiddle tested in Firefox.
You have to add the fixedLabelCheckbox
class to all labels containing checkboxes that you'd like to fix with the code above.
It will work regardless of where you put the script and it also fixes dynamically added checkboxes as long as the label has the corresponding delegated class/selector.
Note that if you're using other libraries, this may not fire the change handlers bound outside of jQuery.
If you don't feel like adding extra classes to your markup, you can use this version (more code and less performance):
(function ($) {
function getControl(lbl) { //fallback for non-HTML5 browsers if necessary
return lbl.control || (lbl.htmlFor ? $('input[id="'+lbl.htmlFor+'"]')[0] : $(lbl).find('input')[0]);
}
var mdtarg, //last label mousedown target
mdchecked; //checked property when mousedown fired
$(document).on('mousedown', 'label', function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
var ch = getControl(this);
if (!ch || ch.type !== 'checkbox') return;
mdtarg = this;
mdchecked = ch.checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', 'label', function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = getControl(this);
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}(jQuery));
As you can see from the code above, this version should work with both label's for
attribute as well as nested inputs inside the label, without adding any extra markup.
About disabling selection: you can either put the user-select
in the CSS as commented in your question, or, if browsers that don't support the user-select
are also concerned, apply this answer on all labels that you want to have selection disabled.
Upvotes: 3
Reputation: 1170
You could add browser detection and then, if IE or Firefox, add the ondblclick
event via JS to invert the checkbox.
You can't just set it unconditionally, since some browsers (Safari, Chrome) transmit two click
s and a dblclick
, while others (IE, Firefox) transmit only one click
and one dblclick
. On the former, the two click
events will invert the field twice. On the latter, only one click
event fires and thus the field is only inverted once; to mitigate this, you need to make dblclick
invert the field so that two clicks invert it an even number of times.
Hope this helps!!
Upvotes: 0