-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathjquery.multiselect.filter.js
172 lines (138 loc) · 5.26 KB
/
jquery.multiselect.filter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* 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 1.5pre
* Copyright (c) 2012 Eric Hynds
*
* http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
*
* Depends:
* - jQuery UI MultiSelect widget
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function ($) {
var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g;
$.widget('ech.multiselectfilter', {
options: {
label: 'Filter:',
width: null, /* override default width set in css file (px). null will inherit */
placeholder: 'Enter keywords',
autoReset: false
},
_create: function () {
var opts = this.options;
// get the multiselect instance
var instance = (this.instance = $(this.element).data('multiselect'));
// store header; add filter class so the close/check all/uncheck all links can be positioned correctly
var header = (this.header = instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter'));
// wrapper elem
var wrapper = (this.wrapper = $('<div class="ui-multiselect-filter">' + (opts.label.length ? opts.label : '') + '<input placeholder="' + opts.placeholder + '" type="search"' + (/\d/.test(opts.width) ? 'style="width:' + opts.width + 'px"' : '') + ' /></div>').prependTo(this.header));
// reference to the actual inputs
this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');
// build the input box
this.input = wrapper.find('input').bind({
keydown: function (e) {
// prevent the enter key from submitting the form / closing the widget
if (e.which === 13) {
e.preventDefault();
}
},
keyup: $.proxy(this._handler, this),
click: $.proxy(this._handler, this)
});
// cache input values for searching
this.updateCache();
// rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
// only the currently filtered elements are checked
instance._toggleChecked = function (flag, group) {
var $inputs = (group && group.length) ? group : this.labels.find('input');
// do not include hidden elems if the menu isn't open.
var selector = instance._isOpen ? ':disabled, :hidden' : ':disabled';
$inputs = $inputs
.not(selector)
.each(this._toggleState('checked', flag));
// update text
this.update();
// gather an array of the values that actually changed
var values = $inputs.map(function () {
return this.value;
}).get();
// select option tags
this.element.find('option').filter(function () {
if (!this.disabled && $.inArray(this.value, values) > -1) {
_self._toggleState('selected', flag).call(this);
}
});
// trigger the change event on the select
if ($inputs.length) {
this.element.trigger('change');
}
};
// rebuild cache when multiselect is updated
var doc = $(document).bind('multiselectrefresh', $.proxy(function () {
this.updateCache();
this._handler();
}, this));
// automatically reset the widget on close?
if (this.options.autoReset) {
doc.bind('multiselectclose', $.proxy(this._reset, this));
}
},
// thx for the logic here ben alman
_handler: function (e) {
var term = $.trim(this.input[0].value.toLowerCase()),
// speed up lookups
rows = this.rows, inputs = this.inputs, cache = this.cache;
if (!term) {
rows.show();
} else {
rows.hide();
var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');
this._trigger("filter", e, $.map(cache, function (v, i) {
if (v.search(regex) !== -1) {
rows.eq(i).show();
return inputs.get(i);
}
return null;
}));
}
// show/hide optgroups
this.instance.menu.find(".ui-multiselect-optgroup-label").each(function () {
var $this = $(this);
var isVisible = $this.nextUntil('.ui-multiselect-optgroup-label').filter(function () {
return $.css(this, "display") !== 'none';
}).length;
$this[isVisible ? 'show' : 'hide']();
});
},
_reset: function () {
this.input.val('').trigger('keyup');
},
updateCache: function () {
// each list item
this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");
// cache
this.cache = this.element.children().map(function () {
var elem = $(this);
// account for optgroups
if (this.tagName.toLowerCase() === "optgroup") {
elem = elem.children();
}
return elem.map(function () {
return this.innerHTML.toLowerCase();
}).get();
}).get();
},
widget: function () {
return this.wrapper;
},
destroy: function () {
$.Widget.prototype.destroy.call(this);
this.input.val('').trigger("keyup");
this.wrapper.remove();
}
});
})(jQuery);