Skip to content

Instantly share code, notes, and snippets.

@mhinze
Created September 2, 2011 05:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mhinze/1187989 to your computer and use it in GitHub Desktop.
Save mhinze/1187989 to your computer and use it in GitHub Desktop.
tri state check box
// tristate.js
// usage: $('.child').tristate({ parent: '#master' });
(function ($) {
$.fn.tristate = function (options) {
var defaults = {
checkedClass: 'checked',
uncheckedClass: 'unchecked',
indeterminateClass: 'indeterminate',
parent: ''
};
var opts = $.extend(defaults, options);
opts.parent = opts.parent instanceof $ ? opts.parent : $(opts.parent);
var INDETERMINATE = 'indeterminate';
var CHECKED = 'checked';
var utils = {
check: function ($el) {
$el
.removeClass(opts.uncheckedClass)
.removeClass(opts.indeterminateClass)
.removeAttr(INDETERMINATE)
.attr(CHECKED, CHECKED)
.addClass(opts.checkedClass);
},
uncheck: function ($el) {
$el
.removeClass(opts.checkedClass)
.removeClass(opts.indeterminateClass)
.removeAttr(INDETERMINATE)
.removeAttr(CHECKED)
.addClass(opts.uncheckedClass);
},
indeterminate: function ($el) {
$el
.removeClass(opts.checkedClass)
.removeClass(opts.uncheckedClass)
.removeAttr(CHECKED)
.attr(INDETERMINATE, true)
.addClass(opts.indeterminateClass);
},
is_checked: function ($el) {
return $el.is(':checked');
},
was_indeterminate: function ($el) {
return $el.hasClass(opts.indeterminateClass);
},
count: function (arr, fn) {
var result = 0;
var length = arr.length;
for (var i = 0; i < length; i++) {
if (fn(arr[i])) {
result++;
}
}
return result;
}
};
var children_data = 'tristate.children';
var parent_data = 'tristate.parent';
var modify_children = function (parent) {
var children = $(parent).data(children_data);
$.each(children, function () {
if (utils.is_checked($(parent))) {
utils.check($(this));
} else {
utils.uncheck($(this));
}
$(this).trigger('parent_changed_tristate');
});
};
var notify_parent = function (el) {
var parent = $(el).data(parent_data);
if (parent) {
parent.trigger('child_changed_tristate');
}
};
opts.parent.bind({
'click': function () {
if (utils.was_indeterminate($(this)) || utils.is_checked($(this))) {
utils.check($(this));
notify_parent(this);
}
if (!utils.is_checked($(this))) {
utils.uncheck($(this));
}
modify_children(this);
},
'parent_changed_tristate': function () {
modify_children(this);
},
'child_changed_tristate': function () {
var data = $(this).data(children_data);
var count = utils.count(data, function (el) {
return utils.is_checked($(el));
});
if (count == 0) {
utils.uncheck($(this));
} else if (count === data.length) {
utils.check($(this));
} else {
utils.indeterminate($(this));
}
notify_parent(this);
}
});
this.each(function () {
$(this).data(parent_data, opts.parent);
var array = (opts.parent.data(children_data) || []);
array.push(this);
opts.parent.data(children_data, array);
}).bind('click', function () {
if (utils.is_checked($(this))) {
utils.check($(this));
}
else {
utils.uncheck($(this));
}
notify_parent(this);
});
notify_parent(this.eq(1));
return this;
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment