| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776 | /** * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/) * * Apache License, Version 2.0: * Copyright (c) 2012 - 2018 David Stutz * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * BSD 3-Clause License: * Copyright (c) 2012 - 2018 David Stutz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: *    - Redistributions of source code must retain the above copyright notice, *      this list of conditions and the following disclaimer. *    - Redistributions in binary form must reproduce the above copyright notice, *      this list of conditions and the following disclaimer in the documentation *      and/or other materials provided with the distribution. *    - Neither the name of David Stutz nor the names of its contributors may be *      used to endorse or promote products derived from this software without *      specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */(function (root, factory) {    // check to see if 'knockout' AMD module is specified if using requirejs    if (typeof define === 'function' && define.amd &&        typeof require === 'function' && typeof require.specified === 'function' && require.specified('knockout')) {        // AMD. Register as an anonymous module.        define(['jquery', 'knockout'], factory);    } else {        // Browser globals        factory(root.jQuery, root.ko);    }})(this, function ($, ko) {    "use strict";// jshint ;_;    if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {        ko.bindingHandlers.multiselect = {            after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],            init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {                var $element = $(element);                var config = ko.toJS(valueAccessor());                $element.multiselect(config);                if (allBindings.has('options')) {                    var options = allBindings.get('options');                    if (ko.isObservable(options)) {                        ko.computed({                            read: function() {                                options();                                setTimeout(function() {                                    var ms = $element.data('multiselect');                                    if (ms)                                        ms.updateOriginalOptions();//Not sure how beneficial this is.                                    $element.multiselect('rebuild');                                }, 1);                            },                            disposeWhenNodeIsRemoved: element                        });                    }                }                //value and selectedOptions are two-way, so these will be triggered even by our own actions.                //It needs some way to tell if they are triggered because of us or because of outside change.                //It doesn't loop but it's a waste of processing.                if (allBindings.has('value')) {                    var value = allBindings.get('value');                    if (ko.isObservable(value)) {                        ko.computed({                            read: function() {                                value();                                setTimeout(function() {                                    $element.multiselect('refresh');                                }, 1);                            },                            disposeWhenNodeIsRemoved: element                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });                    }                }                //Switched from arrayChange subscription to general subscription using 'refresh'.                //Not sure performance is any better using 'select' and 'deselect'.                if (allBindings.has('selectedOptions')) {                    var selectedOptions = allBindings.get('selectedOptions');                    if (ko.isObservable(selectedOptions)) {                        ko.computed({                            read: function() {                                selectedOptions();                                setTimeout(function() {                                    $element.multiselect('refresh');                                }, 1);                            },                            disposeWhenNodeIsRemoved: element                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });                    }                }                var setEnabled = function (enable) {                    setTimeout(function () {                        if (enable)                            $element.multiselect('enable');                        else                            $element.multiselect('disable');                    });                };                if (allBindings.has('enable')) {                    var enable = allBindings.get('enable');                    if (ko.isObservable(enable)) {                        ko.computed({                            read: function () {                                setEnabled(enable());                            },                            disposeWhenNodeIsRemoved: element                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });                    } else {                        setEnabled(enable);                    }                }                if (allBindings.has('disable')) {                    var disable = allBindings.get('disable');                    if (ko.isObservable(disable)) {                        ko.computed({                            read: function () {                                setEnabled(!disable());                            },                            disposeWhenNodeIsRemoved: element                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });                    } else {                        setEnabled(!disable);                    }                }                ko.utils.domNodeDisposal.addDisposeCallback(element, function() {                    $element.multiselect('destroy');                });            },            update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {                var $element = $(element);                var config = ko.toJS(valueAccessor());                $element.multiselect('setOptions', config);                $element.multiselect('rebuild');            }        };    }    function forEach(array, callback) {        for (var index = 0; index < array.length; ++index) {            callback(array[index], index);        }    }    /**     * Constructor to create a new multiselect using the given select.     *     * @param {jQuery} select     * @param {Object} options     * @returns {Multiselect}     */    function Multiselect(select, options) {        this.$select = $(select);        this.options = this.mergeOptions($.extend({}, options, this.$select.data()));        // Placeholder via data attributes        if (this.$select.attr("data-placeholder")) {            this.options.nonSelectedText = this.$select.data("placeholder");        }        // Initialization.        // We have to clone to create a new reference.        this.originalOptions = this.$select.clone()[0].options;        this.query = '';        this.searchTimeout = null;        this.lastToggledInput = null;        this.options.multiple = this.$select.attr('multiple') === "multiple";        this.options.onChange = $.proxy(this.options.onChange, this);        this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);        this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);        this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);        this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);        this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);        this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);        this.options.onInitialized = $.proxy(this.options.onInitialized, this);        this.options.onFiltering = $.proxy(this.options.onFiltering, this);        // Build select all if enabled.        this.buildContainer();        this.buildButton();        this.buildDropdown();        this.buildReset();        this.buildSelectAll();        this.buildDropdownOptions();        this.buildFilter();        this.updateButtonText();        this.updateSelectAll(true);        if (this.options.enableClickableOptGroups && this.options.multiple) {            this.updateOptGroups();        }        this.options.wasDisabled = this.$select.prop('disabled');        if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {            this.disable();        }        this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container);        this.options.onInitialized(this.$select, this.$container);    }    Multiselect.prototype = {        defaults: {            /**             * Default text function will either print 'None selected' in case no             * option is selected or a list of the selected options up to a length             * of 3 selected options.             *             * @param {jQuery} options             * @param {jQuery} select             * @returns {String}             */            buttonText: function(options, select) {                if (this.disabledText.length > 0                        && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty)))  {                    return this.disabledText;                }                else if (options.length === 0) {                    return this.nonSelectedText;                }                else if (this.allSelectedText                        && options.length === $('option', $(select)).length                        && $('option', $(select)).length !== 1                        && this.multiple) {                    if (this.selectAllNumber) {                        return this.allSelectedText + ' (' + options.length + ')';                    }                    else {                        return this.allSelectedText;                    }                }                else if (this.numberDisplayed != 0 && options.length > this.numberDisplayed) {                    return options.length + ' ' + this.nSelectedText;                }                else {                    var selected = '';                    var delimiter = this.delimiterText;                    options.each(function() {                        var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();                        selected += label + delimiter;                    });                    return selected.substr(0, selected.length - this.delimiterText.length);                }            },            /**             * Updates the title of the button similar to the buttonText function.             *             * @param {jQuery} options             * @param {jQuery} select             * @returns {@exp;selected@call;substr}             */            buttonTitle: function(options, select) {                if (options.length === 0) {                    return this.nonSelectedText;                }                else {                    var selected = '';                    var delimiter = this.delimiterText;                    options.each(function () {                        var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();                        selected += label + delimiter;                    });                    return selected.substr(0, selected.length - this.delimiterText.length);                }            },            checkboxName: function(option) {                return false; // no checkbox name            },            /**             * Create a label.             *             * @param {jQuery} element             * @returns {String}             */            optionLabel: function(element){                return $(element).attr('label') || $(element).text();            },            /**             * Create a class.             *             * @param {jQuery} element             * @returns {String}             */            optionClass: function(element) {                return $(element).attr('class') || '';            },            /**             * Triggered on change of the multiselect.             *             * Not triggered when selecting/deselecting options manually.             *             * @param {jQuery} option             * @param {Boolean} checked             */            onChange : function(option, checked) {            },            /**             * Triggered when the dropdown is shown.             *             * @param {jQuery} event             */            onDropdownShow: function(event) {            },            /**             * Triggered when the dropdown is hidden.             *             * @param {jQuery} event             */            onDropdownHide: function(event) {            },            /**             * Triggered after the dropdown is shown.             *             * @param {jQuery} event             */            onDropdownShown: function(event) {            },            /**             * Triggered after the dropdown is hidden.             *             * @param {jQuery} event             */            onDropdownHidden: function(event) {            },            /**             * Triggered on select all.             */            onSelectAll: function() {            },            /**             * Triggered on deselect all.             */            onDeselectAll: function() {            },            /**             * Triggered after initializing.             *             * @param {jQuery} $select             * @param {jQuery} $container             */            onInitialized: function($select, $container) {            },            /**             * Triggered on filtering.             *             * @param {jQuery} $filter             */            onFiltering: function($filter) {            },            enableHTML: false,            buttonClass: 'btn btn-default',            inheritClass: false,            buttonWidth: 'auto',            buttonContainer: '<div class="btn-group" />',            dropRight: false,            dropUp: false,            selectedClass: 'active',            // Maximum height of the dropdown menu.            // If maximum height is exceeded a scrollbar will be displayed.            maxHeight: false,            includeSelectAllOption: false,            includeSelectAllIfMoreThan: 0,            selectAllText: ' Select all',            selectAllValue: 'multiselect-all',            selectAllName: false,            selectAllNumber: true,            selectAllJustVisible: true,            enableFiltering: false,            enableCaseInsensitiveFiltering: false,            enableFullValueFiltering: false,            enableClickableOptGroups: false,            enableCollapsibleOptGroups: false,            collapseOptGroupsByDefault: false,            filterPlaceholder: 'Search',            // possible options: 'text', 'value', 'both'            filterBehavior: 'text',            includeFilterClearBtn: true,            preventInputChangeEvent: false,            nonSelectedText: 'None selected',            nSelectedText: 'selected',            allSelectedText: 'All selected',            numberDisplayed: 3,            disableIfEmpty: false,            disabledText: '',            delimiterText: ', ',            includeResetOption: false,            includeResetDivider: false,            resetText: 'Reset',            templates: {                button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',                ul: '<ul class="multiselect-container dropdown-menu"></ul>',                filter: '<li class="multiselect-item multiselect-filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text" /></div></li>',                filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>',                li: '<li><a tabindex="0"><label></label></a></li>',                divider: '<li class="multiselect-item divider"></li>',                liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>',                resetButton: '<li class="multiselect-reset text-center"><div class="input-group"><a class="btn btn-default btn-block"></a></div></li>'            }        },        constructor: Multiselect,        /**         * Builds the container of the multiselect.         */        buildContainer: function() {            this.$container = $(this.options.buttonContainer);            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);        },        /**         * Builds the button of the multiselect.         */        buildButton: function() {            this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);            if (this.$select.attr('class') && this.options.inheritClass) {                this.$button.addClass(this.$select.attr('class'));            }            // Adopt active state.            if (this.$select.prop('disabled')) {                this.disable();            }            else {                this.enable();            }            // Manually add button width if set.            if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {                this.$button.css({                    'width' : '100%', //this.options.buttonWidth,                    'overflow' : 'hidden',                    'text-overflow' : 'ellipsis'                });                this.$container.css({                    'width': this.options.buttonWidth                });            }            // Keep the tab index from the select.            var tabindex = this.$select.attr('tabindex');            if (tabindex) {                this.$button.attr('tabindex', tabindex);            }            this.$container.prepend(this.$button);        },        /**         * Builds the ul representing the dropdown menu.         */        buildDropdown: function() {            // Build ul.            this.$ul = $(this.options.templates.ul);            if (this.options.dropRight) {                this.$ul.addClass('pull-right');            }            // Set max height of dropdown menu to activate auto scrollbar.            if (this.options.maxHeight) {                // TODO: Add a class for this option to move the css declarations.                this.$ul.css({                    'max-height': this.options.maxHeight + 'px',                    'overflow-y': 'auto',                    'overflow-x': 'hidden'                });            }            if (this.options.dropUp) {                var height = Math.min(this.options.maxHeight, $('option[data-role!="divider"]', this.$select).length*26 + $('option[data-role="divider"]', this.$select).length*19 + (this.options.includeSelectAllOption ? 26 : 0) + (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering ? 44 : 0));                var moveCalc = height + 34;                this.$ul.css({                    'max-height': height + 'px',                    'overflow-y': 'auto',                    'overflow-x': 'hidden',                    'margin-top': "-" + moveCalc + 'px'                });            }            this.$container.append(this.$ul);        },        /**         * Build the dropdown options and binds all necessary events.         *         * Uses createDivider and createOptionValue to create the necessary options.         */        buildDropdownOptions: function() {            this.$select.children().each($.proxy(function(index, element) {                var $element = $(element);                // Support optgroups and options without a group simultaneously.                var tag = $element.prop('tagName')                    .toLowerCase();                if ($element.prop('value') === this.options.selectAllValue) {                    return;                }                if (tag === 'optgroup') {                    this.createOptgroup(element);                }                else if (tag === 'option') {                    if ($element.data('role') === 'divider') {                        this.createDivider();                    }                    else {                        this.createOptionValue(element);                    }                }                // Other illegal tags will be ignored.            }, this));            // Bind the change event on the dropdown elements.            $(this.$ul).off('change', 'li:not(.multiselect-group) input[type="checkbox"], li:not(.multiselect-group) input[type="radio"]');            $(this.$ul).on('change', 'li:not(.multiselect-group) input[type="checkbox"], li:not(.multiselect-group) input[type="radio"]', $.proxy(function(event) {                var $target = $(event.target);                var checked = $target.prop('checked') || false;                var isSelectAllOption = $target.val() === this.options.selectAllValue;                // Apply or unapply the configured selected class.                if (this.options.selectedClass) {                    if (checked) {                        $target.closest('li')                            .addClass(this.options.selectedClass);                    }                    else {                        $target.closest('li')                            .removeClass(this.options.selectedClass);                    }                }                // Get the corresponding option.                var value = $target.val();                var $option = this.getOptionByValue(value);                var $optionsNotThis = $('option', this.$select).not($option);                var $checkboxesNotThis = $('input', this.$container).not($target);                if (isSelectAllOption) {                    if (checked) {                        this.selectAll(this.options.selectAllJustVisible, true);                    }                    else {                        this.deselectAll(this.options.selectAllJustVisible, true);                    }                }                else {                    if (checked) {                        $option.prop('selected', true);                        if (this.options.multiple) {                            // Simply select additional option.                            $option.prop('selected', true);                        }                        else {                            // Unselect all other options and corresponding checkboxes.                            if (this.options.selectedClass) {                                $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);                            }                            $($checkboxesNotThis).prop('checked', false);                            $optionsNotThis.prop('selected', false);                            // It's a single selection, so close.                            this.$button.click();                        }                        if (this.options.selectedClass === "active") {                            $optionsNotThis.closest("a").css("outline", "");                        }                    }                    else {                        // Unselect option.                        $option.prop('selected', false);                    }                    // To prevent select all from firing onChange: #575                    this.options.onChange($option, checked);                    // Do not update select all or optgroups on select all change!                    this.updateSelectAll();                    if (this.options.enableClickableOptGroups && this.options.multiple) {                        this.updateOptGroups();                    }                }                this.$select.change();                this.updateButtonText();                if(this.options.preventInputChangeEvent) {                    return false;                }            }, this));            $('li a', this.$ul).on('mousedown', function(e) {                if (e.shiftKey) {                    // Prevent selecting text by Shift+click                    return false;                }            });            $(this.$ul).on('touchstart click', 'li a', $.proxy(function(event) {                event.stopPropagation();                var $target = $(event.target);                if (event.shiftKey && this.options.multiple) {                    if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)                        event.preventDefault();                        $target = $target.find("input");                        $target.prop("checked", !$target.prop("checked"));                    }                    var checked = $target.prop('checked') || false;                    if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range                        var from = this.$ul.find("li:visible").index($target.parents("li"));                        var to = this.$ul.find("li:visible").index(this.lastToggledInput.parents("li"));                        if (from > to) { // Swap the indices                            var tmp = to;                            to = from;                            from = tmp;                        }                        // Make sure we grab all elements since slice excludes the last index                        ++to;                        // Change the checkboxes and underlying options                        var range = this.$ul.find("li").not(".multiselect-filter-hidden").slice(from, to).find("input");                        range.prop('checked', checked);                        if (this.options.selectedClass) {                            range.closest('li')                                .toggleClass(this.options.selectedClass, checked);                        }                        for (var i = 0, j = range.length; i < j; i++) {                            var $checkbox = $(range[i]);                            var $option = this.getOptionByValue($checkbox.val());                            $option.prop('selected', checked);                        }                    }                    // Trigger the select "change" event                    $target.trigger("change");                }                // Remembers last clicked option                if($target.is("input") && !$target.closest("li").is(".multiselect-item")){                    this.lastToggledInput = $target;                }                $target.blur();            }, this));            // Keyboard support.            this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) {                if ($('input[type="text"]', this.$container).is(':focus')) {                    return;                }                if (event.keyCode === 9 && this.$container.hasClass('open')) {                    this.$button.click();                }                else {                    var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");                    if (!$items.length) {                        return;                    }                    var index = $items.index($items.filter(':focus'));                                        // Navigation up.                    if (event.keyCode === 38 && index > 0) {                        index--;                    }                    // Navigate down.                    else if (event.keyCode === 40 && index < $items.length - 1) {                        index++;                    }                    else if (!~index) {                        index = 0;                    }                    var $current = $items.eq(index);                    $current.focus();                    if (event.keyCode === 32 || event.keyCode === 13) {                        var $checkbox = $current.find('input');                        $checkbox.prop("checked", !$checkbox.prop("checked"));                        $checkbox.change();                    }                    event.stopPropagation();                    event.preventDefault();                }            }, this));            if (this.options.enableClickableOptGroups && this.options.multiple) {                $("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) {                    event.stopPropagation();                    var $target = $(event.target);                    var checked = $target.prop('checked') || false;                    var $li = $(event.target).closest('li');                    var $group = $li.nextUntil("li.multiselect-group")                        .not('.multiselect-filter-hidden')                        .not('.disabled');                    var $inputs = $group.find("input");                    var values = [];                    var $options = [];                    if (this.options.selectedClass) {                        if (checked) {                            $li.addClass(this.options.selectedClass);                        }                        else {                            $li.removeClass(this.options.selectedClass);                        }                    }                    $.each($inputs, $.proxy(function(index, input) {                        var value = $(input).val();                        var $option = this.getOptionByValue(value);                        if (checked) {                            $(input).prop('checked', true);                            $(input).closest('li')                                .addClass(this.options.selectedClass);                            $option.prop('selected', true);                        }                        else {                            $(input).prop('checked', false);                            $(input).closest('li')                                .removeClass(this.options.selectedClass);                            $option.prop('selected', false);                        }                        $options.push(this.getOptionByValue(value));                    }, this))                    // Cannot use select or deselect here because it would call updateOptGroups again.                    this.options.onChange($options, checked);                    this.$select.change();                    this.updateButtonText();                    this.updateSelectAll();                }, this));            }            if (this.options.enableCollapsibleOptGroups && this.options.multiple) {                $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) {                    var $li = $(event.target).closest('li');                    var $inputs = $li.nextUntil("li.multiselect-group")                            .not('.multiselect-filter-hidden');                    var visible = true;                    $inputs.each(function() {                        visible = visible && !$(this).hasClass('multiselect-collapsible-hidden');                    });                    if (visible) {                        $inputs.hide()                            .addClass('multiselect-collapsible-hidden');                    }                    else {                        $inputs.show()                            .removeClass('multiselect-collapsible-hidden');                    }                }, this));                $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea');                $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px');                $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px');            }        },        /**         * Create an option using the given select option.         *         * @param {jQuery} element         */        createOptionValue: function(element) {            var $element = $(element);            if ($element.is(':selected')) {                $element.prop('selected', true);            }            // Support the label attribute on options.            var label = this.options.optionLabel(element);            var classes = this.options.optionClass(element);            var value = $element.val();            var inputType = this.options.multiple ? "checkbox" : "radio";            var $li = $(this.options.templates.li);            var $label = $('label', $li);            $label.addClass(inputType);            $label.attr("title", label);            $li.addClass(classes);            // Hide all children items when collapseOptGroupsByDefault is true            if (this.options.collapseOptGroupsByDefault && $(element).parent().prop("tagName").toLowerCase() === "optgroup") {                $li.addClass("multiselect-collapsible-hidden");                $li.hide();            }            if (this.options.enableHTML) {                $label.html(" " + label);            }            else {                $label.text(" " + label);            }            var $checkbox = $('<input/>').attr('type', inputType);            var name = this.options.checkboxName($element);            if (name) {                $checkbox.attr('name', name);            }            $label.prepend($checkbox);            var selected = $element.prop('selected') || false;            $checkbox.val(value);            if (value === this.options.selectAllValue) {                $li.addClass("multiselect-item multiselect-all");                $checkbox.parent().parent()                    .addClass('multiselect-all');            }            $label.attr('title', $element.attr('title'));            this.$ul.append($li);            if ($element.is(':disabled')) {                $checkbox.attr('disabled', 'disabled')                    .prop('disabled', true)                    .closest('a')                    .attr("tabindex", "-1")                    .closest('li')                    .addClass('disabled');            }            $checkbox.prop('checked', selected);            if (selected && this.options.selectedClass) {                $checkbox.closest('li')                    .addClass(this.options.selectedClass);            }        },        /**         * Creates a divider using the given select option.         *         * @param {jQuery} element         */        createDivider: function(element) {            var $divider = $(this.options.templates.divider);            this.$ul.append($divider);        },        /**         * Creates an optgroup.         *         * @param {jQuery} group         */        createOptgroup: function(group) {            var label = $(group).attr("label");            var value = $(group).attr("value");            var $li = $('<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><label><b></b></label></a></li>');            var classes = this.options.optionClass(group);            $li.addClass(classes);            if (this.options.enableHTML) {                $('label b', $li).html(" " + label);            }            else {                $('label b', $li).text(" " + label);            }            if (this.options.enableCollapsibleOptGroups && this.options.multiple) {                $('a', $li).append('<span class="caret-container"><b class="caret"></b></span>');            }            if (this.options.enableClickableOptGroups && this.options.multiple) {                $('a label', $li).prepend('<input type="checkbox" value="' + value + '"/>');            }            if ($(group).is(':disabled')) {                $li.addClass('disabled');            }            this.$ul.append($li);            $("option", group).each($.proxy(function($, group) {                this.createOptionValue(group);            }, this))        },        /**         * Build the reset.         *         */        buildReset: function() {            if (this.options.includeResetOption) {                // Check whether to add a divider after the reset.                if (this.options.includeResetDivider) {                    this.$ul.prepend($(this.options.templates.divider));                }                var $resetButton = $(this.options.templates.resetButton);                if (this.options.enableHTML) {                    $('a', $resetButton).html(this.options.resetText);                }                else {                    $('a', $resetButton).text(this.options.resetText);                }                $('a', $resetButton).click($.proxy(function(){                    this.clearSelection();                }, this));                this.$ul.prepend($resetButton);            }        },        /**         * Build the select all.         *         * Checks if a select all has already been created.         */        buildSelectAll: function() {            if (typeof this.options.selectAllValue === 'number') {                this.options.selectAllValue = this.options.selectAllValue.toString();            }            var alreadyHasSelectAll = this.hasSelectAll();            if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple                    && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {                // Check whether to add a divider after the select all.                if (this.options.includeSelectAllDivider) {                    this.$ul.prepend($(this.options.templates.divider));                }                var $li = $(this.options.templates.li);                $('label', $li).addClass("checkbox");                if (this.options.enableHTML) {                    $('label', $li).html(" " + this.options.selectAllText);                }                else {                    $('label', $li).text(" " + this.options.selectAllText);                }                if (this.options.selectAllName) {                    $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />');                }                else {                    $('label', $li).prepend('<input type="checkbox" />');                }                var $checkbox = $('input', $li);                $checkbox.val(this.options.selectAllValue);                $li.addClass("multiselect-item multiselect-all");                $checkbox.parent().parent()                    .addClass('multiselect-all');                this.$ul.prepend($li);                $checkbox.prop('checked', false);            }        },        /**         * Builds the filter.         */        buildFilter: function() {            // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.            if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {                var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);                if (this.$select.find('option').length >= enableFilterLength) {                    this.$filter = $(this.options.templates.filter);                    $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);                    // Adds optional filter clear button                    if(this.options.includeFilterClearBtn) {                        var clearBtn = $(this.options.templates.filterClearBtn);                        clearBtn.on('click', $.proxy(function(event){                            clearTimeout(this.searchTimeout);                            this.query = '';                            this.$filter.find('.multiselect-search').val('');                            $('li', this.$ul).show().removeClass('multiselect-filter-hidden');                            this.updateSelectAll();                            if (this.options.enableClickableOptGroups && this.options.multiple) {                                this.updateOptGroups();                            }                        }, this));                        this.$filter.find('.input-group').append(clearBtn);                    }                    this.$ul.prepend(this.$filter);                    this.$filter.val(this.query).on('click', function(event) {                        event.stopPropagation();                    }).on('input keydown', $.proxy(function(event) {                        // Cancel enter key default behaviour                        if (event.which === 13) {                          event.preventDefault();                      }                        // This is useful to catch "keydown" events after the browser has updated the control.                        clearTimeout(this.searchTimeout);                        this.searchTimeout = this.asyncFunction($.proxy(function() {                            if (this.query !== event.target.value) {                                this.query = event.target.value;                                var currentGroup, currentGroupVisible;                                $.each($('li', this.$ul), $.proxy(function(index, element) {                                    var value = $('input', element).length > 0 ? $('input', element).val() : "";                                    var text = $('label', element).text();                                    var filterCandidate = '';                                    if ((this.options.filterBehavior === 'text')) {                                        filterCandidate = text;                                    }                                    else if ((this.options.filterBehavior === 'value')) {                                        filterCandidate = value;                                    }                                    else if (this.options.filterBehavior === 'both') {                                        filterCandidate = text + '\n' + value;                                    }                                    if (value !== this.options.selectAllValue && text) {                                        // By default lets assume that element is not                                        // interesting for this search.                                        var showElement = false;                                        if (this.options.enableCaseInsensitiveFiltering) {                                            filterCandidate = filterCandidate.toLowerCase();                                            this.query = this.query.toLowerCase();                                        }                                        if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') {                                            var valueToMatch = filterCandidate.trim().substring(0, this.query.length);                                            if (this.query.indexOf(valueToMatch) > -1) {                                                showElement = true;                                            }                                        }                                        else if (filterCandidate.indexOf(this.query) > -1) {                                            showElement = true;                                        }                                        // Toggle current element (group or group item) according to showElement boolean.                                        if(!showElement){                                          $(element).css('display', 'none');                                          $(element).addClass('multiselect-filter-hidden');                                        }                                        if(showElement){                                          $(element).css('display', 'block');                                          $(element).removeClass('multiselect-filter-hidden');                                        }                                        // Differentiate groups and group items.                                        if ($(element).hasClass('multiselect-group')) {                                            // Remember group status.                                            currentGroup = element;                                            currentGroupVisible = showElement;                                        }                                        else {                                            // Show group name when at least one of its items is visible.                                            if (showElement) {                                                $(currentGroup).show()                                                    .removeClass('multiselect-filter-hidden');                                            }                                            // Show all group items when group name satisfies filter.                                            if (!showElement && currentGroupVisible) {                                                $(element).show()                                                    .removeClass('multiselect-filter-hidden');                                            }                                        }                                    }                                }, this));                            }                            this.updateSelectAll();                            if (this.options.enableClickableOptGroups && this.options.multiple) {                                this.updateOptGroups();                            }                            this.options.onFiltering(event.target);                        }, this), 300, this);                    }, this));                }            }        },        /**         * Unbinds the whole plugin.         */        destroy: function() {            this.$container.remove();            this.$select.show();            // reset original state            this.$select.prop('disabled', this.options.wasDisabled);            this.$select.data('multiselect', null);        },        /**         * Refreshs the multiselect based on the selected options of the select.         */        refresh: function () {            var inputs = {};            $('li input', this.$ul).each(function() {              inputs[$(this).val()] = $(this);            });            $('option', this.$select).each($.proxy(function (index, element) {                var $elem = $(element);                var $input = inputs[$(element).val()];                if ($elem.is(':selected')) {                    $input.prop('checked', true);                    if (this.options.selectedClass) {                        $input.closest('li')                            .addClass(this.options.selectedClass);                    }                }                else {                    $input.prop('checked', false);                    if (this.options.selectedClass) {                        $input.closest('li')                            .removeClass(this.options.selectedClass);                    }                }                if ($elem.is(":disabled")) {                    $input.attr('disabled', 'disabled')                        .prop('disabled', true)                        .closest('li')                        .addClass('disabled');                }                else {                    $input.prop('disabled', false)                        .closest('li')                        .removeClass('disabled');                }            }, this));            this.updateButtonText();            this.updateSelectAll();            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }        },        /**         * Select all options of the given values.         *         * If triggerOnChange is set to true, the on change event is triggered if         * and only if one value is passed.         *         * @param {Array} selectValues         * @param {Boolean} triggerOnChange         */        select: function(selectValues, triggerOnChange) {            if(!$.isArray(selectValues)) {                selectValues = [selectValues];            }            for (var i = 0; i < selectValues.length; i++) {                var value = selectValues[i];                if (value === null || value === undefined) {                    continue;                }                var $option = this.getOptionByValue(value);                var $checkbox = this.getInputByValue(value);                if($option === undefined || $checkbox === undefined) {                    continue;                }                if (!this.options.multiple) {                    this.deselectAll(false);                }                if (this.options.selectedClass) {                    $checkbox.closest('li')                        .addClass(this.options.selectedClass);                }                $checkbox.prop('checked', true);                $option.prop('selected', true);                if (triggerOnChange) {                    this.options.onChange($option, true);                }            }            this.updateButtonText();            this.updateSelectAll();            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }        },        /**         * Clears all selected items.         */        clearSelection: function () {            this.deselectAll(false);            this.updateButtonText();            this.updateSelectAll();            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }        },        /**         * Deselects all options of the given values.         *         * If triggerOnChange is set to true, the on change event is triggered, if         * and only if one value is passed.         *         * @param {Array} deselectValues         * @param {Boolean} triggerOnChange         */        deselect: function(deselectValues, triggerOnChange) {            if(!$.isArray(deselectValues)) {                deselectValues = [deselectValues];            }            for (var i = 0; i < deselectValues.length; i++) {                var value = deselectValues[i];                if (value === null || value === undefined) {                    continue;                }                var $option = this.getOptionByValue(value);                var $checkbox = this.getInputByValue(value);                if($option === undefined || $checkbox === undefined) {                    continue;                }                if (this.options.selectedClass) {                    $checkbox.closest('li')                        .removeClass(this.options.selectedClass);                }                $checkbox.prop('checked', false);                $option.prop('selected', false);                if (triggerOnChange) {                    this.options.onChange($option, false);                }            }            this.updateButtonText();            this.updateSelectAll();            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }        },        /**         * Selects all enabled & visible options.         *         * If justVisible is true or not specified, only visible options are selected.         *         * @param {Boolean} justVisible         * @param {Boolean} triggerOnSelectAll         */        selectAll: function (justVisible, triggerOnSelectAll) {            var justVisible = typeof justVisible === 'undefined' ? true : justVisible;            var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);            var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');            if(justVisible) {                $('input:enabled' , visibleLis).prop('checked', true);                visibleLis.addClass(this.options.selectedClass);                $('input:enabled' , visibleLis).each($.proxy(function(index, element) {                    var value = $(element).val();                    var option = this.getOptionByValue(value);                    $(option).prop('selected', true);                }, this));            }            else {                $('input:enabled' , allLis).prop('checked', true);                allLis.addClass(this.options.selectedClass);                $('input:enabled' , allLis).each($.proxy(function(index, element) {                    var value = $(element).val();                    var option = this.getOptionByValue(value);                    $(option).prop('selected', true);                }, this));            }            $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', true);            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }            if (triggerOnSelectAll) {                this.options.onSelectAll();            }        },        /**         * Deselects all options.         *         * If justVisible is true or not specified, only visible options are deselected.         *         * @param {Boolean} justVisible         */        deselectAll: function (justVisible, triggerOnDeselectAll) {            var justVisible = typeof justVisible === 'undefined' ? true : justVisible;            var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);            var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');            if(justVisible) {                $('input[type="checkbox"]:enabled' , visibleLis).prop('checked', false);                visibleLis.removeClass(this.options.selectedClass);                $('input[type="checkbox"]:enabled' , visibleLis).each($.proxy(function(index, element) {                    var value = $(element).val();                    var option = this.getOptionByValue(value);                    $(option).prop('selected', false);                }, this));            }            else {                $('input[type="checkbox"]:enabled' , allLis).prop('checked', false);                allLis.removeClass(this.options.selectedClass);                $('input[type="checkbox"]:enabled' , allLis).each($.proxy(function(index, element) {                    var value = $(element).val();                    var option = this.getOptionByValue(value);                    $(option).prop('selected', false);                }, this));            }            $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', false);            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }            if (triggerOnDeselectAll) {                this.options.onDeselectAll();            }        },        /**         * Rebuild the plugin.         *         * Rebuilds the dropdown, the filter and the select all option.         */        rebuild: function() {            this.$ul.html('');            // Important to distinguish between radios and checkboxes.            this.options.multiple = this.$select.attr('multiple') === "multiple";            this.buildSelectAll();            this.buildDropdownOptions();            this.buildFilter();            this.updateButtonText();            this.updateSelectAll(true);            if (this.options.enableClickableOptGroups && this.options.multiple) {                this.updateOptGroups();            }            if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {                this.disable();            }            else {                this.enable();            }            if (this.options.dropRight) {                this.$ul.addClass('pull-right');            }        },        /**         * The provided data will be used to build the dropdown.         */        dataprovider: function(dataprovider) {            var groupCounter = 0;            var $select = this.$select.empty();            $.each(dataprovider, function (index, option) {                var $tag;                if ($.isArray(option.children)) { // create optiongroup tag                    groupCounter++;                    $tag = $('<optgroup/>').attr({                        label: option.label || 'Group ' + groupCounter,                        disabled: !!option.disabled,                        value: option.value                    });                    forEach(option.children, function(subOption) { // add children option tags                        var attributes = {                            value: subOption.value,                            label: subOption.label || subOption.value,                            title: subOption.title,                            selected: !!subOption.selected,                            disabled: !!subOption.disabled                        };                        //Loop through attributes object and add key-value for each attribute                       for (var key in subOption.attributes) {                            attributes['data-' + key] = subOption.attributes[key];                       }                         //Append original attributes + new data attributes to option                        $tag.append($('<option/>').attr(attributes));                    });                }                else {                    var attributes = {                        'value': option.value,                        'label': option.label || option.value,                        'title': option.title,                        'class': option['class'],                        'selected': !!option['selected'],                        'disabled': !!option['disabled']                    };                    //Loop through attributes object and add key-value for each attribute                    for (var key in option.attributes) {                      attributes['data-' + key] = option.attributes[key];                    }                    //Append original attributes + new data attributes to option                    $tag = $('<option/>').attr(attributes);                    $tag.text(option.label || option.value);                }                $select.append($tag);            });            this.rebuild();        },        /**         * Enable the multiselect.         */        enable: function() {            this.$select.prop('disabled', false);            this.$button.prop('disabled', false)                .removeClass('disabled');        },        /**         * Disable the multiselect.         */        disable: function() {            this.$select.prop('disabled', true);            this.$button.prop('disabled', true)                .addClass('disabled');        },        /**         * Set the options.         *         * @param {Array} options         */        setOptions: function(options) {            this.options = this.mergeOptions(options);        },        /**         * Merges the given options with the default options.         *         * @param {Array} options         * @returns {Array}         */        mergeOptions: function(options) {            return $.extend(true, {}, this.defaults, this.options, options);        },        /**         * Checks whether a select all checkbox is present.         *         * @returns {Boolean}         */        hasSelectAll: function() {            return $('li.multiselect-all', this.$ul).length > 0;        },        /**         * Update opt groups.         */        updateOptGroups: function() {            var $groups = $('li.multiselect-group', this.$ul)            var selectedClass = this.options.selectedClass;            $groups.each(function() {                var $options = $(this).nextUntil('li.multiselect-group')                    .not('.multiselect-filter-hidden')                    .not('.disabled');                var checked = true;                $options.each(function() {                    var $input = $('input', this);                    if (!$input.prop('checked')) {                        checked = false;                    }                });                if (selectedClass) {                    if (checked) {                        $(this).addClass(selectedClass);                    }                    else {                        $(this).removeClass(selectedClass);                    }                }                $('input', this).prop('checked', checked);            });        },        /**         * Updates the select all checkbox based on the currently displayed and selected checkboxes.         */        updateSelectAll: function(notTriggerOnSelectAll) {            if (this.hasSelectAll()) {                var allBoxes = $("li:not(.multiselect-item):not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$ul);                var allBoxesLength = allBoxes.length;                var checkedBoxesLength = allBoxes.filter(":checked").length;                var selectAllLi  = $("li.multiselect-all", this.$ul);                var selectAllInput = selectAllLi.find("input");                if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {                    selectAllInput.prop("checked", true);                    selectAllLi.addClass(this.options.selectedClass);                }                else {                    selectAllInput.prop("checked", false);                    selectAllLi.removeClass(this.options.selectedClass);                }            }        },        /**         * Update the button text and its title based on the currently selected options.         */        updateButtonText: function() {            var options = this.getSelected();            // First update the displayed button text.            if (this.options.enableHTML) {                $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));            }            else {                $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));            }            // Now update the title attribute of the button.            $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));        },        /**         * Get all selected options.         *         * @returns {jQUery}         */        getSelected: function() {            return $('option', this.$select).filter(":selected");        },        /**         * Gets a select option by its value.         *         * @param {String} value         * @returns {jQuery}         */        getOptionByValue: function (value) {            var options = $('option', this.$select);            var valueToCompare = value.toString();            for (var i = 0; i < options.length; i = i + 1) {                var option = options[i];                if (option.value === valueToCompare) {                    return $(option);                }            }        },        /**         * Get the input (radio/checkbox) by its value.         *         * @param {String} value         * @returns {jQuery}         */        getInputByValue: function (value) {            var checkboxes = $('li input:not(.multiselect-search)', this.$ul);            var valueToCompare = value.toString();            for (var i = 0; i < checkboxes.length; i = i + 1) {                var checkbox = checkboxes[i];                if (checkbox.value === valueToCompare) {                    return $(checkbox);                }            }        },        /**         * Used for knockout integration.         */        updateOriginalOptions: function() {            this.originalOptions = this.$select.clone()[0].options;        },        asyncFunction: function(callback, timeout, self) {            var args = Array.prototype.slice.call(arguments, 3);            return setTimeout(function() {                callback.apply(self || window, args);            }, timeout);        },        setAllSelectedText: function(allSelectedText) {            this.options.allSelectedText = allSelectedText;            this.updateButtonText();        }    };    $.fn.multiselect = function(option, parameter, extraOptions) {        return this.each(function() {            var data = $(this).data('multiselect');            var options = typeof option === 'object' && option;            // Initialize the multiselect.            if (!data) {                data = new Multiselect(this, options);                $(this).data('multiselect', data);            }            // Call multiselect method.            if (typeof option === 'string') {                data[option](parameter, extraOptions);                if (option === 'destroy') {                    $(this).data('multiselect', false);                }            }        });    };    $.fn.multiselect.Constructor = Multiselect;    $(function() {        $("select[data-role=multiselect]").multiselect();    });});
 |