PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | js/bootstrap-multiselect.js +3 -1974 6.5.2 → trunk View file →
@@ -1,9 +1,9 @@
1 1 /**
2 2 * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/)
3 3 *
4 4 * Apache License, Version 2.0:
5 - * Copyright (c) 2012 - 2021 David Stutz
5 + * Copyright (c) 2012 - 2022 David Stutz
6 6 *
7 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8 8 * use this file except in compliance with the License. You may obtain a
9 9 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -14,9 +14,9 @@
14 14 * License for the specific language governing permissions and limitations
15 15 * under the License.
16 16 *
17 17 * BSD 3-Clause License:
18 - * Copyright (c) 2012 - 2021 David Stutz
18 + * Copyright (c) 2012 - 2022 David Stutz
19 19 * All rights reserved.
20 20 *
21 21 * Redistribution and use in source and binary forms, with or without
22 22 * modification, are permitted provided that the following conditions are met:
@@ -40,1976 +40,5 @@
40 40 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
41 41 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42 42 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 43 */
44 - (function (root, factory) {
45 - // check to see if 'knockout' AMD module is specified if using requirejs
46 - if (typeof define === 'function' && define.amd &&
47 - typeof require === 'function' && typeof require.specified === 'function' && require.specified('knockout')) {
48 -
49 - // AMD. Register as an anonymous module.
50 - define(['jquery', 'knockout'], factory);
51 - } else {
52 - // Browser globals
53 - factory(root.jQuery, root.ko);
54 - }
55 -})(this, function ($, ko) {
56 - "use strict";// jshint ;_;
57 -
58 - if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
59 - ko.bindingHandlers.multiselect = {
60 - after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],
61 -
62 - init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
63 - var $element = $(element);
64 - var config = ko.toJS(valueAccessor());
65 -
66 - $element.multiselect(config);
67 -
68 - if (allBindings.has('options')) {
69 - var options = allBindings.get('options');
70 - if (ko.isObservable(options)) {
71 - ko.computed({
72 - read: function () {
73 - options();
74 - setTimeout(function () {
75 - var ms = $element.data('multiselect');
76 - if (ms)
77 - ms.updateOriginalOptions();//Not sure how beneficial this is.
78 - $element.multiselect('rebuild');
79 - }, 1);
80 - },
81 - disposeWhenNodeIsRemoved: element
82 - });
83 - }
84 - }
85 -
86 - //value and selectedOptions are two-way, so these will be triggered even by our own actions.
87 - //It needs some way to tell if they are triggered because of us or because of outside change.
88 - //It doesn't loop but it's a waste of processing.
89 - if (allBindings.has('value')) {
90 - var value = allBindings.get('value');
91 - if (ko.isObservable(value)) {
92 - ko.computed({
93 - read: function () {
94 - value();
95 - setTimeout(function () {
96 - $element.multiselect('refresh');
97 - }, 1);
98 - },
99 - disposeWhenNodeIsRemoved: element
100 - }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
101 - }
102 - }
103 -
104 - //Switched from arrayChange subscription to general subscription using 'refresh'.
105 - //Not sure performance is any better using 'select' and 'deselect'.
106 - if (allBindings.has('selectedOptions')) {
107 - var selectedOptions = allBindings.get('selectedOptions');
108 - if (ko.isObservable(selectedOptions)) {
109 - ko.computed({
110 - read: function () {
111 - selectedOptions();
112 - setTimeout(function () {
113 - $element.multiselect('refresh');
114 - }, 1);
115 - },
116 - disposeWhenNodeIsRemoved: element
117 - }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
118 - }
119 - }
120 -
121 - var setEnabled = function (enable) {
122 - setTimeout(function () {
123 - if (enable)
124 - $element.multiselect('enable');
125 - else
126 - $element.multiselect('disable');
127 - });
128 - };
129 -
130 - if (allBindings.has('enable')) {
131 - var enable = allBindings.get('enable');
132 - if (ko.isObservable(enable)) {
133 - ko.computed({
134 - read: function () {
135 - setEnabled(enable());
136 - },
137 - disposeWhenNodeIsRemoved: element
138 - }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
139 - } else {
140 - setEnabled(enable);
141 - }
142 - }
143 -
144 - if (allBindings.has('disable')) {
145 - var disable = allBindings.get('disable');
146 - if (ko.isObservable(disable)) {
147 - ko.computed({
148 - read: function () {
149 - setEnabled(!disable());
150 - },
151 - disposeWhenNodeIsRemoved: element
152 - }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
153 - } else {
154 - setEnabled(!disable);
155 - }
156 - }
157 -
158 - ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
159 - $element.multiselect('destroy');
160 - });
161 - },
162 -
163 - update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
164 - var $element = $(element);
165 - var config = ko.toJS(valueAccessor());
166 -
167 - $element.multiselect('setOptions', config);
168 - $element.multiselect('rebuild');
169 - }
170 - };
171 - }
172 -
173 - function forEach(array, callback) {
174 - for (var index = 0; index < array.length; ++index) {
175 - callback(array[index], index);
176 - }
177 - }
178 -
179 - /**
180 - * Constructor to create a new multiselect using the given select.
181 - *
182 - * @param {jQuery} select
183 - * @param {Object} options
184 - * @returns {Multiselect}
185 - */
186 - function Multiselect(select, options) {
187 -
188 - this.$select = $(select);
189 - this.options = this.mergeOptions($.extend({}, options, this.$select.data()));
190 -
191 - // Placeholder via data attributes
192 - if (this.$select.attr("data-placeholder")) {
193 - this.options.nonSelectedText = this.$select.data("placeholder");
194 - }
195 -
196 - // Initialization.
197 - // We have to clone to create a new reference.
198 - this.originalOptions = this.$select.clone()[0].options;
199 - this.query = '';
200 - this.searchTimeout = null;
201 - this.lastToggledInput = null;
202 -
203 - this.options.multiple = this.$select.attr('multiple') === "multiple";
204 - this.options.onChange = $.proxy(this.options.onChange, this);
205 - this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);
206 - this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);
207 - this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
208 - this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
209 - this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
210 - this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
211 - this.options.onInitialized = $.proxy(this.options.onInitialized, this);
212 - this.options.onFiltering = $.proxy(this.options.onFiltering, this);
213 -
214 - // Build select all if enabled.
215 - this.buildContainer();
216 - this.buildButton();
217 - this.buildDropdown();
218 - this.buildReset();
219 - this.buildSelectAll();
220 - this.buildDropdownOptions();
221 - this.buildFilter();
222 - this.buildButtons();
223 -
224 - this.updateButtonText();
225 - this.updateSelectAll(true);
226 -
227 - if (this.options.enableClickableOptGroups && this.options.multiple) {
228 - this.updateOptGroups();
229 - }
230 -
231 - this.options.wasDisabled = this.$select.prop('disabled');
232 - if (this.options.disableIfEmpty && $('option', this.$select).length <= 0 && !this.options.wasDisabled) {
233 - this.disable(true);
234 - }
235 -
236 - this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container);
237 - this.$select.prop('tabindex', '-1');
238 -
239 - if (this.options.widthSynchronizationMode !== 'never') {
240 - this.synchronizeButtonAndPopupWidth();
241 - }
242 -
243 - this.options.onInitialized(this.$select, this.$container);
244 - }
245 -
246 - Multiselect.prototype = {
247 -
248 - defaults: {
249 - /**
250 - * Default text function will either print 'None selected' in case no
251 - * option is selected or a list of the selected options up to a length
252 - * of 3 selected options.
253 - *
254 - * @param {jQuery} options
255 - * @param {jQuery} select
256 - * @returns {String}
257 - */
258 - buttonText: function (selectedOptions, select) {
259 - if (this.disabledText.length > 0 && select.prop('disabled')) {
260 - return this.disabledText;
261 - }
262 - else if (selectedOptions.length === 0) {
263 - return this.nonSelectedText;
264 - }
265 - else if (this.allSelectedText
266 - && selectedOptions.length === $('option', $(select)).length
267 - && $('option', $(select)).length !== 1
268 - && this.multiple) {
269 -
270 - if (this.selectAllNumber) {
271 - return this.allSelectedText + ' (' + selectedOptions.length + ')';
272 - }
273 - else {
274 - return this.allSelectedText;
275 - }
276 - }
277 - else if (this.numberDisplayed != 0 && selectedOptions.length > this.numberDisplayed) {
278 - return selectedOptions.length + ' ' + this.nSelectedText;
279 - }
280 - else {
281 - var selected = '';
282 - var delimiter = this.delimiterText;
283 -
284 - selectedOptions.each(function () {
285 - var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
286 - selected += label + delimiter;
287 - });
288 -
289 - return selected.substr(0, selected.length - this.delimiterText.length);
290 - }
291 - },
292 - /**
293 - * Updates the title of the button similar to the buttonText function.
294 - *
295 - * @param {jQuery} options
296 - * @param {jQuery} select
297 - * @returns {@exp;selected@call;substr}
298 - */
299 - buttonTitle: function (options, select) {
300 - if (options.length === 0) {
301 - return this.nonSelectedText;
302 - }
303 - else {
304 - var selected = '';
305 - var delimiter = this.delimiterText;
306 -
307 - options.each(function () {
308 - var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
309 - selected += label + delimiter;
310 - });
311 - return selected.substr(0, selected.length - this.delimiterText.length);
312 - }
313 - },
314 - checkboxName: function (option) {
315 - return false; // no checkbox name
316 - },
317 - /**
318 - * Create a label.
319 - *
320 - * @param {jQuery} element
321 - * @returns {String}
322 - */
323 - optionLabel: function (element) {
324 - return $(element).attr('label') || $(element).text();
325 - },
326 - /**
327 - * Create a class.
328 - *
329 - * @param {jQuery} element
330 - * @returns {String}
331 - */
332 - optionClass: function (element) {
333 - return $(element).attr('class') || '';
334 - },
335 - /**
336 - * Triggered on change of the multiselect.
337 - *
338 - * Not triggered when selecting/deselecting options manually.
339 - *
340 - * @param {jQuery} option
341 - * @param {Boolean} checked
342 - */
343 - onChange: function (option, checked) {
344 -
345 - },
346 - /**
347 - * Triggered when the dropdown is shown.
348 - *
349 - * @param {jQuery} event
350 - */
351 - onDropdownShow: function (event) {
352 -
353 - },
354 - /**
355 - * Triggered when the dropdown is hidden.
356 - *
357 - * @param {jQuery} event
358 - */
359 - onDropdownHide: function (event) {
360 -
361 - },
362 - /**
363 - * Triggered after the dropdown is shown.
364 - *
365 - * @param {jQuery} event
366 - */
367 - onDropdownShown: function (event) {
368 -
369 - },
370 - /**
371 - * Triggered after the dropdown is hidden.
372 - *
373 - * @param {jQuery} event
374 - */
375 - onDropdownHidden: function (event) {
376 -
377 - },
378 - /**
379 - * Triggered on select all.
380 - */
381 - onSelectAll: function () {
382 -
383 - },
384 - /**
385 - * Triggered on deselect all.
386 - */
387 - onDeselectAll: function () {
388 -
389 - },
390 - /**
391 - * Triggered after initializing.
392 - *
393 - * @param {jQuery} $select
394 - * @param {jQuery} $container
395 - */
396 - onInitialized: function ($select, $container) {
397 -
398 - },
399 - /**
400 - * Triggered on filtering.
401 - *
402 - * @param {jQuery} $filter
403 - */
404 - onFiltering: function ($filter) {
405 -
406 - },
407 - enableHTML: false,
408 - buttonClass: 'custom-select',
409 - inheritClass: false,
410 - buttonWidth: 'auto',
411 - buttonContainer: '<div class="btn-group" />',
412 - dropRight: false,
413 - dropUp: false,
414 - selectedClass: 'active',
415 - // Maximum height of the dropdown menu.
416 - // If maximum height is exceeded a scrollbar will be displayed.
417 - maxHeight: false,
418 - includeSelectAllOption: false,
419 - includeSelectAllIfMoreThan: 0,
420 - selectAllText: ' Select all',
421 - selectAllValue: 'multiselect-all',
422 - selectAllName: false,
423 - selectAllNumber: true,
424 - selectAllJustVisible: true,
425 - enableFiltering: false,
426 - enableCaseInsensitiveFiltering: false,
427 - enableFullValueFiltering: false,
428 - enableClickableOptGroups: false,
429 - enableCollapsibleOptGroups: false,
430 - collapseOptGroupsByDefault: false,
431 - filterPlaceholder: 'Search',
432 - // possible options: 'text', 'value', 'both'
433 - filterBehavior: 'text',
434 - includeFilterClearBtn: true,
435 - preventInputChangeEvent: false,
436 - nonSelectedText: 'None selected',
437 - nSelectedText: 'selected',
438 - allSelectedText: 'All selected',
439 - resetButtonText: 'Reset',
440 - numberDisplayed: 3,
441 - disableIfEmpty: false,
442 - disabledText: '',
443 - delimiterText: ', ',
444 - includeResetOption: false,
445 - includeResetDivider: false,
446 - resetText: 'Reset',
447 - indentGroupOptions: true,
448 - // possible options: 'never', 'always', 'ifPopupIsSmaller', 'ifPopupIsWider'
449 - widthSynchronizationMode: 'never',
450 - buttonTextAlignment: 'center',
451 - enableResetButton: false,
452 - templates: {
453 - button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span></button>',
454 - popupContainer: '<div class="multiselect-container dropdown-menu"></div>',
455 - filter: '<div class="multiselect-filter d-flex align-items-center"><i class="fas fa-sm fa-search text-muted"></i><input type="search" class="multiselect-search form-control" /></div>',
456 - buttonGroup: '<div class="multiselect-buttons btn-group" style="display:flex;"></div>',
457 - buttonGroupReset: '<button type="button" class="multiselect-reset btn btn-secondary btn-block"></button>',
458 - option: '<button type="button" class="multiselect-option dropdown-item"></button>',
459 - divider: '<div class="dropdown-divider"></div>',
460 - optionGroup: '<button type="button" class="multiselect-group dropdown-item"></button>',
461 - resetButton: '<div class="multiselect-reset text-center p-2"><button type="button" class="btn btn-sm btn-block btn-outline-secondary"></button></div>'
462 - }
463 - },
464 -
465 - constructor: Multiselect,
466 -
467 - /**
468 - * Builds the container of the multiselect.
469 - */
470 - buildContainer: function () {
471 - this.$container = $(this.options.buttonContainer);
472 - if (this.options.widthSynchronizationMode !== 'never') {
473 - this.$container.on('show.bs.dropdown', $.proxy(function () {
474 - // the width needs to be synchronized again in case the width of the button changed in between
475 - this.synchronizeButtonAndPopupWidth();
476 - this.options.onDropdownShow();
477 - }, this));
478 - }
479 - else {
480 - this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
481 - }
482 - this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
483 - this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
484 - this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
485 - },
486 -
487 - /**
488 - * Builds the button of the multiselect.
489 - */
490 - buildButton: function () {
491 - this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
492 - if (this.$select.attr('class') && this.options.inheritClass) {
493 - this.$button.addClass(this.$select.attr('class'));
494 - }
495 - // Adopt active state.
496 - if (this.$select.prop('disabled')) {
497 - this.disable();
498 - }
499 - else {
500 - this.enable();
501 - }
502 -
503 - // Manually add button width if set.
504 - if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
505 - this.$button.css({
506 - 'width': '100%' //this.options.buttonWidth,
507 - });
508 - this.$container.css({
509 - 'width': this.options.buttonWidth
510 - });
511 - }
512 -
513 - if (this.options.buttonTextAlignment) {
514 - switch (this.options.buttonTextAlignment) {
515 - case 'left':
516 - this.$button.addClass('text-left');
517 - break;
518 - case 'center':
519 - this.$button.addClass('text-center');
520 - break;
521 - case 'right':
522 - this.$button.addClass('text-right');
523 - break;
524 - }
525 - }
526 -
527 - // Keep the tab index from the select.
528 - var tabindex = this.$select.attr('tabindex');
529 - if (tabindex) {
530 - this.$button.attr('tabindex', tabindex);
531 - }
532 -
533 - this.$container.prepend(this.$button);
534 - },
535 -
536 - /**
537 - * Builds the popup container representing the dropdown menu.
538 - */
539 - buildDropdown: function () {
540 -
541 - // Build popup container.
542 - this.$popupContainer = $(this.options.templates.popupContainer);
543 -
544 - if (this.options.dropRight) {
545 - this.$container.addClass('dropright');
546 - }
547 - else if (this.options.dropUp) {
548 - this.$container.addClass("dropup");
549 - }
550 -
551 - // Set max height of dropdown menu to activate auto scrollbar.
552 - if (this.options.maxHeight) {
553 - // TODO: Add a class for this option to move the css declarations.
554 - this.$popupContainer.css({
555 - 'max-height': this.options.maxHeight + 'px',
556 - 'overflow-y': 'auto',
557 - 'overflow-x': 'hidden'
558 - });
559 - }
560 -
561 - if (this.options.widthSynchronizationMode !== 'never') {
562 - this.$popupContainer.css('overflow-x', 'hidden');
563 - }
564 -
565 - this.$popupContainer.on("touchstart click", function (e) {
566 - e.stopPropagation();
567 - });
568 -
569 - this.$container.append(this.$popupContainer);
570 - },
571 -
572 - synchronizeButtonAndPopupWidth: function () {
573 - if (!this.$popupContainer || this.options.widthSynchronizationMode === 'never') {
574 - return;
575 - }
576 -
577 - var buttonWidth = this.$button.outerWidth();
578 - switch (this.options.widthSynchronizationMode) {
579 - case 'always':
580 - this.$popupContainer.css('min-width', buttonWidth);
581 - this.$popupContainer.css('max-width', buttonWidth);
582 - break;
583 - case 'ifPopupIsSmaller':
584 - this.$popupContainer.css('min-width', buttonWidth);
585 - break;
586 - case 'ifPopupIsWider':
587 - this.$popupContainer.css('max-width', buttonWidth);
588 - break;
589 - }
590 - },
591 -
592 - /**
593 - * Build the dropdown options and binds all necessary events.
594 - *
595 - * Uses createDivider and createOptionValue to create the necessary options.
596 - */
597 - buildDropdownOptions: function () {
598 -
599 - this.$select.children().each($.proxy(function (index, element) {
600 -
601 - var $element = $(element);
602 - // Support optgroups and options without a group simultaneously.
603 - var tag = $element.prop('tagName')
604 - .toLowerCase();
605 -
606 - if ($element.prop('value') === this.options.selectAllValue) {
607 - return;
608 - }
609 -
610 - if (tag === 'optgroup') {
611 - this.createOptgroup(element);
612 - }
613 - else if (tag === 'option') {
614 -
615 - if ($element.data('role') === 'divider') {
616 - this.createDivider();
617 - }
618 - else {
619 - this.createOptionValue(element, false);
620 - }
621 -
622 - }
623 -
624 - // Other illegal tags will be ignored.
625 - }, this));
626 -
627 - // Bind the change event on the dropdown elements.
628 - $(this.$popupContainer).off('change', '> *:not(.multiselect-group) input[type="checkbox"], > *:not(.multiselect-group) input[type="radio"]');
629 - $(this.$popupContainer).on('change', '> *:not(.multiselect-group) input[type="checkbox"], > *:not(.multiselect-group) input[type="radio"]', $.proxy(function (event) {
630 - var $target = $(event.target);
631 -
632 - var checked = $target.prop('checked') || false;
633 - var isSelectAllOption = $target.val() === this.options.selectAllValue;
634 -
635 - // Apply or unapply the configured selected class.
636 - if (this.options.selectedClass) {
637 - if (checked) {
638 - $target.closest('.multiselect-option')
639 - .addClass(this.options.selectedClass);
640 - }
641 - else {
642 - $target.closest('.multiselect-option')
643 - .removeClass(this.options.selectedClass);
644 - }
645 - }
646 -
647 - // Get the corresponding option.
648 - var value = $target.val();
649 - var $option = this.getOptionByValue(value);
650 -
651 - var $optionsNotThis = $('option', this.$select).not($option);
652 - var $checkboxesNotThis = $('input', this.$container).not($target);
653 -
654 - if (isSelectAllOption) {
655 -
656 - if (checked) {
657 - this.selectAll(this.options.selectAllJustVisible, true);
658 - }
659 - else {
660 - this.deselectAll(this.options.selectAllJustVisible, true);
661 - }
662 - }
663 - else {
664 - if (checked) {
665 - $option.prop('selected', true);
666 -
667 - if (this.options.multiple) {
668 - // Simply select additional option.
669 - $option.prop('selected', true);
670 - }
671 - else {
672 - // Unselect all other options and corresponding checkboxes.
673 - if (this.options.selectedClass) {
674 - $($checkboxesNotThis).closest('.dropdown-item').removeClass(this.options.selectedClass);
675 - }
676 -
677 - $($checkboxesNotThis).prop('checked', false);
678 - $optionsNotThis.prop('selected', false);
679 -
680 - // It's a single selection, so close.
681 - this.$button.click();
682 - }
683 -
684 - if (this.options.selectedClass === "active") {
685 - $optionsNotThis.closest(".dropdown-item").css("outline", "");
686 - }
687 - }
688 - else {
689 - // Unselect option.
690 - $option.prop('selected', false);
691 - }
692 -
693 - // To prevent select all from firing onChange: #575
694 - this.options.onChange($option, checked);
695 -
696 - // Do not update select all or optgroups on select all change!
697 - this.updateSelectAll();
698 -
699 - if (this.options.enableClickableOptGroups && this.options.multiple) {
700 - this.updateOptGroups();
701 - }
702 - }
703 -
704 - this.$select.change();
705 - this.updateButtonText();
706 -
707 - if (this.options.preventInputChangeEvent) {
708 - return false;
709 - }
710 - }, this));
711 -
712 - $('.multiselect-option', this.$popupContainer).off('mousedown');
713 - $('.multiselect-option', this.$popupContainer).on('mousedown', function (e) {
714 - if (e.shiftKey) {
715 - // Prevent selecting text by Shift+click
716 - return false;
717 - }
718 - });
719 -
720 - $(this.$popupContainer).off('touchstart click', '.multiselect-option, .multiselect-all, .multiselect-group');
721 - $(this.$popupContainer).on('touchstart click', '.multiselect-option, .multiselect-all, .multiselect-group', $.proxy(function (event) {
722 - event.stopPropagation();
723 -
724 - var $target = $(event.target);
725 -
726 - if (event.shiftKey && this.options.multiple) {
727 - if (!$target.is("input")) { // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
728 - event.preventDefault();
729 - $target = $target.closest(".multiselect-option").find("input");
730 - $target.prop("checked", !$target.prop("checked"));
731 - }
732 - var checked = $target.prop('checked') || false;
733 -
734 - if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
735 - var from = this.$popupContainer.find(".multiselect-option:visible").index($target.closest(".multiselect-option"));
736 - var to = this.$popupContainer.find(".multiselect-option:visible").index(this.lastToggledInput.closest(".multiselect-option"));
737 -
738 - if (from > to) { // Swap the indices
739 - var tmp = to;
740 - to = from;
741 - from = tmp;
742 - }
743 -
744 - // Make sure we grab all elements since slice excludes the last index
745 - ++to;
746 -
747 - // Change the checkboxes and underlying options
748 - var range = this.$popupContainer.find(".multiselect-option:not(.multiselect-filter-hidden)").slice(from, to).find("input");
749 -
750 - range.prop('checked', checked);
751 -
752 - if (this.options.selectedClass) {
753 - range.closest('.multiselect-option')
754 - .toggleClass(this.options.selectedClass, checked);
755 - }
756 -
757 - for (var i = 0, j = range.length; i < j; i++) {
758 - var $checkbox = $(range[i]);
759 -
760 - var $option = this.getOptionByValue($checkbox.val());
761 -
762 - $option.prop('selected', checked);
763 - }
764 - }
765 -
766 - // Trigger the select "change" event
767 - $target.trigger("change");
768 - }
769 - else if (!$target.is('input')) {
770 - var $checkbox = $target.closest('.multiselect-option, .multiselect-all').find('.form-check-input');
771 - if ($checkbox.length > 0) {
772 - if (this.options.multiple || !$checkbox.prop('checked')) {
773 - $checkbox.prop('checked', !$checkbox.prop('checked'));
774 - $checkbox.change();
775 - }
776 - }
777 - else if (this.options.enableClickableOptGroups && this.options.multiple && !$target.hasClass("caret-container")) {
778 - var groupItem = $target;
779 - if (!groupItem.hasClass("multiselect-group")) {
780 - groupItem = $target.closest('.multiselect-group');
781 - }
782 - $checkbox = groupItem.find(".form-check-input");
783 - if ($checkbox.length > 0) {
784 - $checkbox.prop('checked', !$checkbox.prop('checked'));
785 - $checkbox.change();
786 - }
787 - }
788 -
789 - event.preventDefault();
790 - }
791 -
792 - // Remembers last clicked option
793 - var $input = $target.closest(".multiselect-option").find("input[type='checkbox'], input[type='radio']");
794 - if ($input.length > 0) {
795 - this.lastToggledInput = $target;
796 - }
797 - else {
798 - this.lastToggledInput = null;
799 - }
800 -
801 - $target.blur();
802 - }, this));
803 -
804 - //Keyboard support.
805 - this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function (event) {
806 - var $items = $(this.$container).find(".multiselect-option:not(.disabled), .multiselect-group:not(.disabled), .multiselect-all").filter(":visible");
807 - var index = $items.index($items.filter(':focus'));
808 - var $search = $('.multiselect-search', this.$container);
809 -
810 - // keyCode 9 == Tab
811 - if (event.keyCode === 9 && this.$container.hasClass('show')) {
812 - this.$button.click();
813 - }
814 - // keyCode 13 = Enter
815 - else if (event.keyCode == 13) {
816 - var $current = $items.eq(index);
817 - setTimeout(function () {
818 - $current.focus();
819 - }, 1);
820 - }
821 - // keyCode 38 = Arrow Up
822 - else if (event.keyCode == 38) {
823 - if (index == 0 && !$search.is(':focus')) {
824 - setTimeout(function () {
825 - $search.focus();
826 - }, 1);
827 - }
828 - }
829 - // keyCode 40 = Arrow Down
830 - else if (event.keyCode == 40) {
831 - if ($search.is(':focus')) {
832 - var $first = $items.eq(0);
833 - setTimeout(function () {
834 - $search.blur();
835 - $first.focus();
836 - }, 1);
837 - }
838 - else if (index == -1) {
839 - setTimeout(function () {
840 - $search.focus();
841 - }, 1);
842 - }
843 - }
844 - }, this));
845 -
846 - if (this.options.enableClickableOptGroups && this.options.multiple) {
847 - $(".multiselect-group input", this.$popupContainer).off("change");
848 - $(".multiselect-group input", this.$popupContainer).on("change", $.proxy(function (event) {
849 - event.stopPropagation();
850 -
851 - var $target = $(event.target);
852 - var checked = $target.prop('checked') || false;
853 -
854 - var $item = $(event.target).closest('.dropdown-item');
855 - var $group = $item.nextUntil(".multiselect-group")
856 - .not('.multiselect-filter-hidden')
857 - .not('.disabled');
858 -
859 - var $inputs = $group.find("input");
860 -
861 - var $options = [];
862 -
863 - if (this.options.selectedClass) {
864 - if (checked) {
865 - $item.addClass(this.options.selectedClass);
866 - }
867 - else {
868 - $item.removeClass(this.options.selectedClass);
869 - }
870 - }
871 -
872 - $.each($inputs, $.proxy(function (index, input) {
873 - var $input = $(input);
874 - var value = $input.val();
875 - var $option = this.getOptionByValue(value);
876 -
877 - if (checked) {
878 - $input.prop('checked', true);
879 - $input.closest('.dropdown-item')
880 - .addClass(this.options.selectedClass);
881 -
882 - $option.prop('selected', true);
883 - }
884 - else {
885 - $input.prop('checked', false);
886 - $input.closest('.dropdown-item')
887 - .removeClass(this.options.selectedClass);
888 -
889 - $option.prop('selected', false);
890 - }
891 -
892 - $options.push(this.getOptionByValue(value));
893 - }, this))
894 -
895 - // Cannot use select or deselect here because it would call updateOptGroups again.
896 -
897 - this.options.onChange($options, checked);
898 -
899 - this.$select.change();
900 - this.updateButtonText();
901 - this.updateSelectAll();
902 - }, this));
903 - }
904 -
905 - if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
906 - $(".multiselect-group .caret-container", this.$popupContainer).off("click");
907 - $(".multiselect-group .caret-container", this.$popupContainer).on("click", $.proxy(function (event) {
908 - var $group = $(event.target).closest('.multiselect-group');
909 - var $inputs = $group.nextUntil(".multiselect-group")
910 - .not('.multiselect-filter-hidden');
911 -
912 - var visible = true;
913 - $inputs.each(function () {
914 - visible = visible && !$(this).hasClass('multiselect-collapsible-hidden');
915 - });
916 -
917 - if (visible) {
918 - $inputs.hide()
919 - .addClass('multiselect-collapsible-hidden');
920 - }
921 - else {
922 - $inputs.show()
923 - .removeClass('multiselect-collapsible-hidden');
924 - }
925 - }, this));
926 - }
927 - },
928 -
929 - /**
930 - * Create a checkbox container with input and label based on given values
931 - * @param {JQuery} $item
932 - * @param {String} label
933 - * @param {String} name
934 - * @param {String} value
935 - * @param {String} inputType
936 - * @returns {JQuery}
937 - */
938 - createCheckbox: function ($item, labelContent, name, value, title, inputType) {
939 - var $wrapper = $('<span />');
940 - $wrapper.addClass("form-check");
941 -
942 - if (this.options.enableHTML && $(labelContent).length > 0) {
943 - var $checkboxLabel = $('<label class="form-check-label" />');
944 - $checkboxLabel.html(labelContent);
945 - $wrapper.append($checkboxLabel);
946 - }
947 - else {
948 - var $checkboxLabel = $('<label class="form-check-label" />');
949 - $checkboxLabel.text(labelContent);
950 - $wrapper.append($checkboxLabel);
951 - }
952 -
953 - var $checkbox = $('<input class="form-check-input"/>').attr('type', inputType);
954 - $checkbox.val(value);
955 - $wrapper.prepend($checkbox);
956 -
957 - if (name) {
958 - $checkbox.attr('name', name);
959 - }
960 -
961 - $item.prepend($wrapper);
962 - $item.attr("title", title || labelContent);
963 -
964 - return $checkbox;
965 - },
966 -
967 - /**
968 - * Create an option using the given select option.
969 - *
970 - * @param {jQuery} element
971 - */
972 - createOptionValue: function (element, isGroupOption) {
973 - var $element = $(element);
974 - if ($element.is(':selected')) {
975 - $element.prop('selected', true);
976 - }
977 -
978 - // Support the label attribute on options.
979 - var label = this.options.optionLabel(element);
980 - var classes = this.options.optionClass(element);
981 - var value = $element.val();
982 - var inputType = this.options.multiple ? "checkbox" : "radio";
983 - var title = $element.attr('title');
984 -
985 - var $option = $(this.options.templates.option);
986 - $option.addClass(classes);
987 -
988 - if (isGroupOption && this.options.indentGroupOptions) {
989 - $option.addClass("multiselect-group-option-indented")
990 - }
991 -
992 - // Hide all children items when collapseOptGroupsByDefault is true
993 - if (this.options.collapseOptGroupsByDefault && $(element).parent().prop("tagName").toLowerCase() === "optgroup") {
994 - $option.addClass("multiselect-collapsible-hidden");
995 - $option.hide();
996 - }
997 -
998 - var name = this.options.checkboxName($element);
999 - var $checkbox = this.createCheckbox($option, label, name, value, title, inputType);
1000 -
1001 - var selected = $element.prop('selected') || false;
1002 -
1003 - if (value === this.options.selectAllValue) {
1004 - $option.addClass("multiselect-all");
1005 - $option.removeClass("multiselect-option");
1006 - $checkbox.parent().parent()
1007 - .addClass('multiselect-all');
1008 - }
1009 -
1010 - this.$popupContainer.append($option);
1011 -
1012 - if ($element.is(':disabled')) {
1013 - $checkbox.attr('disabled', 'disabled')
1014 - .prop('disabled', true)
1015 - .closest('.dropdown-item')
1016 - .addClass('disabled');
1017 - }
1018 -
1019 - $checkbox.prop('checked', selected);
1020 -
1021 - if (selected && this.options.selectedClass) {
1022 - $checkbox.closest('.dropdown-item')
1023 - .addClass(this.options.selectedClass);
1024 - }
1025 - },
1026 -
1027 - /**
1028 - * Creates a divider using the given select option.
1029 - *
1030 - * @param {jQuery} element
1031 - */
1032 - createDivider: function (element) {
1033 - var $divider = $(this.options.templates.divider);
1034 - this.$popupContainer.append($divider);
1035 - },
1036 -
1037 - /**
1038 - * Creates an optgroup.
1039 - *
1040 - * @param {jQuery} group
1041 - */
1042 - createOptgroup: function (group) {
1043 - var $group = $(group);
1044 - var label = $group.attr("label");
1045 - var value = $group.attr("value");
1046 - var title = $group.attr('title');
1047 -
1048 - var $groupOption = $("<span class='multiselect-group dropdown-item-text'></span>");
1049 -
1050 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1051 - $groupOption = $(this.options.templates.optionGroup);
1052 - var $checkbox = this.createCheckbox($groupOption, label, null, value, title, "checkbox");
1053 - }
1054 - else {
1055 - if (this.options.enableHTML) {
1056 - $groupOption.html(" " + label);
1057 - }
1058 - else {
1059 - $groupOption.text(" " + label);
1060 - }
1061 - }
1062 -
1063 - var classes = this.options.optionClass(group);
1064 - $groupOption.addClass(classes);
1065 -
1066 - if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
1067 - $groupOption.find('.form-check').addClass('d-inline-block');
1068 - $groupOption.append('<span class="caret-container dropdown-toggle pl-1"></span>');
1069 - }
1070 -
1071 - if ($group.is(':disabled')) {
1072 - $groupOption.addClass('disabled');
1073 - }
1074 -
1075 - this.$popupContainer.append($groupOption);
1076 -
1077 - $("option", group).each($.proxy(function ($, group) {
1078 - this.createOptionValue(group, true);
1079 - }, this));
1080 - },
1081 -
1082 - /**
1083 - * Build the reset.
1084 - *
1085 - */
1086 - buildReset: function () {
1087 - if (this.options.includeResetOption) {
1088 -
1089 - // Check whether to add a divider after the reset.
1090 - if (this.options.includeResetDivider) {
1091 - var divider = $(this.options.templates.divider);
1092 - divider.addClass("mt-0");
1093 - this.$popupContainer.prepend(divider);
1094 - }
1095 -
1096 - var $resetButton = $(this.options.templates.resetButton);
1097 -
1098 - if (this.options.enableHTML) {
1099 - $('button', $resetButton).html(this.options.resetText);
1100 - }
1101 - else {
1102 - $('button', $resetButton).text(this.options.resetText);
1103 - }
1104 -
1105 - $('button', $resetButton).click($.proxy(function () {
1106 - this.clearSelection();
1107 - }, this));
1108 -
1109 - this.$popupContainer.prepend($resetButton);
1110 - }
1111 - },
1112 -
1113 - /**
1114 - * Build the select all.
1115 - *
1116 - * Checks if a select all has already been created.
1117 - */
1118 - buildSelectAll: function () {
1119 - if (typeof this.options.selectAllValue === 'number') {
1120 - this.options.selectAllValue = this.options.selectAllValue.toString();
1121 - }
1122 -
1123 - var alreadyHasSelectAll = this.hasSelectAll();
1124 -
1125 - if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
1126 - && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {
1127 -
1128 - // Check whether to add a divider after the select all.
1129 - if (this.options.includeSelectAllDivider) {
1130 - this.$popupContainer.prepend($(this.options.templates.divider));
1131 - }
1132 -
1133 - var $option = $(this.options.templates.li || this.options.templates.option);
1134 - var $checkbox = this.createCheckbox($option, this.options.selectAllText, this.options.selectAllName, this.options.selectAllValue, this.options.selectAllText, "checkbox");
1135 -
1136 - $option.addClass("multiselect-all");
1137 - $option.removeClass("multiselect-option");
1138 - $option.find(".form-check-label").addClass("font-weight-bold");
1139 -
1140 - this.$popupContainer.prepend($option);
1141 -
1142 - $checkbox.prop('checked', false);
1143 - }
1144 - },
1145 -
1146 - /**
1147 - * Builds the filter.
1148 - */
1149 - buildFilter: function () {
1150 -
1151 - // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
1152 - if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
1153 - var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
1154 -
1155 - if (this.$select.find('option').length >= enableFilterLength) {
1156 -
1157 - this.$filter = $(this.options.templates.filter);
1158 - $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);
1159 -
1160 - // Handles optional filter clear button
1161 - if (!this.options.includeFilterClearBtn) {
1162 - this.$filter.find(".multiselect-search").attr("type", "text");
1163 -
1164 - // Remove clear button if the old design of the filter with input groups and separated clear button is used
1165 - this.$filter.find(".multiselect-clear-filter").remove();
1166 - }
1167 - else {
1168 - // Firefox does not support a clear button in search inputs right now therefore it must be added manually
1169 - if (this.isFirefox() && this.$filter.find(".multiselect-clear-filter").length === 0) {
1170 - this.$filter.append("<i class='fas fa-times text-muted multiselect-clear-filter multiselect-moz-clear-filter'></i>");
1171 - }
1172 -
1173 - this.$filter.find(".multiselect-clear-filter").on('click', $.proxy(function (event) {
1174 - clearTimeout(this.searchTimeout);
1175 -
1176 - this.query = '';
1177 - this.$filter.find('.multiselect-search').val('');
1178 - $('.dropdown-item', this.$popupContainer).show().removeClass('multiselect-filter-hidden');
1179 -
1180 - this.updateSelectAll();
1181 -
1182 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1183 - this.updateOptGroups();
1184 - }
1185 -
1186 - }, this));
1187 - }
1188 -
1189 - this.$popupContainer.prepend(this.$filter);
1190 -
1191 - this.$filter.val(this.query).on('click', function (event) {
1192 - event.stopPropagation();
1193 - }).on('input keydown', $.proxy(function (event) {
1194 - // Cancel enter key default behaviour
1195 - if (event.which === 13) {
1196 - event.preventDefault();
1197 - }
1198 -
1199 - if (this.isFirefox() && this.options.includeFilterClearBtn) {
1200 - if (event.target.value) {
1201 - this.$filter.find(".multiselect-moz-clear-filter").show();
1202 - }
1203 - else {
1204 - this.$filter.find(".multiselect-moz-clear-filter").hide();
1205 - }
1206 - }
1207 -
1208 - // This is useful to catch "keydown" events after the browser has updated the control.
1209 - clearTimeout(this.searchTimeout);
1210 -
1211 - this.searchTimeout = this.asyncFunction($.proxy(function () {
1212 -
1213 - if (this.query !== event.target.value) {
1214 - this.query = event.target.value;
1215 -
1216 - var currentGroup, currentGroupVisible;
1217 - $.each($('.multiselect-option, .multiselect-group', this.$popupContainer), $.proxy(function (index, element) {
1218 - var value = $('input', element).length > 0 ? $('input', element).val() : "";
1219 - var text = $('.form-check-label', element).text();
1220 -
1221 - var filterCandidate = '';
1222 - if ((this.options.filterBehavior === 'text')) {
1223 - filterCandidate = text;
1224 - }
1225 - else if ((this.options.filterBehavior === 'value')) {
1226 - filterCandidate = value;
1227 - }
1228 - else if (this.options.filterBehavior === 'both') {
1229 - filterCandidate = text + '\n' + value;
1230 - }
1231 -
1232 - if (value !== this.options.selectAllValue && text) {
1233 -
1234 - // By default lets assume that element is not
1235 - // interesting for this search.
1236 - var showElement = false;
1237 -
1238 - if (this.options.enableCaseInsensitiveFiltering) {
1239 - filterCandidate = filterCandidate.toLowerCase();
1240 - this.query = this.query.toLowerCase();
1241 - }
1242 -
1243 - if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') {
1244 - var valueToMatch = filterCandidate.trim().substring(0, this.query.length);
1245 - if (this.query.indexOf(valueToMatch) > -1) {
1246 - showElement = true;
1247 - }
1248 - }
1249 - else if (filterCandidate.indexOf(this.query) > -1) {
1250 - showElement = true;
1251 - }
1252 -
1253 - // Toggle current element (group or group item) according to showElement boolean.
1254 - if (!showElement) {
1255 - $(element).css('display', 'none');
1256 - $(element).addClass('multiselect-filter-hidden');
1257 - }
1258 - if (showElement) {
1259 - $(element).css('display', 'block');
1260 - $(element).removeClass('multiselect-filter-hidden');
1261 - }
1262 -
1263 - // Differentiate groups and group items.
1264 - if ($(element).hasClass('multiselect-group')) {
1265 - // Remember group status.
1266 - currentGroup = element;
1267 - currentGroupVisible = showElement;
1268 - }
1269 - else {
1270 - // Show group name when at least one of its items is visible.
1271 - if (showElement) {
1272 - $(currentGroup).show()
1273 - .removeClass('multiselect-filter-hidden');
1274 - }
1275 -
1276 - // Show all group items when group name satisfies filter.
1277 - if (!showElement && currentGroupVisible) {
1278 - $(element).show()
1279 - .removeClass('multiselect-filter-hidden');
1280 - }
1281 - }
1282 - }
1283 - }, this));
1284 - }
1285 -
1286 - this.updateSelectAll();
1287 -
1288 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1289 - this.updateOptGroups();
1290 - }
1291 -
1292 - this.updatePopupPosition();
1293 -
1294 - this.options.onFiltering(event.target);
1295 -
1296 - }, this), 300, this);
1297 - }, this));
1298 - }
1299 - }
1300 - },
1301 -
1302 - /**
1303 - * Builds the filter.
1304 - */
1305 - buildButtons: function () {
1306 - if (this.options.enableResetButton) {
1307 - var $buttonGroup = $(this.options.templates.buttonGroup);
1308 - this.$buttonGroupReset = $(this.options.templates.buttonGroupReset).text(this.options.resetButtonText);
1309 - $buttonGroup.append(this.$buttonGroupReset);
1310 - this.$popupContainer.prepend($buttonGroup);
1311 -
1312 - // We save all options that were previously selected.
1313 - this.defaultSelection = {};
1314 - $('option', this.$select).each($.proxy(function(index, element) {
1315 - var $option = $(element);
1316 - this.defaultSelection[$option.val()] = $option.prop('selected');
1317 - }, this));
1318 -
1319 - this.$buttonGroupReset.on('click', $.proxy(function(event) {
1320 - $('option', this.$select).each($.proxy(function(index, element) {
1321 - var $option = $(element);
1322 - $option.prop('selected', this.defaultSelection[$option.val()]);
1323 - }, this));
1324 - this.refresh();
1325 -
1326 - if (this.options.enableFiltering) {
1327 - this.$filter.trigger('keydown');
1328 - $('input', this.$filter).val('');
1329 - }
1330 - }, this));
1331 - }
1332 - },
1333 -
1334 - updatePopupPosition: function() {
1335 - // prevent gaps between popup and select when filter is used (#1199)
1336 - var transformMatrix = this.$popupContainer.css("transform");
1337 - var matrixType = transformMatrix.substring(0, transformMatrix.indexOf('('));
1338 - var values = transformMatrix.substring(transformMatrix.indexOf('(') + 1, transformMatrix.length - 1);
1339 - var valuesArray = values.split(',');
1340 -
1341 - var valueIndex = 5;
1342 - if(matrixType === "matrix3d") {
1343 - valueIndex = 13;
1344 - }
1345 -
1346 - var yTransformation = valuesArray[valueIndex];
1347 - // Need to check to avoid errors when testing and in some other situations.
1348 - yTransformation = typeof yTransformation === 'undefined' ? 0 : yTransformation.trim();
1349 - if (yTransformation < 0) {
1350 - yTransformation = this.$popupContainer.css("height").replace('px', '') * -1;
1351 - valuesArray[valueIndex] = yTransformation;
1352 - transformMatrix = matrixType + '(' + valuesArray.join(',') + ')';
1353 - this.$popupContainer.css("transform", transformMatrix);
1354 - }
1355 - },
1356 -
1357 - /**
1358 - * Unbinds the whole plugin.
1359 - */
1360 - destroy: function () {
1361 - this.$container.remove();
1362 - this.$select.unwrap();
1363 - this.$select.show();
1364 -
1365 - // reset original state
1366 - this.$select.prop('disabled', this.options.wasDisabled);
1367 -
1368 - this.$select.data('multiselect', null);
1369 - },
1370 -
1371 - /**
1372 - * Refreshs the multiselect based on the selected options of the select.
1373 - */
1374 - refresh: function () {
1375 - var inputs = {};
1376 - $('.multiselect-option input', this.$popupContainer).each(function () {
1377 - inputs[$(this).val()] = $(this);
1378 - });
1379 -
1380 - $('option', this.$select).each($.proxy(function (index, element) {
1381 - var $elem = $(element);
1382 - var $input = inputs[$(element).val()];
1383 -
1384 - if ($elem.is(':selected')) {
1385 - $input.prop('checked', true);
1386 -
1387 - if (this.options.selectedClass) {
1388 - $input.closest('.multiselect-option')
1389 - .addClass(this.options.selectedClass);
1390 - }
1391 - }
1392 - else {
1393 - $input.prop('checked', false);
1394 -
1395 - if (this.options.selectedClass) {
1396 - $input.closest('.multiselect-option')
1397 - .removeClass(this.options.selectedClass);
1398 - }
1399 - }
1400 -
1401 - if ($elem.is(":disabled")) {
1402 - $input.attr('disabled', 'disabled')
1403 - .prop('disabled', true)
1404 - .closest('.multiselect-option')
1405 - .addClass('disabled');
1406 - }
1407 - else {
1408 - $input.prop('disabled', false)
1409 - .closest('.multiselect-option')
1410 - .removeClass('disabled');
1411 - }
1412 - }, this));
1413 -
1414 - this.updateButtonText();
1415 - this.updateSelectAll();
1416 -
1417 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1418 - this.updateOptGroups();
1419 - }
1420 - },
1421 -
1422 - /**
1423 - * Select all options of the given values.
1424 - *
1425 - * If triggerOnChange is set to true, the on change event is triggered if
1426 - * and only if one value is passed.
1427 - *
1428 - * @param {Array} selectValues
1429 - * @param {Boolean} triggerOnChange
1430 - */
1431 - select: function (selectValues, triggerOnChange) {
1432 - if (!$.isArray(selectValues)) {
1433 - selectValues = [selectValues];
1434 - }
1435 -
1436 - for (var i = 0; i < selectValues.length; i++) {
1437 - var value = selectValues[i];
1438 -
1439 - if (value === null || value === undefined) {
1440 - continue;
1441 - }
1442 -
1443 - var $option = this.getOptionByValue(value);
1444 - var $checkbox = this.getInputByValue(value);
1445 -
1446 - if ($option === undefined || $checkbox === undefined) {
1447 - continue;
1448 - }
1449 -
1450 - if (this.options.selectedClass) {
1451 - $checkbox.closest('.dropdown-item')
1452 - .addClass(this.options.selectedClass);
1453 - }
1454 -
1455 - $checkbox.prop('checked', true);
1456 - $option.prop('selected', true);
1457 -
1458 - if (!this.options.multiple) {
1459 - var $checkboxesNotThis = $('input', this.$container).not($checkbox);
1460 - $($checkboxesNotThis).prop('checked', false);
1461 - $($checkboxesNotThis).closest('.multiselect-option').removeClass("active")
1462 -
1463 - var $optionsNotThis = $('option', this.$select).not($option);
1464 - $optionsNotThis.prop('selected', false);
1465 - }
1466 -
1467 - if (triggerOnChange) {
1468 - this.options.onChange($option, true);
1469 - }
1470 - }
1471 -
1472 - this.updateButtonText();
1473 - this.updateSelectAll();
1474 -
1475 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1476 - this.updateOptGroups();
1477 - }
1478 - },
1479 -
1480 - /**
1481 - * Clears all selected items.
1482 - */
1483 - clearSelection: function () {
1484 - this.deselectAll(false);
1485 - this.updateButtonText();
1486 - this.updateSelectAll();
1487 -
1488 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1489 - this.updateOptGroups();
1490 - }
1491 - },
1492 -
1493 - /**
1494 - * Deselects all options of the given values.
1495 - *
1496 - * If triggerOnChange is set to true, the on change event is triggered, if
1497 - * and only if one value is passed.
1498 - *
1499 - * @param {Array} deselectValues
1500 - * @param {Boolean} triggerOnChange
1501 - */
1502 - deselect: function (deselectValues, triggerOnChange) {
1503 - if (!this.options.multiple) {
1504 - // In single selection mode at least on option needs to be selected
1505 - return;
1506 - }
1507 -
1508 - if (!$.isArray(deselectValues)) {
1509 - deselectValues = [deselectValues];
1510 - }
1511 -
1512 - for (var i = 0; i < deselectValues.length; i++) {
1513 - var value = deselectValues[i];
1514 -
1515 - if (value === null || value === undefined) {
1516 - continue;
1517 - }
1518 -
1519 - var $option = this.getOptionByValue(value);
1520 - var $checkbox = this.getInputByValue(value);
1521 -
1522 - if ($option === undefined || $checkbox === undefined) {
1523 - continue;
1524 - }
1525 -
1526 - if (this.options.selectedClass) {
1527 - $checkbox.closest('.dropdown-item')
1528 - .removeClass(this.options.selectedClass);
1529 - }
1530 -
1531 - $checkbox.prop('checked', false);
1532 - $option.prop('selected', false);
1533 -
1534 - if (triggerOnChange) {
1535 - this.options.onChange($option, false);
1536 - }
1537 - }
1538 -
1539 - this.updateButtonText();
1540 - this.updateSelectAll();
1541 -
1542 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1543 - this.updateOptGroups();
1544 - }
1545 - },
1546 -
1547 - /**
1548 - * Selects all enabled & visible options.
1549 - *
1550 - * If justVisible is true or not specified, only visible options are selected.
1551 - *
1552 - * @param {Boolean} justVisible
1553 - * @param {Boolean} triggerOnSelectAll
1554 - */
1555 - selectAll: function (justVisible, triggerOnSelectAll) {
1556 - if (!this.options.multiple) {
1557 - // In single selection mode only one option can be selected at a time
1558 - return;
1559 - }
1560 -
1561 - // Record all changes, i.e., options selected that were not selected before.
1562 - var selected = [];
1563 - var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
1564 -
1565 - if (justVisible) {
1566 - var visibleOptions = $(".multiselect-option:not(.disabled):not(.multiselect-filter-hidden)", this.$popupContainer);
1567 - $('input:enabled', visibleOptions).prop('checked', true);
1568 - visibleOptions.addClass(this.options.selectedClass);
1569 -
1570 - $('input:enabled', visibleOptions).each($.proxy(function (index, element) {
1571 - var value = $(element).val();
1572 - var option = this.getOptionByValue(value);
1573 - if (!$(option).prop('selected')) {
1574 - selected.push(option);
1575 - }
1576 - $(option).prop('selected', true);
1577 - }, this));
1578 - }
1579 - else {
1580 - var allOptions = $(".multiselect-option:not(.disabled)", this.$popupContainer);
1581 - $('input:enabled', allOptions).prop('checked', true);
1582 - allOptions.addClass(this.options.selectedClass);
1583 -
1584 - $('input:enabled', allOptions).each($.proxy(function (index, element) {
1585 - var value = $(element).val();
1586 - var option = this.getOptionByValue(value);
1587 - if (!$(option).prop('selected')) {
1588 - selected.push(option);
1589 - }
1590 - $(option).prop('selected', true);
1591 - }, this));
1592 - }
1593 -
1594 - $('.multiselect-option input[value="' + this.options.selectAllValue + '"]', this.$popupContainer).prop('checked', true);
1595 -
1596 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1597 - this.updateOptGroups();
1598 - }
1599 -
1600 - this.updateButtonText();
1601 - this.updateSelectAll();
1602 -
1603 - if (triggerOnSelectAll) {
1604 - this.options.onSelectAll(selected);
1605 - }
1606 - },
1607 -
1608 - /**
1609 - * Deselects all options.
1610 - *
1611 - * If justVisible is true or not specified, only visible options are deselected.
1612 - *
1613 - * @param {Boolean} justVisible
1614 - */
1615 - deselectAll: function (justVisible, triggerOnDeselectAll) {
1616 - if (!this.options.multiple) {
1617 - // In single selection mode at least on option needs to be selected
1618 - return;
1619 - }
1620 -
1621 - // Record changes, i.e., those options that are deselected but were not deselected before.
1622 - var deselected = [];
1623 - var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
1624 -
1625 - if (justVisible) {
1626 - var visibleOptions = $(".multiselect-option:not(.disabled):not(.multiselect-filter-hidden)", this.$popupContainer);
1627 - $('input[type="checkbox"]:enabled', visibleOptions).prop('checked', false);
1628 - visibleOptions.removeClass(this.options.selectedClass);
1629 -
1630 - $('input[type="checkbox"]:enabled', visibleOptions).each($.proxy(function (index, element) {
1631 - var value = $(element).val();
1632 - var option = this.getOptionByValue(value);
1633 - if ($(option).prop('selected')) {
1634 - deselected.push(option);
1635 - }
1636 - $(option).prop('selected', false);
1637 - }, this));
1638 - }
1639 - else {
1640 - var allOptions = $(".multiselect-option:not(.disabled):not(.multiselect-group)", this.$popupContainer);
1641 - $('input[type="checkbox"]:enabled', allOptions).prop('checked', false);
1642 - allOptions.removeClass(this.options.selectedClass);
1643 -
1644 - $('input[type="checkbox"]:enabled', allOptions).each($.proxy(function (index, element) {
1645 - var value = $(element).val();
1646 - var option = this.getOptionByValue(value);
1647 - if ($(option).prop('selected')) {
1648 - deselected.push(option);
1649 - }
1650 - $(option).prop('selected', false);
1651 - }, this));
1652 - }
1653 -
1654 - $('.multiselect-all input[value="' + this.options.selectAllValue + '"]', this.$popupContainer).prop('checked', false);
1655 -
1656 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1657 - this.updateOptGroups();
1658 - }
1659 -
1660 - this.updateButtonText();
1661 - this.updateSelectAll();
1662 -
1663 - if (triggerOnDeselectAll) {
1664 - this.options.onDeselectAll(deselected);
1665 - }
1666 - },
1667 -
1668 - /**
1669 - * Rebuild the plugin.
1670 - *
1671 - * Rebuilds the dropdown, the filter and the select all option.
1672 - */
1673 - rebuild: function () {
1674 - this.$popupContainer.html('');
1675 -
1676 - // Important to distinguish between radios and checkboxes.
1677 - this.options.multiple = this.$select.attr('multiple') === "multiple";
1678 -
1679 - this.buildSelectAll();
1680 - this.buildDropdownOptions();
1681 - this.buildFilter();
1682 - this.buildButtons();
1683 -
1684 - this.updateButtonText();
1685 - this.updateSelectAll(true);
1686 -
1687 - if (this.options.enableClickableOptGroups && this.options.multiple) {
1688 - this.updateOptGroups();
1689 - }
1690 -
1691 - if (this.options.disableIfEmpty) {
1692 - if ($('option', this.$select).length <= 0) {
1693 - if (!this.$select.prop('disabled')) {
1694 - this.disable(true);
1695 - }
1696 - }
1697 - else if (this.$select.data("disabled-by-option")) {
1698 - this.enable();
1699 - }
1700 - }
1701 -
1702 - if (this.options.dropRight) {
1703 - this.$container.addClass('dropright');
1704 - }
1705 - else if (this.options.dropUp) {
1706 - this.$container.addClass('dropup');
1707 - }
1708 -
1709 - if (this.options.widthSynchronizationMode !== 'never') {
1710 - this.synchronizeButtonAndPopupWidth();
1711 - }
1712 - },
1713 -
1714 - /**
1715 - * The provided data will be used to build the dropdown.
1716 - */
1717 - dataprovider: function (dataprovider) {
1718 -
1719 - var groupCounter = 0;
1720 - var $select = this.$select.empty();
1721 -
1722 - $.each(dataprovider, function (index, option) {
1723 - var $tag;
1724 -
1725 - if ($.isArray(option.children)) { // create optiongroup tag
1726 - groupCounter++;
1727 -
1728 - $tag = $('<optgroup/>').attr({
1729 - label: option.label || 'Group ' + groupCounter,
1730 - disabled: !!option.disabled,
1731 - value: option.value
1732 - });
1733 -
1734 - forEach(option.children, function (subOption) { // add children option tags
1735 - var attributes = {
1736 - value: subOption.value,
1737 - label: subOption.label || subOption.value,
1738 - title: subOption.title,
1739 - selected: !!subOption.selected,
1740 - disabled: !!subOption.disabled
1741 - };
1742 -
1743 - //Loop through attributes object and add key-value for each attribute
1744 - for (var key in subOption.attributes) {
1745 - attributes['data-' + key] = subOption.attributes[key];
1746 - }
1747 - //Append original attributes + new data attributes to option
1748 - $tag.append($('<option/>').attr(attributes));
1749 - });
1750 - }
1751 - else {
1752 -
1753 - var attributes = {
1754 - 'value': option.value,
1755 - 'label': option.label || option.value,
1756 - 'title': option.title,
1757 - 'class': option['class'],
1758 - 'selected': !!option['selected'],
1759 - 'disabled': !!option['disabled']
1760 - };
1761 - //Loop through attributes object and add key-value for each attribute
1762 - for (var key in option.attributes) {
1763 - attributes['data-' + key] = option.attributes[key];
1764 - }
1765 - //Append original attributes + new data attributes to option
1766 - $tag = $('<option/>').attr(attributes);
1767 -
1768 - $tag.text(option.label || option.value);
1769 - }
1770 -
1771 - $select.append($tag);
1772 - });
1773 -
1774 - this.rebuild();
1775 - },
1776 -
1777 - /**
1778 - * Enable the multiselect.
1779 - */
1780 - enable: function () {
1781 - this.$select.prop('disabled', false);
1782 - this.$button.prop('disabled', false)
1783 - .removeClass('disabled');
1784 -
1785 - this.updateButtonText();
1786 - },
1787 -
1788 - /**
1789 - * Disable the multiselect.
1790 - */
1791 - disable: function (disableByOption) {
1792 - this.$select.prop('disabled', true);
1793 - this.$button.prop('disabled', true)
1794 - .addClass('disabled');
1795 -
1796 - if (disableByOption) {
1797 - this.$select.data("disabled-by-option", true);
1798 - }
1799 - else {
1800 - this.$select.data("disabled-by-option", null);
1801 - }
1802 -
1803 - this.updateButtonText();
1804 - },
1805 -
1806 - /**
1807 - * Set the options.
1808 - *
1809 - * @param {Array} options
1810 - */
1811 - setOptions: function (options) {
1812 - this.options = this.mergeOptions(options);
1813 - },
1814 -
1815 - /**
1816 - * Merges the given options with the default options.
1817 - *
1818 - * @param {Array} options
1819 - * @returns {Array}
1820 - */
1821 - mergeOptions: function (options) {
1822 - return $.extend(true, {}, this.defaults, this.options, options);
1823 - },
1824 -
1825 - /**
1826 - * Checks whether a select all checkbox is present.
1827 - *
1828 - * @returns {Boolean}
1829 - */
1830 - hasSelectAll: function () {
1831 - return $('.multiselect-all', this.$popupContainer).length > 0;
1832 - },
1833 -
1834 - /**
1835 - * Update opt groups.
1836 - */
1837 - updateOptGroups: function () {
1838 - var $groups = $('.multiselect-group', this.$popupContainer)
1839 - var selectedClass = this.options.selectedClass;
1840 -
1841 - $groups.each(function () {
1842 - var $options = $(this).nextUntil('.multiselect-group')
1843 - .not('.multiselect-filter-hidden')
1844 - .not('.disabled');
1845 -
1846 - var checked = true;
1847 - $options.each(function () {
1848 - var $input = $('input', this);
1849 -
1850 - if (!$input.prop('checked')) {
1851 - checked = false;
1852 - }
1853 - });
1854 -
1855 - if (selectedClass) {
1856 - if (checked) {
1857 - $(this).addClass(selectedClass);
1858 - }
1859 - else {
1860 - $(this).removeClass(selectedClass);
1861 - }
1862 - }
1863 -
1864 - $('input', this).prop('checked', checked);
1865 - });
1866 - },
1867 -
1868 - /**
1869 - * Updates the select all checkbox based on the currently displayed and selected checkboxes.
1870 - */
1871 - updateSelectAll: function (notTriggerOnSelectAll) {
1872 - if (this.hasSelectAll()) {
1873 - var allBoxes = $(".multiselect-option:not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$popupContainer);
1874 - var allBoxesLength = allBoxes.length;
1875 - var checkedBoxesLength = allBoxes.filter(":checked").length;
1876 - var selectAllItem = $(".multiselect-all", this.$popupContainer);
1877 - var selectAllInput = selectAllItem.find("input");
1878 -
1879 - if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {
1880 - selectAllInput.prop("checked", true);
1881 - selectAllItem.addClass(this.options.selectedClass);
1882 - }
1883 - else {
1884 - selectAllInput.prop("checked", false);
1885 - selectAllItem.removeClass(this.options.selectedClass);
1886 - }
1887 - }
1888 - },
1889 -
1890 - /**
1891 - * Update the button text and its title based on the currently selected options.
1892 - */
1893 - updateButtonText: function () {
1894 - var options = this.getSelected();
1895 -
1896 - // First update the displayed button text.
1897 - if (this.options.enableHTML) {
1898 - $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));
1899 - }
1900 - else {
1901 - $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));
1902 - }
1903 -
1904 - // Now update the title attribute of the button.
1905 - $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
1906 - this.$button.trigger('change');
1907 - },
1908 -
1909 - /**
1910 - * Get all selected options.
1911 - *
1912 - * @returns {jQUery}
1913 - */
1914 - getSelected: function () {
1915 - return $('option', this.$select).filter(":selected");
1916 - },
1917 -
1918 - /**
1919 - * Gets a select option by its value.
1920 - *
1921 - * @param {String} value
1922 - * @returns {jQuery}
1923 - */
1924 - getOptionByValue: function (value) {
1925 -
1926 - var options = $('option', this.$select);
1927 - var valueToCompare = value.toString();
1928 -
1929 - for (var i = 0; i < options.length; i = i + 1) {
1930 - var option = options[i];
1931 - if (option.value === valueToCompare) {
1932 - return $(option);
1933 - }
1934 - }
1935 - },
1936 -
1937 - /**
1938 - * Get the input (radio/checkbox) by its value.
1939 - *
1940 - * @param {String} value
1941 - * @returns {jQuery}
1942 - */
1943 - getInputByValue: function (value) {
1944 -
1945 - var checkboxes = $('.multiselect-option input:not(.multiselect-search)', this.$popupContainer);
1946 - var valueToCompare = value.toString();
1947 -
1948 - for (var i = 0; i < checkboxes.length; i = i + 1) {
1949 - var checkbox = checkboxes[i];
1950 - if (checkbox.value === valueToCompare) {
1951 - return $(checkbox);
1952 - }
1953 - }
1954 - },
1955 -
1956 - /**
1957 - * Used for knockout integration.
1958 - */
1959 - updateOriginalOptions: function () {
1960 - this.originalOptions = this.$select.clone()[0].options;
1961 - },
1962 -
1963 - asyncFunction: function (callback, timeout, self) {
1964 - var args = Array.prototype.slice.call(arguments, 3);
1965 - return setTimeout(function () {
1966 - callback.apply(self || window, args);
1967 - }, timeout);
1968 - },
1969 -
1970 - setAllSelectedText: function (allSelectedText) {
1971 - this.options.allSelectedText = allSelectedText;
1972 - this.updateButtonText();
1973 - },
1974 -
1975 - isFirefox: function () {
1976 - var firefoxIdentifier = 'firefox';
1977 - var valueNotFoundIndex = -1;
1978 -
1979 - if (navigator && navigator.userAgent) {
1980 - return navigator.userAgent.toLocaleLowerCase().indexOf(firefoxIdentifier) > valueNotFoundIndex;
1981 - }
1982 -
1983 - return false;
1984 - }
1985 - };
1986 -
1987 - $.fn.multiselect = function (option, parameter, extraOptions) {
1988 - return this.each(function () {
1989 - var data = $(this).data('multiselect');
1990 - var options = typeof option === 'object' && option;
1991 -
1992 - // Initialize the multiselect.
1993 - if (!data) {
1994 - data = new Multiselect(this, options);
1995 - $(this).data('multiselect', data);
1996 - }
1997 -
1998 - // Call multiselect method.
1999 - if (typeof option === 'string') {
2000 - data[option](parameter, extraOptions);
2001 -
2002 - if (option === 'destroy') {
2003 - $(this).data('multiselect', false);
2004 - }
2005 - }
2006 - });
2007 - };
2008 -
2009 - $.fn.multiselect.Constructor = Multiselect;
2010 -
2011 - $(function () {
2012 - $("select[data-role=multiselect]").multiselect();
2013 - });
2014 -
2015 -});
44 +!function(t,e){"function"==typeof define&&define.amd&&"function"==typeof require&&"function"==typeof require.specified&&require.specified("knockout")?define(["jquery","knockout"],e):e(t.jQuery,t.ko)}(this,(function(t,e){"use strict";void 0!==e&&e.bindingHandlers&&!e.bindingHandlers.multiselect&&(e.bindingHandlers.multiselect={after:["options","value","selectedOptions","enable","disable"],init:function(i,s,o,n,l){var p=t(i),a=e.toJS(s());if(p.multiselect(a),o.has("options")){var r=o.get("options");e.isObservable(r)&&e.computed({read:function(){r(),setTimeout((function(){var t=p.data("multiselect");t&&t.updateOriginalOptions(),p.multiselect("rebuild")}),1)},disposeWhenNodeIsRemoved:i})}if(o.has("value")){var c=o.get("value");e.isObservable(c)&&e.computed({read:function(){c(),setTimeout((function(){p.multiselect("refresh")}),1)},disposeWhenNodeIsRemoved:i}).extend({rateLimit:100,notifyWhenChangesStop:!0})}if(o.has("selectedOptions")){var h=o.get("selectedOptions");e.isObservable(h)&&e.computed({read:function(){h(),setTimeout((function(){p.multiselect("refresh")}),1)},disposeWhenNodeIsRemoved:i}).extend({rateLimit:100,notifyWhenChangesStop:!0})}var u=function(t){setTimeout((function(){t?p.multiselect("enable"):p.multiselect("disable")}))};if(o.has("enable")){var d=o.get("enable");e.isObservable(d)?e.computed({read:function(){u(d())},disposeWhenNodeIsRemoved:i}).extend({rateLimit:100,notifyWhenChangesStop:!0}):u(d)}if(o.has("disable")){var f=o.get("disable");e.isObservable(f)?e.computed({read:function(){u(!f())},disposeWhenNodeIsRemoved:i}).extend({rateLimit:100,notifyWhenChangesStop:!0}):u(!f)}e.utils.domNodeDisposal.addDisposeCallback(i,(function(){p.multiselect("destroy")}))},update:function(i,s,o,n,l){var p=t(i),a=e.toJS(s());p.multiselect("setOptions",a),p.multiselect("rebuild")}});function i(e,i){this.$select=t(e),this.options=this.mergeOptions(t.extend({},i,this.$select.data())),this.$select.attr("data-placeholder")&&(this.options.nonSelectedText=this.$select.data("placeholder")),this.originalOptions=this.$select.clone()[0].options,this.query="",this.searchTimeout=null,this.lastToggledInput=null,this.multiselectId=this.generateUniqueId()+"_0",this.internalIdCount=0,this.options.multiple="multiple"===this.$select.attr("multiple"),this.options.onChange=t.proxy(this.options.onChange,this),this.options.onSelectAll=t.proxy(this.options.onSelectAll,this),this.options.onDeselectAll=t.proxy(this.options.onDeselectAll,this),this.options.onDropdownShow=t.proxy(this.options.onDropdownShow,this),this.options.onDropdownHide=t.proxy(this.options.onDropdownHide,this),this.options.onDropdownShown=t.proxy(this.options.onDropdownShown,this),this.options.onDropdownHidden=t.proxy(this.options.onDropdownHidden,this),this.options.onInitialized=t.proxy(this.options.onInitialized,this),this.options.onFiltering=t.proxy(this.options.onFiltering,this),this.buildContainer(),this.buildButton(),this.buildDropdown(),this.buildReset(),this.buildSelectAll(),this.buildDropdownOptions(),this.buildFilter(),this.buildButtons(),this.updateButtonText(),this.updateSelectAll(!0),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups(),this.options.wasDisabled=this.$select.prop("disabled"),this.options.disableIfEmpty&&t("option",this.$select).length<=0&&!this.options.wasDisabled&&this.disable(!0),this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container),this.$select.prop("tabindex","-1"),"never"!==this.options.widthSynchronizationMode&&this.synchronizeButtonAndPopupWidth(),this.$select.data("multiselect",this),this.options.onInitialized(this.$select,this.$container)}i.prototype={defaults:{buttonText:function(e,i){if(this.disabledText.length>0&&i.prop("disabled"))return this.disabledText;if(0===e.length)return this.nonSelectedText;if(this.allSelectedText&&e.length===t("option",t(i)).length&&1!==t("option",t(i)).length&&this.multiple)return this.selectAllNumber?this.allSelectedText+" ("+e.length+")":this.allSelectedText;if(0!=this.numberDisplayed&&e.length>this.numberDisplayed)return e.length+" "+this.nSelectedText;var s="",o=this.delimiterText;return e.each((function(){var e=void 0!==t(this).attr("label")?t(this).attr("label"):t(this).text();s+=e+o})),s.substr(0,s.length-this.delimiterText.length)},buttonTitle:function(e,i){if(0===e.length)return this.nonSelectedText;var s="",o=this.delimiterText;return e.each((function(){var e=void 0!==t(this).attr("label")?t(this).attr("label"):t(this).text();s+=e+o})),s.substr(0,s.length-this.delimiterText.length)},checkboxName:function(t){return!1},optionLabel:function(e){return t(e).attr("label")||t(e).text()},optionClass:function(e){return t(e).attr("class")||""},onChange:function(t,e){},onDropdownShow:function(t){},onDropdownHide:function(t){},onDropdownShown:function(t){},onDropdownHidden:function(t){},onSelectAll:function(t){},onDeselectAll:function(t){},onInitialized:function(t,e){},onFiltering:function(t){},enableHTML:!1,buttonClass:"custom-select",inheritClass:!1,buttonWidth:"auto",buttonContainer:'<div class="btn-group" />',dropRight:!1,dropUp:!1,selectedClass:"active",maxHeight:null,includeSelectAllOption:!1,includeSelectAllIfMoreThan:0,selectAllText:" Select all",selectAllValue:"multiselect-all",selectAllName:!1,selectAllNumber:!0,selectAllJustVisible:!0,enableFiltering:!1,enableCaseInsensitiveFiltering:!1,enableFullValueFiltering:!1,enableClickableOptGroups:!1,enableCollapsibleOptGroups:!1,collapseOptGroupsByDefault:!1,filterPlaceholder:"Search",filterBehavior:"text",includeFilterClearBtn:!0,preventInputChangeEvent:!1,nonSelectedText:"None selected",nSelectedText:"selected",allSelectedText:"All selected",resetButtonText:"Reset",numberDisplayed:3,disableIfEmpty:!1,disabledText:"",delimiterText:", ",includeResetOption:!1,includeResetDivider:!1,resetText:"Reset",indentGroupOptions:!0,widthSynchronizationMode:"never",buttonTextAlignment:"center",enableResetButton:!1,templates:{button:'<button type="button" class="multiselect form-select dropdown-toggle" data-bs-toggle="dropdown"><span class="multiselect-selected-text"></span></button>',popupContainer:'<div class="multiselect-container dropdown-menu"></div>',filter:'<div class="multiselect-filter d-flex align-items-center"><i class="fas fa-sm fa-search text-body-secondary"></i><input type="search" class="multiselect-search form-control" /></div>',buttonGroup:'<div class="multiselect-buttons btn-group" style="display:flex;"></div>',buttonGroupReset:'<button type="button" class="multiselect-reset btn btn-secondary w-100"></button>',option:'<button type="button" class="multiselect-option dropdown-item"></button>',divider:'<div class="dropdown-divider"></div>',optionGroup:'<button type="button" class="multiselect-group dropdown-item"></button>',resetButton:'<div class="multiselect-reset text-center p-2"><button type="button" class="btn btn-sm w-100 btn-outline-secondary"></button></div>'}},constructor:i,buildContainer:function(){this.$container=t(this.options.buttonContainer),"never"!==this.options.widthSynchronizationMode?this.$container.on("show.bs.dropdown",t.proxy((function(){this.synchronizeButtonAndPopupWidth(),this.options.onDropdownShow()}),this)):this.$container.on("show.bs.dropdown",this.options.onDropdownShow),this.$container.on("hide.bs.dropdown",this.options.onDropdownHide),this.$container.on("shown.bs.dropdown",this.options.onDropdownShown),this.$container.on("hidden.bs.dropdown",this.options.onDropdownHidden)},buildButton:function(){if(this.$button=t(this.options.templates.button).addClass(this.options.buttonClass),this.$select.attr("class")&&this.options.inheritClass&&this.$button.addClass(this.$select.attr("class")),this.$select.prop("disabled")?this.disable():this.enable(),this.options.buttonWidth&&"auto"!==this.options.buttonWidth&&(this.$button.css({width:"100%"}),this.$container.css({width:this.options.buttonWidth})),this.options.buttonTextAlignment)switch(this.options.buttonTextAlignment){case"left":this.$button.addClass("text-start");break;case"center":this.$button.addClass("text-center");break;case"right":this.$button.addClass("text-end")}var e=this.$select.attr("tabindex");e&&this.$button.attr("tabindex",e),this.$container.prepend(this.$button)},buildDropdown:function(){this.$popupContainer=t(this.options.templates.popupContainer),this.options.dropRight?this.$container.addClass("dropend"):this.options.dropUp&&this.$container.addClass("dropup"),this.options.maxHeight&&this.$popupContainer.css({"max-height":this.options.maxHeight+"px","overflow-y":"auto","overflow-x":"hidden"}),"never"!==this.options.widthSynchronizationMode&&this.$popupContainer.css("overflow-x","hidden"),this.$popupContainer.on("touchstart click",(function(t){t.stopPropagation()})),this.$container.append(this.$popupContainer)},synchronizeButtonAndPopupWidth:function(){if(this.$popupContainer&&"never"!==this.options.widthSynchronizationMode){var t=this.$button.outerWidth();switch(this.options.widthSynchronizationMode){case"always":this.$popupContainer.css("min-width",t),this.$popupContainer.css("max-width",t);break;case"ifPopupIsSmaller":this.$popupContainer.css("min-width",t);break;case"ifPopupIsWider":this.$popupContainer.css("max-width",t)}}},buildDropdownOptions:function(){if(this.$select.children().each(t.proxy((function(e,i){var s=t(i),o=s.prop("tagName").toLowerCase();s.prop("value")!==this.options.selectAllValue&&("optgroup"===o?this.createOptgroup(i):"option"===o&&("divider"===s.data("role")?this.createDivider():this.createOptionValue(i,!1)))}),this)),t(this.$popupContainer).off("change",'> *:not(.multiselect-group) input[type="checkbox"], > *:not(.multiselect-group) input[type="radio"]'),t(this.$popupContainer).on("change",'> *:not(.multiselect-group) input[type="checkbox"], > *:not(.multiselect-group) input[type="radio"]',t.proxy((function(e){var i=t(e.target),s=i.prop("checked")||!1,o=i.val()===this.options.selectAllValue;this.options.selectedClass&&(s?i.closest(".multiselect-option").addClass(this.options.selectedClass):i.closest(".multiselect-option").removeClass(this.options.selectedClass));var n=i.attr("id"),l=this.getOptionById(n),p=t("option",this.$select).not(l),a=t("input",this.$container).not(i);if(o?s?this.selectAll(this.options.selectAllJustVisible,!0):this.deselectAll(this.options.selectAllJustVisible,!0):(s?(l.prop("selected",!0),this.options.multiple?l.prop("selected",!0):(this.options.selectedClass&&t(a).closest(".dropdown-item").removeClass(this.options.selectedClass),t(a).prop("checked",!1),p.prop("selected",!1),this.$button.click()),"active"===this.options.selectedClass&&p.closest(".dropdown-item").css("outline","")):l.prop("selected",!1),this.options.onChange(l,s),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()),this.$select.change(),this.updateButtonText(),this.options.preventInputChangeEvent)return!1}),this)),t(".multiselect-option",this.$popupContainer).off("mousedown"),t(".multiselect-option",this.$popupContainer).on("mousedown",(function(t){if(t.shiftKey)return!1})),t(this.$popupContainer).off("touchstart click",".multiselect-option, .multiselect-all, .multiselect-group"),t(this.$popupContainer).on("touchstart click",".multiselect-option, .multiselect-all, .multiselect-group",t.proxy((function(e){e.stopPropagation();var i=t(e.target);if(e.shiftKey&&this.options.multiple){i.is("input")||(e.preventDefault(),(i=i.closest(".multiselect-option").find("input")).prop("checked",!i.prop("checked")));var s=i.prop("checked")||!1;if(null!==this.lastToggledInput&&this.lastToggledInput!==i){var o=this.$popupContainer.find(".multiselect-option:visible").index(i.closest(".multiselect-option")),n=this.$popupContainer.find(".multiselect-option:visible").index(this.lastToggledInput.closest(".multiselect-option"));if(o>n){var l=n;n=o,o=l}++n;var p=this.$popupContainer.find(".multiselect-option:not(.multiselect-filter-hidden)").slice(o,n).find("input");p.prop("checked",s),this.options.selectedClass&&p.closest(".multiselect-option").toggleClass(this.options.selectedClass,s);for(var a=0,r=p.length;a<r;a++){var c=t(p[a]);this.getOptionById(c.attr("id")).prop("selected",s)}}i.trigger("change")}else if(!i.is("input")){if((c=i.closest(".multiselect-option, .multiselect-all").find(".form-check-input")).length>0)!this.options.multiple&&c.prop("checked")||(c.prop("checked",!c.prop("checked")),c.change());else if(this.options.enableClickableOptGroups&&this.options.multiple&&!i.hasClass("caret-container")){var h=i;h.hasClass("multiselect-group")||(h=i.closest(".multiselect-group")),(c=h.find(".form-check-input")).length>0&&(c.prop("checked",!c.prop("checked")),c.change())}e.preventDefault()}i.closest(".multiselect-option").find("input[type='checkbox'], input[type='radio']").length>0?this.lastToggledInput=i:this.lastToggledInput=null,i.blur()}),this)),this.$container.off("keydown.multiselect").on("keydown.multiselect",t.proxy((function(e){var i=t(this.$container).find(".multiselect-option:not(.disabled), .multiselect-group:not(.disabled), .multiselect-all").filter(":visible"),s=i.index(i.filter(":focus")),o=t(".multiselect-search",this.$container);if(9===e.keyCode&&this.$container.hasClass("show"))this.$button.click();else if(13==e.keyCode){var n=i.eq(s);setTimeout((function(){n.focus()}),1)}else if(38==e.keyCode)0!=s||o.is(":focus")||setTimeout((function(){o.focus()}),1);else if(40==e.keyCode)if(o.is(":focus")){var l=i.eq(0);setTimeout((function(){o.blur(),l.focus()}),1)}else-1==s&&setTimeout((function(){o.focus()}),1)}),this)),this.options.enableClickableOptGroups&&this.options.multiple&&(t(".multiselect-group input",this.$popupContainer).off("change"),t(".multiselect-group input",this.$popupContainer).on("change",t.proxy((function(e){e.stopPropagation();var i=t(e.target).prop("checked")||!1,s=t(e.target).closest(".dropdown-item"),o=s.nextUntil(".multiselect-group").not(".multiselect-filter-hidden").not(".disabled").find("input"),n=[];this.options.selectedClass&&(i?s.addClass(this.options.selectedClass):s.removeClass(this.options.selectedClass)),t.each(o,t.proxy((function(e,s){var o=t(s),l=o.attr("id"),p=this.getOptionById(l);i?(o.prop("checked",!0),o.closest(".dropdown-item").addClass(this.options.selectedClass),p.prop("selected",!0)):(o.prop("checked",!1),o.closest(".dropdown-item").removeClass(this.options.selectedClass),p.prop("selected",!1)),n.push(p)}),this)),this.options.onChange(n,i),this.$select.change(),this.updateButtonText(),this.updateSelectAll()}),this))),this.options.enableCollapsibleOptGroups){let e=this.options.enableClickableOptGroups?".multiselect-group .caret-container":".multiselect-group";t(e,this.$popupContainer).off("click"),t(e,this.$popupContainer).on("click",t.proxy((function(e){var i=t(e.target).closest(".multiselect-group"),s=i.nextUntil(".multiselect-group").not(".multiselect-filter-hidden"),o=!0;s.each((function(){o=o&&!t(this).hasClass("multiselect-collapsible-hidden")})),o?(s.hide().addClass("multiselect-collapsible-hidden"),i.get(0).classList.add("closed")):(s.show().removeClass("multiselect-collapsible-hidden"),i.get(0).classList.remove("closed"))}),this))}},createCheckbox:function(e,i,s,o,n,l,p){var a=t("<span />");a.addClass("form-check");var r=t('<label class="form-check-label" />');this.options.enableHTML&&t(i).length>0?r.html(i):r.text(i),a.append(r);var c=t('<input class="form-check-input"/>').attr("type",l);return c.val(o),a.prepend(c),p&&(c.attr("id",p),r.attr("for",p)),s&&c.attr("name",s),e.prepend(a),e.attr("title",n||i),c},createOptionValue:function(e,i){var s=t(e);s.is(":selected")&&s.prop("selected",!0);var o=this.options.optionLabel(e),n=this.options.optionClass(e),l=s.val(),p=this.options.multiple?"checkbox":"radio",a=s.attr("title"),r=t(this.options.templates.option);r.addClass(n),i&&this.options.indentGroupOptions&&(this.options.enableCollapsibleOptGroups?r.addClass("multiselect-group-option-indented-full"):r.addClass("multiselect-group-option-indented")),this.options.collapseOptGroupsByDefault&&"optgroup"===t(e).parent().prop("tagName").toLowerCase()&&(r.addClass("multiselect-collapsible-hidden"),r.hide());var c=this.options.checkboxName(s),h=this.createAndApplyUniqueId(s),u=this.createCheckbox(r,o,c,l,a,p,h),d=s.prop("selected")||!1;l===this.options.selectAllValue&&(r.addClass("multiselect-all"),r.removeClass("multiselect-option"),u.parent().parent().addClass("multiselect-all")),this.$popupContainer.append(r),s.is(":disabled")&&u.attr("disabled","disabled").prop("disabled",!0).closest(".dropdown-item").addClass("disabled"),u.prop("checked",d),d&&this.options.selectedClass&&u.closest(".dropdown-item").addClass(this.options.selectedClass)},createDivider:function(e){var i=t(this.options.templates.divider);this.$popupContainer.append(i)},createOptgroup:function(e){var i=t(e),s=i.attr("label"),o=i.attr("value"),n=i.attr("title"),l=t("<span class='multiselect-group dropdown-item-text'></span>");if(this.options.enableClickableOptGroups&&this.options.multiple){l=t(this.options.templates.optionGroup);var p=this.createAndApplyUniqueId(i);this.createCheckbox(l,s,null,o,n,"checkbox",p)}else this.options.enableHTML?l.html(" "+s):l.text(" "+s);var a=this.options.optionClass(e);l.addClass(a),this.options.enableCollapsibleOptGroups&&(l.find(".form-check").addClass("d-inline-block"),l.get(0).insertAdjacentHTML("afterbegin",'<span class="caret-container dropdown-toggle"></span>')),i.is(":disabled")&&l.addClass("disabled"),this.$popupContainer.append(l),t("option",e).each(t.proxy((function(t,e){this.createOptionValue(e,!0)}),this))},buildReset:function(){if(this.options.includeResetOption){if(this.options.includeResetDivider){var e=t(this.options.templates.divider);e.addClass("mt-0"),this.$popupContainer.prepend(e)}var i=t(this.options.templates.resetButton);this.options.enableHTML?t("button",i).html(this.options.resetText):t("button",i).text(this.options.resetText),t("button",i).click(t.proxy((function(){this.clearSelection()}),this)),this.$popupContainer.prepend(i)}},buildSelectAll:function(){if("number"==typeof this.options.selectAllValue&&(this.options.selectAllValue=this.options.selectAllValue.toString()),!this.hasSelectAll()&&this.options.includeSelectAllOption&&this.options.multiple&&t("option",this.$select).length>this.options.includeSelectAllIfMoreThan){this.options.includeSelectAllDivider&&this.$popupContainer.prepend(t(this.options.templates.divider));var e=t(this.options.templates.li||this.options.templates.option),i=this.createCheckbox(e,this.options.selectAllText,this.options.selectAllName,this.options.selectAllValue,this.options.selectAllText,"checkbox",this.createAndApplyUniqueId(null));e.addClass("multiselect-all"),e.removeClass("multiselect-option"),e.find(".form-check-label").addClass("font-weight-bold"),this.$popupContainer.prepend(e),i.prop("checked",!1)}},buildFilter:function(){if(this.options.enableFiltering||this.options.enableCaseInsensitiveFiltering){var e=Math.max(this.options.enableFiltering,this.options.enableCaseInsensitiveFiltering);this.$select.find("option").length>=e&&(this.$filter=t(this.options.templates.filter),t("input",this.$filter).attr("placeholder",this.options.filterPlaceholder),this.options.includeFilterClearBtn?(this.isFirefox()&&0===this.$filter.find(".multiselect-clear-filter").length&&this.$filter.append("<i class='fas fa-times text-body-secondary multiselect-clear-filter multiselect-moz-clear-filter'></i>"),this.$filter.find(".multiselect-clear-filter").on("click",t.proxy((function(e){clearTimeout(this.searchTimeout),this.query="",this.$filter.find(".multiselect-search").val(""),t(".dropdown-item",this.$popupContainer).show().removeClass("multiselect-filter-hidden"),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()}),this))):(this.$filter.find(".multiselect-search").attr("type","text"),this.$filter.find(".multiselect-clear-filter").remove()),this.$popupContainer.prepend(this.$filter),this.$filter.val(this.query).on("click",(function(t){t.stopPropagation()})).on("input keydown",t.proxy((function(e){13===e.which&&e.preventDefault(),this.isFirefox()&&this.options.includeFilterClearBtn&&(e.target.value?this.$filter.find(".multiselect-moz-clear-filter").show():this.$filter.find(".multiselect-moz-clear-filter").hide()),clearTimeout(this.searchTimeout),this.searchTimeout=this.asyncFunction(t.proxy((function(){var i,s;this.query!==e.target.value&&(this.query=e.target.value,t.each(t(".multiselect-option, .multiselect-group",this.$popupContainer),t.proxy((function(e,o){var n=t("input",o).length>0?t("input",o).val():"",l=t(".form-check-label",o).text(),p="";if("text"===this.options.filterBehavior?p=l:"value"===this.options.filterBehavior?p=n:"both"===this.options.filterBehavior&&(p=l+"\n"+n),n!==this.options.selectAllValue&&l){var a=!1;if(this.options.enableCaseInsensitiveFiltering&&(p=p.toLowerCase(),this.query=this.query.toLowerCase()),this.options.enableFullValueFiltering&&"both"!==this.options.filterBehavior){var r=p.trim().substring(0,this.query.length);this.query.indexOf(r)>-1&&(a=!0)}else p.indexOf(this.query)>-1&&(a=!0);a||(t(o).css("display","none"),t(o).addClass("multiselect-filter-hidden")),a&&(t(o).css("display","block"),t(o).removeClass("multiselect-filter-hidden")),t(o).hasClass("multiselect-group")?(i=o,s=a):(a&&t(i).show().removeClass("multiselect-filter-hidden"),!a&&s&&t(o).show().removeClass("multiselect-filter-hidden"))}}),this)));this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups(),this.updatePopupPosition(),this.options.onFiltering(e.target)}),this),300,this)}),this)))}},buildButtons:function(){if(this.options.enableResetButton){var e=t(this.options.templates.buttonGroup);this.$buttonGroupReset=t(this.options.templates.buttonGroupReset).text(this.options.resetButtonText),e.append(this.$buttonGroupReset),this.$popupContainer.prepend(e),this.defaultSelection={},t("option",this.$select).each(t.proxy((function(e,i){var s=t(i);this.defaultSelection[s.val()]=s.prop("selected")}),this)),this.$buttonGroupReset.on("click",t.proxy((function(e){t("option",this.$select).each(t.proxy((function(e,i){var s=t(i);s.prop("selected",this.defaultSelection[s.val()])}),this)),this.refresh(),this.options.enableFiltering&&(this.$filter.trigger("keydown"),t("input",this.$filter).val(""))}),this))}},updatePopupPosition:function(){var t=this.$popupContainer.css("transform"),e=t.substring(0,t.indexOf("(")),i=t.substring(t.indexOf("(")+1,t.length-1).split(","),s=5;if("matrix3d"===e&&(s=13),!(i.length<s)){var o=i[s];(o=void 0===o?0:o.trim())<0&&(o=-1*this.$popupContainer.css("height").replace("px",""),i[s]=o,t=e+"("+i.join(",")+")",this.$popupContainer.css("transform",t))}},destroy:function(){this.$container.remove(),this.$select.unwrap(),this.$select.show(),this.$select.prop("disabled",this.options.wasDisabled),this.$select.find("option, optgroup").removeAttr("data-multiselectid"),this.$select.data("multiselect",null)},refresh:function(){var e={};t(".multiselect-option input",this.$popupContainer).each((function(){e[t(this).val()]=t(this)})),t("option",this.$select).each(t.proxy((function(i,s){var o=t(s),n=e[t(s).val()];o.is(":selected")?(n.prop("checked",!0),this.options.selectedClass&&n.closest(".multiselect-option").addClass(this.options.selectedClass)):(n.prop("checked",!1),this.options.selectedClass&&n.closest(".multiselect-option").removeClass(this.options.selectedClass)),o.is(":disabled")?n.attr("disabled","disabled").prop("disabled",!0).closest(".multiselect-option").addClass("disabled"):n.prop("disabled",!1).closest(".multiselect-option").removeClass("disabled")}),this)),this.updateButtonText(),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()},select:function(e,i){t.isArray(e)||(e=[e]);for(var s=0;s<e.length;s++){var o=e[s];if(null!=o){var n=this.getInputsByValue(o);if(n&&0!==n.length)for(var l=0;l<n.length;++l){var p=n[l],a=this.getOptionById(p.attr("id"));if(void 0!==a){if(this.options.selectedClass&&p.closest(".dropdown-item").addClass(this.options.selectedClass),p.prop("checked",!0),a.prop("selected",!0),!this.options.multiple){var r=t("input",this.$container).not(p);t(r).prop("checked",!1),t(r).closest(".multiselect-option").removeClass("active"),t("option",this.$select).not(a).prop("selected",!1)}i&&this.options.onChange(a,!0)}}}}this.updateButtonText(),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()},clearSelection:function(){this.deselectAll(!1),this.updateButtonText(),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()},deselect:function(e,i){if(this.options.multiple){t.isArray(e)||(e=[e]);for(var s=0;s<e.length;s++){var o=e[s];if(null!=o){var n=this.getInputsByValue(o);if(n&&0!==n.length)for(var l=0;l<n.length;++l){var p=n[l],a=this.getOptionById(p.attr("id"));a&&(this.options.selectedClass&&p.closest(".dropdown-item").removeClass(this.options.selectedClass),p.prop("checked",!1),a.prop("selected",!1),i&&this.options.onChange(a,!1))}}}this.updateButtonText(),this.updateSelectAll(),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups()}},selectAll:function(e,i){if(this.options.multiple){var s=[];if(e=void 0===e||e){var o=t(".multiselect-option:not(.disabled):not(.multiselect-filter-hidden)",this.$popupContainer);t("input:enabled",o).prop("checked",!0),o.addClass(this.options.selectedClass),t("input:enabled",o).each(t.proxy((function(e,i){var o=t(i).attr("id"),n=this.getOptionById(o);t(n).prop("selected")||s.push(n),t(n).prop("selected",!0)}),this))}else{var n=t(".multiselect-option:not(.disabled)",this.$popupContainer);t("input:enabled",n).prop("checked",!0),n.addClass(this.options.selectedClass),t("input:enabled",n).each(t.proxy((function(e,i){var o=t(i).attr("id"),n=this.getOptionById(o);t(n).prop("selected")||s.push(n),t(n).prop("selected",!0)}),this))}t('.multiselect-option input[value="'+this.options.selectAllValue+'"]',this.$popupContainer).prop("checked",!0),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups(),this.updateButtonText(),this.updateSelectAll(),i&&this.options.onSelectAll(s)}},deselectAll:function(e,i){if(this.options.multiple){var s=[];if(e=void 0===e||e){var o=t(".multiselect-option:not(.disabled):not(.multiselect-filter-hidden)",this.$popupContainer);t('input[type="checkbox"]:enabled',o).prop("checked",!1),o.removeClass(this.options.selectedClass),t('input[type="checkbox"]:enabled',o).each(t.proxy((function(e,i){var o=t(i).attr("id"),n=this.getOptionById(o);t(n).prop("selected")&&s.push(n),t(n).prop("selected",!1)}),this))}else{var n=t(".multiselect-option:not(.disabled):not(.multiselect-group)",this.$popupContainer);t('input[type="checkbox"]:enabled',n).prop("checked",!1),n.removeClass(this.options.selectedClass),t('input[type="checkbox"]:enabled',n).each(t.proxy((function(e,i){var o=t(i).attr("id"),n=this.getOptionById(o);t(n).prop("selected")&&s.push(n),t(n).prop("selected",!1)}),this))}t('.multiselect-all input[value="'+this.options.selectAllValue+'"]',this.$popupContainer).prop("checked",!1),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups(),this.updateButtonText(),this.updateSelectAll(),i&&this.options.onDeselectAll(s)}},rebuild:function(){this.internalIdCount=0,this.$popupContainer.html(""),this.$select.find("option, optgroup").removeAttr("data-multiselectid"),this.options.multiple="multiple"===this.$select.attr("multiple"),this.buildSelectAll(),this.buildDropdownOptions(),this.buildFilter(),this.buildButtons(),this.updateButtonText(),this.updateSelectAll(!0),this.options.enableClickableOptGroups&&this.options.multiple&&this.updateOptGroups(),this.options.disableIfEmpty&&(t("option",this.$select).length<=0?this.$select.prop("disabled")||this.disable(!0):this.$select.data("disabled-by-option")&&this.enable()),this.options.dropRight?this.$container.addClass("dropend"):this.options.dropUp&&this.$container.addClass("dropup"),"never"!==this.options.widthSynchronizationMode&&this.synchronizeButtonAndPopupWidth()},dataprovider:function(e){var i=0,s=this.$select.empty();t.each(e,(function(e,o){var n;if(t.isArray(o.children))i++,n=t("<optgroup/>").attr({label:o.label||"Group "+i,disabled:!!o.disabled,value:o.value}),function(t,e){for(var i=0;i<t.length;++i)e(t[i],i)}(o.children,(function(e){var i={value:e.value,label:void 0!==e.label&&null!==e.label?e.label:e.value,title:e.title,class:e.class,selected:!!e.selected,disabled:!!e.disabled};for(var s in e.attributes)i["data-"+s]=e.attributes[s];n.append(t("<option/>").attr(i))}));else{var l={value:o.value,label:void 0!==o.label&&null!==o.label?o.label:o.value,title:o.title,class:o.class,selected:!!o.selected,disabled:!!o.disabled};for(var p in o.attributes)l["data-"+p]=o.attributes[p];(n=t("<option/>").attr(l)).text(void 0!==o.label&&null!==o.label?o.label:o.value)}s.append(n)})),this.rebuild()},enable:function(){this.$select.prop("disabled",!1),this.$button.prop("disabled",!1).removeClass("disabled"),this.updateButtonText()},disable:function(t){this.$select.prop("disabled",!0),this.$button.prop("disabled",!0).addClass("disabled"),t?this.$select.data("disabled-by-option",!0):this.$select.data("disabled-by-option",null),this.updateButtonText()},setOptions:function(t){this.options=this.mergeOptions(t)},mergeOptions:function(e){return t.extend(!0,{},this.defaults,this.options,e)},hasSelectAll:function(){return t(".multiselect-all",this.$popupContainer).length>0},updateOptGroups:function(){var e=t(".multiselect-group",this.$popupContainer),i=this.options.selectedClass;e.each((function(){var e=t(this).nextUntil(".multiselect-group").not(".multiselect-filter-hidden").not(".disabled"),s=!0;e.each((function(){t("input",this).prop("checked")||(s=!1)})),i&&(s?t(this).addClass(i):t(this).removeClass(i)),t("input",this).prop("checked",s)}))},updateSelectAll:function(e){if(this.hasSelectAll()){var i=t(".multiselect-option:not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled",this.$popupContainer),s=i.length,o=i.filter(":checked").length,n=t(".multiselect-all",this.$popupContainer),l=n.find("input");o>0&&o===s?(l.prop("checked",!0),n.addClass(this.options.selectedClass)):(l.prop("checked",!1),n.removeClass(this.options.selectedClass))}},updateButtonText:function(){var e=this.getSelected();this.options.enableHTML?t(".multiselect .multiselect-selected-text",this.$container).html(this.options.buttonText(e,this.$select)):t(".multiselect .multiselect-selected-text",this.$container).text(this.options.buttonText(e,this.$select)),t(".multiselect",this.$container).attr("title",this.options.buttonTitle(e,this.$select)),this.$button.trigger("change")},getSelected:function(){return t("option",this.$select).filter(":selected")},getOptionById:function(t){return t?this.$select.find("option[data-multiselectid="+t+"], optgroup[data-multiselectid="+t+"]"):null},getInputsByValue:function(e){for(var i=t(".multiselect-option input:not(.multiselect-search)",this.$popupContainer),s=e.toString(),o=[],n=0;n<i.length;n+=1){var l=i[n];l.value===s&&o.push(t(l))}return o},updateOriginalOptions:function(){this.originalOptions=this.$select.clone()[0].options},asyncFunction:function(t,e,i){var s=Array.prototype.slice.call(arguments,3);return setTimeout((function(){t.apply(i||window,s)}),e)},setAllSelectedText:function(t){this.options.allSelectedText=t,this.updateButtonText()},isFirefox:function(){return!(!navigator||!navigator.userAgent)&&navigator.userAgent.toLocaleLowerCase().indexOf("firefox")>-1},createAndApplyUniqueId:function(t){var e="multiselect_"+this.multiselectId+"_"+this.internalIdCount++;return t&&(t[0].dataset.multiselectid=e),e},generateUniqueId:function(){return Math.random().toString(36).substr(2)}},t.fn.multiselect=function(e,s,o){return this.each((function(){var n=t(this).data("multiselect");n||(n=new i(this,"object"==typeof e&&e)),"string"==typeof e&&n[e](s,o)}))},t.fn.multiselect.Constructor=i,t((function(){t("select[data-role=multiselect]").multiselect()}))}));