1/* File: jstree.nativecheckbox.js 2Adds checkboxes to the tree 3Uses input type="checkbox" to render (although not for tracking state) 4 5We have to place the checkbox outside of the item link else the link e.preventDefault() interferes with checkbox state updates 6(This does however break hover highlights: in the non-native case the checkbox is included in the highlight, here it isn't.) 7 8TODO: 9 * hover highlights 10 * general tidy-up 11 * merge into the original checkbox code, either using images or native as a configuration option or 'detect' using https://gist.github.com/2318497 12 * respect three-state option properly: currently appears to break all parent node updates if off? 13 * verify get/set_state and get_json - appear broken in the code I copied? 14*/ 15(function($) { 16 $.jstree.plugin("nativecheckbox", { 17 __construct: function() { 18 this.get_container() 19 .bind("__construct.jstree", $.proxy(function() { 20 // TODO: on move/copy - clean new location and parents 21 }, this)) 22 .bind("move_node.jstree, copy_node.jstree", function(e, data) { 23 if (data.rslt.old_instance && data.rslt.old_parent && $.isFunction(data.rslt.old_instance.checkbox_repair)) { 24 data.rslt.old_instance.checkbox_repair(data.rslt.old_parent); 25 } 26 if (data.rslt.new_instance && $.isFunction(data.rslt.new_instance.checkbox_repair)) { 27 data.rslt.new_instance.checkbox_repair(data.rslt.parent); 28 } 29 }) 30 .bind("delete_node.jstree", function(e, data) { 31 this.checkbox_repair(data.rslt.parent); 32 }) 33 .delegate("input.jstree-nativecheckbox", "click.jstree", $.proxy(function(e) { 34 var obj = this.get_node(e.currentTarget); 35 this.toggle_check(obj, true); 36 }, this)) 37 .delegate("a", "click.jstree", $.proxy(function(e) { 38 e.preventDefault(); 39 e.currentTarget.blur(); 40 var obj = this.get_node(e.currentTarget); 41 this.toggle_check(obj, false); 42 }, this)); 43 }, 44 defaults: { 45 three_state: true 46 }, 47 _fn: { 48 /* 49 Group: (native) checkbox functions 50 */ 51 check_node: function(obj) { 52 obj = this.get_node(obj); 53 // Check this node and all children 54 obj.find(' > input.jstree-nativecheckbox').removeClass('jstree-unchecked jstree-undetermined').addClass('jstree-checked').prop('checked', true).prop('indeterminate', false); 55 this.checkbox_repair(obj); 56 }, 57 uncheck_node: function(obj) { 58 obj = this.get_node(obj); 59 // Uncheck this node and all children 60 obj.find(' > input.jstree-nativecheckbox').removeClass('jstree-checked jstree-undetermined').addClass('jstree-unchecked').prop('checked', false).prop('indeterminate', false); 61 this.checkbox_repair(obj); 62 }, 63 toggle_check: function(obj) { 64 var cb = obj.find(' > input.jstree-nativecheckbox'); 65 var isChecked = cb.is(':checked'); 66 if (cb.hasClass('jstree-checked')) { 67 cb.removeClass('jstree-checked jstree-undetermined').addClass('jstree-unchecked'); 68 if (isChecked) { 69 cb.prop('checked', false).prop('indeterminate', false); 70 } 71 } else { 72 cb.removeClass('jstree-unchecked jstree-undetermined').addClass('jstree-checked'); 73 if (!isChecked) { 74 cb.prop('checked', true).prop('indeterminate', false); 75 } 76 } 77 this.checkbox_repair(this.get_node(obj)); 78 }, 79 uncheck_all: function(context) { 80 var ret = context ? $(context).find(".jstree-checked").closest('li') : this.get_container().find(".jstree-checked").closest('li'); 81 ret.children(".jstree-nativecheckbox").removeClass("jstree-checked jstree-undetermined").addClass('jstree-unchecked').children(':checkbox').prop('checked', false).prop('undermined', false); 82 this.__callback({ "obj": ret }); 83 }, 84 85 checkbox_repair: function(obj) { 86 if (!obj || obj === -1) { 87 // No arguments; repair all checkboxes 88 obj = this.get_container_ul().children('li'); 89 } 90 if (obj.length > 1) { 91 // We don't currently support this for native checkboxes 92 return; 93 } 94 95 // Work up the tree setting each parent node value correctly 96 var c = obj.find(' > input.jstree-nativecheckbox'), 97 fix_up = true, 98 p, st, sc, su, si; 99 100 if (!c.hasClass('jstree-checked') && !c.hasClass('jstree-unchecked')) { 101 // No checked or unchecked children; either all indeterminate or no children 102 p = this.get_parent(obj); 103 if (p && p !== -1 && p.length && p.find('> a > .jstree-checked')) { 104 c.removeClass('jstree-unchecked jstree-undetermined').addClass('jstree-checked').prop('checked', true).prop('indeterminate', false); 105 } else { 106 c.removeClass('jstree-checked jstree-undetermined').addClass('jstree-unchecked').prop('checked', false).prop('indeterminate', false); 107 } 108 fix_up = false; 109 } 110 111 if (c.hasClass('jstree-checked')) { 112 obj.find('.jstree-nativecheckbox').removeClass('jstree-unchecked jstree-undetermined').addClass('jstree-checked').prop('checked', true).prop('indeterminate', false); 113 } 114 if (c.hasClass('jstree-unchecked')) { 115 obj.find('.jstree-nativecheckbox').removeClass('jstree-checked jstree-undetermined').addClass('jstree-unchecked').prop('checked', false).prop('indeterminate', false); 116 } 117 118 while (fix_up) { 119 obj = this.get_parent(obj); 120 if (!obj || obj === -1 || !obj.length) { return; } 121 122 st = obj.find(' > ul > li'); 123 sc = st.find(' > input.jstree-nativecheckbox.jstree-checked').length; 124 su = st.find(' > input.jstree-nativecheckbox.jstree-unchecked').length; 125 si = st.find(' > input.jstree-nativecheckbox.jstree-undetermined').length; 126 st = st.length; 127 128 if (sc + su + si < st) { return; } 129 130 if (su === st) { 131 c = obj.find(' > input.jstree-nativecheckbox'); 132 if (c.hasClass('jstree-unchecked')) { return; } 133 c.removeClass('jstree-checked jstree-undetermined').addClass('jstree-unchecked').prop('checked', false).prop('indeterminate', false); 134 continue; 135 } 136 if (sc === st) { 137 c = obj.find(' > input.jstree-nativecheckbox'); 138 if (c.hasClass('jstree-checked')) { return; } 139 c.removeClass('jstree-unchecked jstree-undetermined').addClass('jstree-checked').prop('checked', true).prop('indeterminate', false); 140 continue; 141 } 142 obj.parentsUntil(".jstree", "li").andSelf().find(' > input.jstree-nativecheckbox').removeClass('jstree-checked jstree-unchecked').addClass('jstree-undetermined').prop('checked', false).prop('indeterminate', true); 143 return; 144 } 145 }, 146 147 clean_node: function(obj) { 148 obj = this.__call_old(); 149 var t = this; 150 obj = obj.each(function() { 151 var o = $(this), 152 d = o.data("jstree"); 153 var li = o.is('li') ? o : o.closest('li'); 154 var id = "check_" + (li.attr('id') || Math.ceil(Math.random() * 10000)); 155 o.find(" > input.jstree-nativecheckbox").remove(); 156 var checked = (d && d.checkbox && d.checkbox.checked === true); 157 o.children("a").before("<input id='" + id + "' name='" + id + "' type='checkbox' class='jstree-nativecheckbox " + (checked ? "jstree-checked' checked='checked'" : "jstree-unchecked'") + " />"); 158 }); 159 t.checkbox_repair(obj); 160 return obj;
161 }, 162 get_state: function() { 163 var state = this.__call_old(); 164 state.checked = []; 165 this.get_container().find('.jstree-checked').closest('li').each(function() { if (this.id) { state.checked.push(this.id); } }); 166 return state; 167 }, 168 set_state: function(state, callback) { 169 if (this.__call_old()) { 170 if (state.checkbox) { 171 var _this = this; 172 this.uncheck_all(); 173 $.each(state.checkbox, function(i, v) { 174 _this.check_node(document.getElementById(v)); 175 }); 176 this.checkbox_repair(); 177 delete state.checkbox; 178 this.set_state(state, callback); 179 return false; 180 } 181 return true; 182 } 183 return false; 184 }, 185 get_json: function(obj, is_callback) { 186 var r = this.__call_old(), i; 187 if (is_callback) { 188 i = obj.find('> input.jstree-nativecheckbox'); 189 r.data.jstree.checkbox = {}; 190 r.data.jstree.checkbox.checked = i.parent().hasClass('jstree-checked'); 191 if (i.attr('name') != 'jstree[]') { r.data.checkbox.name = i.attr('name'); } 192 if (i.val() != obj.attr('id')) { r.data.checkbox.value = i.val(); } 193 } 194 return r; 195 } 196 } 197 }); 198 $(function() { 199 // add native checkbox specific CSS 200 var css_string = '' + 201 '.jstree li input.jstree-nativecheckbox { margin:0 2px 0 0; padding:0; border:0; display:inline; vertical-align:text-bottom; } ' + 202 '.jstree-rtl li input.jstree-nativecheckbox { margin:0 0 0 2px; padding:0; border:0; display:inline; vertical-align:text-bottom; } '; 203 $.vakata.css.add_sheet({ str: css_string, title: "jstree" }); 204 }); 205 206 // for now, don't include this plugin by default 207 // $.jstree.defaults.plugins.push("nativecheckbox"); 208})(jQuery); 209//*/
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.