|
47 | 47 | appendTo: null,
|
48 | 48 | menuWidth:null,
|
49 | 49 | selectedListSeparator: ', ',
|
50 |
| - disableInputsOnToggle: true |
| 50 | + disableInputsOnToggle: true, |
| 51 | + groupColumns: false |
51 | 52 | },
|
52 | 53 |
|
53 | 54 | _getAppendEl: function() {
|
|
70 | 71 |
|
71 | 72 | this.speed = $.fx.speeds._default; // default speed for effects
|
72 | 73 | this._isOpen = false; // assume no
|
| 74 | + this.inputIdCounter = 0; |
73 | 75 |
|
74 | 76 | // create a unique namespace for events that the widget
|
75 | 77 | // factory cannot unbind automatically. Use eventNamespace if on
|
|
154 | 156 | }
|
155 | 157 | },
|
156 | 158 |
|
| 159 | + _makeOption: function(option) { |
| 160 | + var title = option.title ? option.title : null; |
| 161 | + var value = option.value; |
| 162 | + var id = this.element.attr('id') || multiselectID; // unique ID for the label & option tags |
| 163 | + var inputID = 'ui-multiselect-' + multiselectID + '-' + (option.id || id + '-option-' + this.inputIdCounter++); |
| 164 | + var isDisabled = option.disabled; |
| 165 | + var isSelected = option.selected; |
| 166 | + var labelClasses = [ 'ui-corner-all' ]; |
| 167 | + var liClasses = []; |
| 168 | + var o = this.options; |
| 169 | + |
| 170 | + if(isDisabled) { |
| 171 | + liClasses.push('ui-multiselect-disabled'); |
| 172 | + labelClasses.push('ui-state-disabled'); |
| 173 | + } |
| 174 | + if(option.className) { |
| 175 | + liClasses.push(option.className); |
| 176 | + } |
| 177 | + if(isSelected && !o.multiple) { |
| 178 | + labelClasses.push('ui-state-active'); |
| 179 | + } |
| 180 | + |
| 181 | + var $item = $("<li/>").addClass(liClasses.join(' ')); |
| 182 | + var $label = $("<label/>").attr({ |
| 183 | + "for": inputID, |
| 184 | + "title": title |
| 185 | + }).addClass(labelClasses.join(' ')).appendTo($item); |
| 186 | + var $input = $("<input/>").attr({ |
| 187 | + "name": "multiselect_" + id, |
| 188 | + "type": o.multiple ? "checkbox" : "radio", |
| 189 | + "value": value, |
| 190 | + "title": title, |
| 191 | + "id": inputID, |
| 192 | + "checked": isSelected ? "checked" : null, |
| 193 | + "aria-selected": isSelected ? "true" : null, |
| 194 | + "disabled": isDisabled ? "disabled" : null, |
| 195 | + "aria-disabled": isDisabled ? "true" : null |
| 196 | + }).data($(option).data()).appendTo($label); |
| 197 | + |
| 198 | + $("<span/>").text($(option).text()).appendTo($label); |
| 199 | + |
| 200 | + return $item; |
| 201 | + }, |
| 202 | + |
| 203 | + _buildOptionList: function(element, $appendTo) { |
| 204 | + var self = this; |
| 205 | + element.children().each(function() { |
| 206 | + var $this = $(this); |
| 207 | + if(this.tagName === 'OPTGROUP') { |
| 208 | + var $optionGroup = $("<ul/>").addClass('ui-multiselect-optgroup ' + this.className).appendTo($appendTo); |
| 209 | + if(self.options.groupColumns) { |
| 210 | + $optionGroup.addClass("ui-multiselect-columns"); |
| 211 | + } |
| 212 | + $("<a/>").text(this.getAttribute('label')).appendTo($optionGroup); |
| 213 | + self._buildOptionList($this, $optionGroup); |
| 214 | + } else { |
| 215 | + var $listItem = self._makeOption(this).appendTo($appendTo); |
| 216 | + } |
| 217 | + }); |
| 218 | + |
| 219 | + }, |
| 220 | + |
157 | 221 | refresh: function(init) {
|
158 |
| - var inputIdCounter = 0; |
| 222 | + var self = this; |
159 | 223 | var el = this.element;
|
160 | 224 | var o = this.options;
|
161 | 225 | var menu = this.menu;
|
162 | 226 | var checkboxContainer = this.checkboxContainer;
|
163 | 227 | var html = "";
|
164 | 228 | var $dropdown = $("<ul/>").addClass('ui-multiselect-checkboxes ui-helper-reset');
|
165 |
| - var id = el.attr('id') || multiselectID++; // unique ID for the label & option tags |
166 |
| - |
167 |
| - function makeItem(option, isInOptionGroup) { |
168 |
| - var title = option.title ? option.title : null; |
169 |
| - var value = option.value; |
170 |
| - var inputID = 'ui-multiselect-' + multiselectID + '-' + (option.id || id + '-option-' + inputIdCounter++); |
171 |
| - var isDisabled = option.disabled; |
172 |
| - var isSelected = option.selected; |
173 |
| - var labelClasses = [ 'ui-corner-all' ]; |
174 |
| - var liClasses = []; |
175 |
| - |
176 |
| - if(isDisabled) { |
177 |
| - liClasses.push('ui-multiselect-disabled'); |
178 |
| - labelClasses.push('ui-state-disabled'); |
179 |
| - } |
180 |
| - if(option.className) { |
181 |
| - liClasses.push(option.className); |
182 |
| - } |
183 |
| - if(isSelected && !o.multiple) { |
184 |
| - labelClasses.push('ui-state-active'); |
185 |
| - } |
186 |
| - if(isInOptionGroup) { |
187 |
| - liClasses.push('ui-multiselect-optgrp-child'); |
188 |
| - } |
| 229 | + this.inputIdCounter = 0; |
189 | 230 |
|
190 |
| - var $item = $("<li/>").addClass(liClasses.join(' ')); |
191 |
| - var $label = $("<label/>").attr({ |
192 |
| - "for": inputID, |
193 |
| - "title": title |
194 |
| - }).addClass(labelClasses.join(' ')).appendTo($item); |
195 |
| - var $input = $("<input/>").attr({ |
196 |
| - "name": "multiselect_" + id, |
197 |
| - "type": o.multiple ? "checkbox" : "radio", |
198 |
| - "value": value, |
199 |
| - "title": title, |
200 |
| - "id": inputID, |
201 |
| - "checked": isSelected ? "checked" : null, |
202 |
| - "aria-selected": isSelected ? "true" : null, |
203 |
| - "disabled": isDisabled ? "disabled" : null, |
204 |
| - "aria-disabled": isDisabled ? "true" : null |
205 |
| - }).data($(option).data()).appendTo($label); |
206 |
| - |
207 |
| - $("<span/>").text($(option).text()).appendTo($label); |
208 |
| - |
209 |
| - return $item; |
210 |
| - }//makeItem |
211 | 231 |
|
212 | 232 | // update header link container visibility if needed
|
213 | 233 | if (this.options.header) {
|
|
218 | 238 | }
|
219 | 239 | }
|
220 | 240 |
|
221 |
| - //Turn all the options and optiongroups into list items |
222 |
| - el.children().each(function(i) { |
223 |
| - var $this = $(this); |
224 |
| - |
225 |
| - if(this.tagName === 'OPTGROUP') { |
226 |
| - var $groupLabel = $("<li/>").addClass('ui-multiselect-optgroup-label ' + this.className).appendTo($dropdown); |
227 |
| - var $link = $("<a/>").attr("href", "#").text(this.getAttribute('label')).appendTo($groupLabel); |
228 |
| - |
229 |
| - $this.children().each(function() { |
230 |
| - var $listItem = makeItem(this, true).appendTo($dropdown); |
231 |
| - }); |
232 |
| - } else { |
233 |
| - var $listItem = makeItem(this).appendTo($dropdown); |
234 |
| - } |
235 |
| - |
236 |
| - }); |
| 241 | + this._buildOptionList(el, $dropdown); |
237 | 242 |
|
238 | 243 | this.menu.find(".ui-multiselect-checkboxes").remove();
|
239 | 244 | this.menu.append($dropdown);
|
|
335 | 340 | _bindMenuEvents: function() {
|
336 | 341 | var self = this;
|
337 | 342 | // optgroup label toggle support
|
338 |
| - this.menu.delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function(e) { |
| 343 | + this.menu.delegate('.ui-multiselect-optgroup a', 'click.multiselect', function(e) { |
339 | 344 | e.preventDefault();
|
340 | 345 |
|
341 | 346 | var $this = $(this);
|
342 |
| - var $inputs = $this.parent().nextUntil(':not(.ui-multiselect-optgrp-child)').find('input:visible:not(:disabled)'); |
| 347 | + var $inputs = $this.parent().find('input:visible:not(:disabled)'); |
343 | 348 | var nodes = $inputs.get();
|
344 |
| - var label = $this.parent().text(); |
| 349 | + var label = $this.text(); |
345 | 350 |
|
346 | 351 | // trigger event and bail if the return is false
|
347 | 352 | if(self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false) {
|
|
556 | 561 | _setMenuHeight: function() {
|
557 | 562 | var headerHeight = this.menu.children(".ui-multiselect-header:visible").outerHeight(true);
|
558 | 563 | var ulHeight = 0;
|
559 |
| - this.menu.find(".ui-multiselect-checkboxes li").each(function(idx, li) { |
| 564 | + this.menu.find(".ui-multiselect-checkboxes li, .ui-multiselect-checkboxes a").each(function(idx, li) { |
560 | 565 | ulHeight += $(li).outerHeight(true);
|
561 | 566 | });
|
562 | 567 | if(ulHeight > this.options.height) {
|
|
581 | 586 | var moveToLast = which === 38 || which === 37;
|
582 | 587 |
|
583 | 588 | // select the first li that isn't an optgroup label / disabled
|
584 |
| - var $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label):visible').first(); |
| 589 | + var $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup):visible').first(); |
| 590 | + // we might have to jump to the next/previous option group |
| 591 | + if(!$next.length) { |
| 592 | + $next = $start.parents(".ui-multiselect-optgroup")[moveToLast ? "prev" : "next" ](); |
| 593 | + } |
585 | 594 |
|
586 | 595 | // if at the first/last element
|
587 | 596 | if(!$next.length) {
|
|
594 | 603 | $container.scrollTop(moveToLast ? $container.height() : 0);
|
595 | 604 |
|
596 | 605 | } else {
|
597 |
| - $next.find('label:visible').trigger('mouseover'); |
| 606 | + $next.find('label:visible')[ moveToLast ? "last" : "first" ]().trigger('mouseover'); |
598 | 607 | }
|
599 | 608 | },
|
600 | 609 |
|
|
701 | 710 | return;
|
702 | 711 | }
|
703 | 712 |
|
704 |
| - var $container = menu.find('ul').last(); |
| 713 | + var $container = menu.find('.ui-multiselect-checkboxes'); |
705 | 714 | var effect = o.show;
|
706 | 715 |
|
707 | 716 | // figure out opening effects/speeds
|
|
717 | 726 | }
|
718 | 727 |
|
719 | 728 | // set the scroll of the checkbox container
|
720 |
| - $container.scrollTop(0).height(o.height); |
| 729 | + $container.scrollTop(0); |
721 | 730 |
|
722 | 731 | // show the menu, maybe with a speed/effect combo
|
723 | 732 | $.fn.show.apply(menu, args);
|
|
824 | 833 | return this.button;
|
825 | 834 | },
|
826 | 835 |
|
| 836 | + getMenu: function() { |
| 837 | + return this.menu; |
| 838 | + }, |
| 839 | + |
| 840 | + getLabels: function() { |
| 841 | + return this.labels; |
| 842 | + }, |
| 843 | + |
| 844 | + addOption: function(attributes, text, groupLabel) { |
| 845 | + var $option = $("<option/>").attr(attributes).text(text); |
| 846 | + var optionNode = $option.get(0); |
| 847 | + if(groupLabel) { |
| 848 | + this.element.children("OPTGROUP").filter(function() { |
| 849 | + return $(this).prop("label") === groupLabel; |
| 850 | + }).append($option); |
| 851 | + this.menu.find(".ui-multiselect-optgroup").filter(function() { |
| 852 | + return $(this).find("a").text() === groupLabel; |
| 853 | + }).append(this._makeOption(optionNode)); |
| 854 | + } else { |
| 855 | + this.element.append($option); |
| 856 | + this.menu.find(".ui-multiselect-checkboxes").append(this._makeOption(optionNode)); |
| 857 | + } |
| 858 | + //update cached elements |
| 859 | + this.labels = this.menu.find('label'); |
| 860 | + this.inputs = this.labels.children('input'); |
| 861 | + }, |
| 862 | + |
| 863 | + removeOption: function(value) { |
| 864 | + if(!value) { |
| 865 | + return; |
| 866 | + } |
| 867 | + this.element.find("option[value=" + value + "]").remove(); |
| 868 | + this.labels.find("input[value=" + value + "]").parents("li").remove(); |
| 869 | + |
| 870 | + //update cached elements |
| 871 | + this.labels = this.menu.find('label'); |
| 872 | + this.inputs = this.labels.children('input'); |
| 873 | + }, |
| 874 | + |
827 | 875 | position: function() {
|
828 | 876 | var pos = {
|
829 | 877 | my: "top",
|
|
0 commit comments