diff --git a/package.json b/package.json
index 96281d5..57196b1 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "jquery-ui-multiselect-widget",
"description": "MultiSelect progessively enhances an ordinary multiple select control into elegant drop down list of checkboxes, stylable with ThemeRoller.",
- "version": "2.0.1",
+ "version": "3.0.0",
"license": "MIT or GPL-2.0",
"author": "Eric Hynds",
"contributors": [
@@ -10,6 +10,8 @@
}, {
"name": "AB Zainuddin",
"email": "burhan@codeyellow.nl"
+ }, {
+ "name": "Steve James",
}
],
"repository": {
@@ -17,6 +19,9 @@
"url": "https://github.com/ehynds/jquery-ui-multiselect-widget"
},
"main": "src/jquery.multiselect.js",
- "dependencies": {},
+ "dependencies": {
+ "jquery": "^1.8.0",
+ "jquery-ui": "^1.11.0"
+ },
"devDependencies": {}
}
diff --git a/src/jquery.multiselect.filter.js b/src/jquery.multiselect.filter.js
index a9bdaaf..6bd48ef 100644
--- a/src/jquery.multiselect.filter.js
+++ b/src/jquery.multiselect.filter.js
@@ -1,6 +1,6 @@
/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
/*
- * jQuery MultiSelect UI Widget Filtering Plugin 2.0.0
+ * jQuery MultiSelect UI Widget Filtering Plugin 3.0.0
* Copyright (c) 2012 Eric Hynds
*
* http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
@@ -71,11 +71,11 @@
else if(e.which === 27) {
$element.multiselect('close');
e.preventDefault();
- }
+ }
else if(e.which === 9 && e.shiftKey) {
$element.multiselect('close');
e.preventDefault();
- }
+ }
else if(e.altKey) {
switch(e.which) {
case 82:
@@ -100,7 +100,7 @@
// automatically reset the widget on close?
if (this.options.autoReset)
$element.on('multiselectclose', $.proxy(this._reset, this));
-
+
// rebuild cache when multiselect is updated
$element.on('multiselectrefresh', $.proxy(function() {
this.updateCache();
@@ -121,9 +121,9 @@
// rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
// only the currently filtered $elements are checked
this.instance._toggleChecked = function(flag, group) {
- var $inputs = (group && group.length) ? group : this.$labels.find('input');
var self = this;
var $element = this.element;
+ var $inputs = (group && group.length) ? group : this.$inputs;
// do not include hidden elems if the menu isn't open.
var selector = self._isOpen ? ':disabled, :hidden' : ':disabled';
@@ -137,9 +137,10 @@
// gather an array of the values that actually changed
var values = {};
- $inputs.each(function() {
- values[this.value] = true;
- });
+ var inputCount = $inputs.length;
+ for (var x = 0; x < inputCount; x++) {
+ values[ $inputs.get(x).value ] = true;
+ }
// select option tags
$element.find('option').filter(function() {
@@ -149,9 +150,9 @@
});
// trigger the change event on the select
- if($inputs.length)
+ if(inputCount)
$element.trigger('change');
-
+
};
},
@@ -163,11 +164,8 @@
$rows = this.$rows, $inputs = this.$inputs, $cache = this.$cache;
var $groups = this.instance.$menu.find(".ui-multiselect-optgroup");
$groups.show();
- if(!term) {
- $rows.show();
- } else {
- $rows.hide();
-
+ $rows.toggle(!term);
+ if(term) {
var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');
this._trigger("filter", e, $.map($cache, function(v, i) {
@@ -183,7 +181,7 @@
// show/hide optgroups
$groups.each(function() {
var $this = $(this);
- if (!$this.children("li:visible").length)
+ if (!$this.children('li').filter(':visible').length)
$this.hide();
});
this.instance._setMenuHeight();
diff --git a/src/jquery.multiselect.js b/src/jquery.multiselect.js
index df04314..ca006d4 100644
--- a/src/jquery.multiselect.js
+++ b/src/jquery.multiselect.js
@@ -4,7 +4,7 @@
* Copyright (c) 2012 Eric Hynds
*
* Depends:
- * - jQuery 1.7+ (http://api.jquery.com/)
+ * - jQuery 1.8+ (http://api.jquery.com/)
* - jQuery UI 1.11 widget factory (http://api.jqueryui.com/jQuery.widget/)
*
* Optional:
@@ -26,7 +26,8 @@
* - https://howchoo.com/g/mmu0nguznjg/learn-the-slow-and-fast-way-to-append-elements-to-the-dom
* - https://stackoverflow.com/questions/1357118/event-preventdefault-vs-return-false
* - https://blog.kevin-brown.com/select2/2014/12/15/jquery-js-performance.html
- * - http://www.jedi.be/blog/2008/10/10/is-your-jquery-or-javascript-getting-slow-or-bad-performance/
+ * - https://jsperf.com/append-array-of-jquery-elements
+ * - https://gist.github.com/adrienne/5341713
*
*/
(function($, undefined) {
@@ -34,73 +35,74 @@
var multiselectID = 0;
var $doc = $(document);
+ var defaultIcons = {
+ 'open': '',
+ 'checkAll': '',
+ 'uncheckAll': '',
+ 'flipAll': ''
+ };
+
$.widget("ech.multiselect", {
// default options
options: {
- header: true, // (true | false) If true, the header is shown.
- height: 175, // (int) Sets the height of the menu.
- minWidth: 225, // (int) Sets the minimum width of the menu.
- classes: '', // Classes that you can provide to be applied to the elements making up the widget.
- openIcon: '', // Scaleable HTML Entities or Font-Awesome icons can be specified here instead of the default jQuery UI icons.
- closeIcon: '', // Scaleable HTML Entities or Font-Awesome icons can be specified here instead of the default jQuery UI icons.
- checkAllIcon: '', // Scaleable HTML Entities or Font-Awesome icons can be specified here instead of the default jQuery UI icons.
- uncheckAllIcon: '', // Scaleable HTML Entities or Font-Awesome icons can be specified here instead of the default jQuery UI icons.
- flipAllIcon: '', // Scaleable HTML Entities or Font-Awesome icons can be specified here instead of the default jQuery UI icons.
- checkAllText: 'Check all', // (str | blank | null) If blank or null, link not shown.
- uncheckAllText: 'Uncheck all', // (str | blank | null) If blank or null, link not shown.
- flipAllText: 'Flip all', // (str | blank | null) If blank or null, link not shown.
- showCheckAll: true, // (true | false) Show or hide the Check All link without blanking the text.
- showUncheckAll: true, // (true | false) Show or hide the Uncheck All link without blanking the text.
- showFlipAll: false, // (true | false) Show or hide the Flip All link without blanking the text.
- 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.
- position: {}, // (object) A jQuery UI position object that constrains how the pop-up menu is positioned.
- appendTo: null, // (jQuery | DOM element | selector str) If provided, this specifies what element to append the widget to in the DOM.
- menuWidth:null, // (int | null) If a number is provided, sets the menu width.
- selectedListSeparator: ', ', // (str) This allows customization of the list separator. Use ', ' to make the button grow vertically showing 1 selection per line.
- htmlButtonText: false, // (true | false) If true, then the text used for the button's label is treated as html rather than plain text.
- htmlOptionText: false, // (true | false) If true, then the text for option label is treated as html rather than plain text.
- disableInputsOnToggle: true, // (true | false)
- groupColumns: false // (true | false)
+ header: true, // (true | false) If true, the header is shown.
+ height: 175, // (int) Sets the height of the menu.
+ minWidth: 225, // (int) Sets the minimum width of the menu.
+ classes: '', // Classes that you can provide to be applied to the elements making up the widget.
+ iconSet: null, // (plain object | null) Supply an object of icons to use alternative icon sets, or null for default set. Reference defaultIcons above for object structure.
+ checkAllText: 'Check all', // (str | blank | null) If blank, only icon shown. If null, no icon, text or link is shown.
+ uncheckAllText: 'Uncheck all', // (str | blank | null) If blank, only icon shown. If null, no icon, text or link is shown.
+ flipAllText: null, //'Flip all', // (str | blank | null) If blank, only icon shown. If null, no icon, text or link is shown.
+ 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.
+ position: {}, // (object) A jQuery UI position object that constrains how the pop-up menu is positioned.
+ appendTo: null, // (jQuery | DOM element | selector str) If provided, this specifies what element to append the widget to in the DOM.
+ menuWidth:null, // (int | null) If a number is provided, sets the menu width.
+ selectedListSeparator: ', ', // (str) This allows customization of the list separator. Use ', ' to make the button grow vertically showing 1 selection per line.
+ htmlButtonText: false, // (true | false) If true, then the text used for the button's label is treated as html rather than plain text.
+ htmlOptionText: false, // (true | false) If true, then the text for option label is treated as html rather than plain text.
+ disableInputsOnToggle: true, // (true | false)
+ groupColumns: false // (true | false)
},
// This method determines which element to append the menu to
// Uses the element provided in the options first, then looks for ui-front / dialog
// Otherwise appends to the body
_getAppendEl: function() {
- var elem = this.options.appendTo; // jQuery object, DOM element, OR selector str.
+ var elem = this.options.appendTo; // jQuery object, DOM element, OR selector str.
if(elem) {
- elem = elem.jquery || elem.nodeType ? $(elem) : this.document.find(elem).eq(0); // Note that the find handles the selector case.
+ elem = elem.jquery || elem.nodeType ? $(elem) : this.document.find(elem).eq(0); // Note that the find handles the selector case.
}
if(!elem || !elem[0]) {
- elem = this.element.closest(".ui-front, dialog"); // element is a jQuery object per http://api.jqueryui.com/jQuery.widget/
+ elem = this.element.closest(".ui-front, dialog"); // element is a jQuery object per http://api.jqueryui.com/jQuery.widget/
}
if(!elem.length) {
- elem = this.document[0].body; // Position at end of body.
+ elem = this.document[0].body; // Position at end of body.
}
return elem;
},
// Performs the initial creation of the widget
_create: function() {
- var $element = this.element.hide(); // element property is a jQuery object per http://api.jqueryui.com/jQuery.widget/
- var elSelect = $element.get(0); // This would be expected to be the underlying native select element.
+ var $element = this.element.hide(); // element property is a jQuery object
+ var elSelect = $element.get(0); // This would be expected to be the underlying native select element.
var options = this.options;
var classes = options.classes;
var headerOn = options.header;
+ var iconSet = $.extend({}, defaultIcons, options.iconSet || {}); // Do an extend here to handle icons missing from options.iconSet
var checkAllText = options.checkAllText;
var uncheckAllText = options.uncheckAllText;
var flipAllText = options.flipAllText;
- this.speed = $.fx.speeds._default; // default speed for effects
+ this.speed = $.fx.speeds._default; // default speed for effects
this._isOpen = false; // assume no
- this.inputIdCounter = 0;
// create a unique namespace for events that the widget
// factory cannot unbind automatically. Use eventNamespace if on
@@ -109,47 +111,53 @@
// bump unique ID after assigning it to the widget instance
this.multiselectID = multiselectID++;
- // The button that opens the widget menu. Note that this inserted later below.
+ // The button that opens the widget menu. Note that this is inserted later below.
var $button = (this.$button = $( document.createElement('button') ) )
- .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all' + (!!classes ? ' ' + classes : ''))
- .attr({ 'type': 'button', 'title': elSelect.title, 'tabIndex': elSelect.tabIndex, 'id': !!elSelect.id ? elSelect.id + '_ms' : null })
+ .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all' + (classes ? ' ' + classes : ''))
+ .attr({
+ 'type': 'button',
+ 'title': elSelect.title,
+ 'tabIndex': elSelect.tabIndex,
+ 'id': elSelect.id ? elSelect.id + '_ms' : null
+ })
.prop('aria-haspopup', true)
- .html('' + options.openIcon + ''); // Necessary to simplify dynamically changing the open icon.
+ .html('' + iconSet.open + ''); // Necessary to simplify dynamically changing the open icon.
- this.$buttonlabel = $( document.createElement('span'))
+ this.$buttonlabel = $( document.createElement('span') )
.html(options.noneSelectedText)
.appendTo( $button );
- // This is the menu that will hold all the options. If this is a single select widget, add the appropriate class. Note that this inserted below.
- var $menu = (this.$menu = $( document.createElement('div') ) )
- .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all ' + (!!elSelect.multiple ? '' : 'ui-multiselect-single ') + classes);
-
- // Menu header to hold controls for the menu
- var $header = (this.$header = $( document.createElement('div') ) )
- .addClass('ui-multiselect-header ui-widget-header ui-corner-all ui-helper-clearfix')
- .appendTo( $menu );
-
// Header controls, will contain the check all/uncheck all buttons
// Depending on how the options are set, this may be empty or simply plain text
- var headerCtlsHTML = ( headerOn === true
- ? (options.showCheckAll && checkAllText ? '