diff --git a/src/jquery.multiselect.js b/src/jquery.multiselect.js index f0ba55f..7dba363 100644 --- a/src/jquery.multiselect.js +++ b/src/jquery.multiselect.js @@ -43,6 +43,7 @@ noneSelectedText: 'Select options', // (str) The text to show in the button where nothing is selected. selectedText: '# of # selected', // (str) A "template" that indicates how to show the count of selections in the button. The "#'s" are replaced by the selection count & option count. selectedList: 0, // (int) The actual list selections will be shown in the button when the count of selections is <= than this number. + selectedMax: null, // (int | function) If selected count > selectedMax or if function returns 1, then message is displayed, and new selection is undone. show: null, // (array) An array containing menu opening effects. hide: null, // (array) An array containing menu closing effects. autoOpen: false, // (true | false) If true, then the menu will be opening immediately after initialization. @@ -453,13 +454,32 @@ var checked = this.checked; var $tags = self.element.find('option'); // "element" is a jQuery object representing the underlying select var isMultiple = !!self.element[0].multiple; - + var inputCount = self.$inputs.length; + var numChecked = self.$inputs.filter(":checked").length; + var selectedMax = self.options.selectedMax; + // bail if this input is disabled or the event is cancelled if(this.disabled || self._trigger('click', e, { value: val, text: optionText, checked: checked }) === false) { e.preventDefault(); return; } + if ( selectedMax && checked && ( $.isFunction(selectedMax) ? !!selectedMax.call(this, self.$inputs) : numChecked > selectedMax ) ) { + var o = self.options; + var saveText = o.selectedText; + + // The following warning is shown in the button and then cleared after a second. + o.selectedText = "
LIMIT OF " + (numChecked - 1) + " REACHED!
"; + self.update(); + setTimeout( function() { + o.selectedText = saveText; + self.update(); + }, 1000 ); + + e.preventDefault(); // Kill the event. + return false; + } + // make sure the input has focus. otherwise, the esc key // won't close the menu after clicking an item. $this.focus(); @@ -993,6 +1013,7 @@ break; case 'selectedText': case 'selectedList': + case 'selectedMax': case 'noneSelectedText': this.options[key] = value; // these all needs to update immediately for the update() call this.update(); diff --git a/tests/unit/options.js b/tests/unit/options.js index 5ca530a..9097f37 100644 --- a/tests/unit/options.js +++ b/tests/unit/options.js @@ -78,14 +78,33 @@ selectedList: 2 }); - el.multiselect("checkAll"); - equals( button().text(), '3 of 3 selected', 'after checkAll with a limited selectedList value, button value displays number of checked'); - el.multiselect("destroy").remove(); - }); - - function asyncSelectedList( useTrigger, message ){ - expect(1); - stop(); + el.multiselect("checkAll"); + equals( button().text(), '3 of 3 selected', 'after checkAll with a limited selectedList value, button value displays number of checked'); + el.multiselect("destroy").remove(); + }); + + test("selectedMax", function(){ + expect(1); + + var html = ''; + + el = $(html).appendTo("body").multiselect({ + selectedMax: 2 + }); + + checkboxes = el.multiselect("widget").find(":checkbox"); + checkboxes.eq(0).trigger('click'); + checkboxes.eq(1).trigger('click'); + checkboxes.eq(2).trigger('click'); + + equals( menu().find("input").filter(":checked").length, 2 , 'after clicking each checkbox, count of checked restored to selectedMax of 2'); + el.multiselect("destroy").remove(); + + }); + + function asyncSelectedList( useTrigger, message ){ + expect(1); + stop(); var html = '', checkboxes;