A coworker showed me a demo for dragging
across checkboxes to check or uncheck them, and asked that I implement it in my own
AJAX library. The cross-browser demo he came across answered a specific
question which required the use of tables and tds, but I wanted to be able to accomplish
the same feat without depending on unrelated tags.
I quickly whipped up a solution that targets the checkboxes and their labels, but the solution was easy enough that I figured I'd get rid of the library dependencies and share the method in good old fashioned cross-browser JavaScript.
<!-- This HTML is used for the following example --> <label for="check1">Check:</label> <input type="checkbox" id="check1"> <label for="check2">Check:</label> <input type="checkbox" id="check2"> <label for="check3">Check:</label> <input type="checkbox" id="check3"> <label for="check4">Check:</label> <input type="checkbox" id="check4"> <label for="check5">Check:</label> <input type="checkbox" id="check5"> <label for="check6">Check:</label> <input type="checkbox" id="check6">
var dragCheckbox = function(root) {
root = root || document;
var dragging = false;
var current = false;
document.onmouseup = function() {
dragging = false;
};
var getTarget = function(element) {
switch (element.tagName.toLowerCase()) {
case 'input':
return element;
break;
case 'label':
element.style['MozUserSelect'] = 'none'; // Firefox and other Gecko
element.style['WebkitUserSelect'] = 'ignore'; // Safari, Chrome, AIR
element.onselectstart = function() {
return false; // IE
};
var el = element.getAttribute('for') || element.getAttribute('htmlFor');
return document.getElementById(el);
break;
default:
return null; // invalid element
}
};
var checkboxes = function() {
var c = [];
var inputs = root.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].getAttribute('type') == 'checkbox') {
c.push(inputs[i]);
}
}
return c;
}();
for (var i = 0; i < checkboxes.length; i++) {
(function() {
var down = function() {
var box = getTarget(this);
if (box) {
dragging = true;
box.checked = !box.checked;
current = box.checked;
}
};
var over = function() {
var box = getTarget(this);
if (box && dragging) {
box.checked = current;
}
};
var click = function() {
var box = getTarget(this);
if (box) {
box.checked = current;
}
};
this.onmousedown = function() { down.call(this); };
this.onmouseover = function() { over.call(this); };
this.onclick = function() { click.call(this); };
var label = (function() {
var l = root.getElementsByTagName('label');
for (var i = 0; i < l.length; i++) {
var f = l[i].getAttribute('for') || l[i].getAttribute('htmlFor');
if (f == this.id) {
return l[i];
}
}
return l;
}).call(this);
if (label) {
label.onmousedown = function() { down.call(label); };
label.onmouseover = function() { over.call(label); };
label.onclick = function() { click.call(label); };
}
}).call(checkboxes[i]);
}
};
Useful? Not? You decide.
I'm a Front-End Engineer at Yahoo! working on the Mail and Messenger teams. I blog about web design and development topics including accessibility, usability, performance, and developing HTML / CSS / JavaScript applications on Appcelerator Titanium and Adobe AIR.
If you're a web developer, you might enjoy Jelo, my JavaScript library.
All original work on this site is covered by a Creative Commons Attribution 3.0 license unless otherwise specified.
You may share or use any code or images from this site in any manner, for free, so long as reasonable effort has been made to give credit where due.
The views expressed in the posts and comments on this blog do not necessarily reflect the views of Yahoo!