{"version":3,"names":[],"mappings":"","sources":["bootstrap-multiselect.js"],"sourcesContent":["/**\r\n * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/)\r\n *\r\n * Apache License, Version 2.0:\r\n * Copyright (c) 2012 - 2018 David Stutz\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\r\n * use this file except in compliance with the License. You may obtain a\r\n * copy of the License at http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r\n * License for the specific language governing permissions and limitations\r\n * under the License.\r\n *\r\n * BSD 3-Clause License:\r\n * Copyright (c) 2012 - 2018 David Stutz\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n * - Redistributions of source code must retain the above copyright notice,\r\n * this list of conditions and the following disclaimer.\r\n * - Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n * - Neither the name of David Stutz nor the names of its contributors may be\r\n * used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\r\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\r\n * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r\n * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r\n * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n(function (root, factory) {\r\n // check to see if 'knockout' AMD module is specified if using requirejs\r\n if (typeof define === 'function' && define.amd &&\r\n typeof require === 'function' && typeof require.specified === 'function' && require.specified('knockout')) {\r\n\r\n // AMD. Register as an anonymous module.\r\n define(['jquery', 'knockout'], factory);\r\n } else {\r\n // Browser globals\r\n factory(root.jQuery, root.ko);\r\n }\r\n})(this, function ($, ko) {\r\n \"use strict\";// jshint ;_;\r\n\r\n if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {\r\n ko.bindingHandlers.multiselect = {\r\n after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],\r\n\r\n init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {\r\n var $element = $(element);\r\n var config = ko.toJS(valueAccessor());\r\n\r\n $element.multiselect(config);\r\n\r\n if (allBindings.has('options')) {\r\n var options = allBindings.get('options');\r\n if (ko.isObservable(options)) {\r\n ko.computed({\r\n read: function() {\r\n options();\r\n setTimeout(function() {\r\n var ms = $element.data('multiselect');\r\n if (ms)\r\n ms.updateOriginalOptions();//Not sure how beneficial this is.\r\n $element.multiselect('rebuild');\r\n }, 1);\r\n },\r\n disposeWhenNodeIsRemoved: element\r\n });\r\n }\r\n }\r\n\r\n //value and selectedOptions are two-way, so these will be triggered even by our own actions.\r\n //It needs some way to tell if they are triggered because of us or because of outside change.\r\n //It doesn't loop but it's a waste of processing.\r\n if (allBindings.has('value')) {\r\n var value = allBindings.get('value');\r\n if (ko.isObservable(value)) {\r\n ko.computed({\r\n read: function() {\r\n value();\r\n setTimeout(function() {\r\n $element.multiselect('refresh');\r\n }, 1);\r\n },\r\n disposeWhenNodeIsRemoved: element\r\n }).extend({ rateLimit: 100, notifyWhenChangesStop: true });\r\n }\r\n }\r\n\r\n //Switched from arrayChange subscription to general subscription using 'refresh'.\r\n //Not sure performance is any better using 'select' and 'deselect'.\r\n if (allBindings.has('selectedOptions')) {\r\n var selectedOptions = allBindings.get('selectedOptions');\r\n if (ko.isObservable(selectedOptions)) {\r\n ko.computed({\r\n read: function() {\r\n selectedOptions();\r\n setTimeout(function() {\r\n $element.multiselect('refresh');\r\n }, 1);\r\n },\r\n disposeWhenNodeIsRemoved: element\r\n }).extend({ rateLimit: 100, notifyWhenChangesStop: true });\r\n }\r\n }\r\n\r\n var setEnabled = function (enable) {\r\n setTimeout(function () {\r\n if (enable)\r\n $element.multiselect('enable');\r\n else\r\n $element.multiselect('disable');\r\n });\r\n };\r\n\r\n if (allBindings.has('enable')) {\r\n var enable = allBindings.get('enable');\r\n if (ko.isObservable(enable)) {\r\n ko.computed({\r\n read: function () {\r\n setEnabled(enable());\r\n },\r\n disposeWhenNodeIsRemoved: element\r\n }).extend({ rateLimit: 100, notifyWhenChangesStop: true });\r\n } else {\r\n setEnabled(enable);\r\n }\r\n }\r\n\r\n if (allBindings.has('disable')) {\r\n var disable = allBindings.get('disable');\r\n if (ko.isObservable(disable)) {\r\n ko.computed({\r\n read: function () {\r\n setEnabled(!disable());\r\n },\r\n disposeWhenNodeIsRemoved: element\r\n }).extend({ rateLimit: 100, notifyWhenChangesStop: true });\r\n } else {\r\n setEnabled(!disable);\r\n }\r\n }\r\n\r\n ko.utils.domNodeDisposal.addDisposeCallback(element, function() {\r\n $element.multiselect('destroy');\r\n });\r\n },\r\n\r\n update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {\r\n var $element = $(element);\r\n var config = ko.toJS(valueAccessor());\r\n\r\n $element.multiselect('setOptions', config);\r\n $element.multiselect('rebuild');\r\n }\r\n };\r\n }\r\n\r\n function forEach(array, callback) {\r\n for (var index = 0; index < array.length; ++index) {\r\n callback(array[index], index);\r\n }\r\n }\r\n\r\n /**\r\n * Constructor to create a new multiselect using the given select.\r\n *\r\n * @param {jQuery} select\r\n * @param {Object} options\r\n * @returns {Multiselect}\r\n */\r\n function Multiselect(select, options) {\r\n\r\n this.$select = $(select);\r\n this.options = this.mergeOptions($.extend({}, options, this.$select.data()));\r\n\r\n // Placeholder via data attributes\r\n if (this.$select.attr(\"data-placeholder\")) {\r\n this.options.nonSelectedText = this.$select.data(\"placeholder\");\r\n }\r\n\r\n // Initialization.\r\n // We have to clone to create a new reference.\r\n this.originalOptions = this.$select.clone()[0].options;\r\n this.query = '';\r\n this.searchTimeout = null;\r\n this.lastToggledInput = null;\r\n\r\n this.options.multiple = this.$select.attr('multiple') === \"multiple\";\r\n this.options.onChange = $.proxy(this.options.onChange, this);\r\n this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);\r\n this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);\r\n this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);\r\n this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);\r\n this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);\r\n this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);\r\n this.options.onInitialized = $.proxy(this.options.onInitialized, this);\r\n this.options.onFiltering = $.proxy(this.options.onFiltering, this);\r\n\r\n // Build select all if enabled.\r\n this.buildContainer();\r\n this.buildButton();\r\n this.buildDropdown();\r\n this.buildReset();\r\n this.buildSelectAll();\r\n this.buildDropdownOptions();\r\n this.buildFilter();\r\n\r\n this.updateButtonText();\r\n this.updateSelectAll(true);\r\n\r\n if (this.options.enableClickableOptGroups && this.options.multiple) {\r\n this.updateOptGroups();\r\n }\r\n\r\n this.options.wasDisabled = this.$select.prop('disabled');\r\n if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {\r\n this.disable();\r\n }\r\n\r\n this.$select.wrap('').after(this.$container);\r\n this.options.onInitialized(this.$select, this.$container);\r\n }\r\n\r\n Multiselect.prototype = {\r\n\r\n defaults: {\r\n /**\r\n * Default text function will either print 'None selected' in case no\r\n * option is selected or a list of the selected options up to a length\r\n * of 3 selected options.\r\n *\r\n * @param {jQuery} options\r\n * @param {jQuery} select\r\n * @returns {String}\r\n */\r\n buttonText: function(options, select) {\r\n if (this.disabledText.length > 0\r\n && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) {\r\n\r\n return this.disabledText;\r\n }\r\n else if (options.length === 0) {\r\n return this.nonSelectedText;\r\n }\r\n else if (this.allSelectedText\r\n && options.length === $('option', $(select)).length\r\n && $('option', $(select)).length !== 1\r\n && this.multiple) {\r\n\r\n if (this.selectAllNumber) {\r\n return this.allSelectedText + ' (' + options.length + ')';\r\n }\r\n else {\r\n return this.allSelectedText;\r\n }\r\n }\r\n else if (this.numberDisplayed != 0 && options.length > this.numberDisplayed) {\r\n return options.length + ' ' + this.nSelectedText;\r\n }\r\n else {\r\n var selected = '';\r\n var delimiter = this.delimiterText;\r\n\r\n options.each(function() {\r\n var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();\r\n selected += label + delimiter;\r\n });\r\n\r\n return selected.substr(0, selected.length - this.delimiterText.length);\r\n }\r\n },\r\n /**\r\n * Updates the title of the button similar to the buttonText function.\r\n *\r\n * @param {jQuery} options\r\n * @param {jQuery} select\r\n * @returns {@exp;selected@call;substr}\r\n */\r\n buttonTitle: function(options, select) {\r\n if (options.length === 0) {\r\n return this.nonSelectedText;\r\n }\r\n else {\r\n var selected = '';\r\n var delimiter = this.delimiterText;\r\n\r\n options.each(function () {\r\n var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();\r\n selected += label + delimiter;\r\n });\r\n return selected.substr(0, selected.length - this.delimiterText.length);\r\n }\r\n },\r\n checkboxName: function(option) {\r\n return false; // no checkbox name\r\n },\r\n /**\r\n * Create a label.\r\n *\r\n * @param {jQuery} element\r\n * @returns {String}\r\n */\r\n optionLabel: function(element){\r\n return $(element).attr('label') || $(element).text();\r\n },\r\n /**\r\n * Create a class.\r\n *\r\n * @param {jQuery} element\r\n * @returns {String}\r\n */\r\n optionClass: function(element) {\r\n return $(element).attr('class') || '';\r\n },\r\n /**\r\n * Triggered on change of the multiselect.\r\n *\r\n * Not triggered when selecting/deselecting options manually.\r\n *\r\n * @param {jQuery} option\r\n * @param {Boolean} checked\r\n */\r\n onChange : function(option, checked) {\r\n\r\n },\r\n /**\r\n * Triggered when the dropdown is shown.\r\n *\r\n * @param {jQuery} event\r\n */\r\n onDropdownShow: function(event) {\r\n\r\n },\r\n /**\r\n * Triggered when the dropdown is hidden.\r\n *\r\n * @param {jQuery} event\r\n */\r\n onDropdownHide: function(event) {\r\n\r\n },\r\n /**\r\n * Triggered after the dropdown is shown.\r\n *\r\n * @param {jQuery} event\r\n */\r\n onDropdownShown: function(event) {\r\n\r\n },\r\n /**\r\n * Triggered after the dropdown is hidden.\r\n *\r\n * @param {jQuery} event\r\n */\r\n onDropdownHidden: function(event) {\r\n\r\n },\r\n /**\r\n * Triggered on select all.\r\n */\r\n onSelectAll: function() {\r\n\r\n },\r\n /**\r\n * Triggered on deselect all.\r\n */\r\n onDeselectAll: function() {\r\n\r\n },\r\n /**\r\n * Triggered after initializing.\r\n *\r\n * @param {jQuery} $select\r\n * @param {jQuery} $container\r\n */\r\n onInitialized: function($select, $container) {\r\n\r\n },\r\n /**\r\n * Triggered on filtering.\r\n *\r\n * @param {jQuery} $filter\r\n */\r\n onFiltering: function($filter) {\r\n\r\n },\r\n enableHTML: false,\r\n buttonClass: 'btn form-control',\r\n inheritClass: false,\r\n buttonWidth: 'auto',\r\n buttonContainer: '
',\r\n dropRight: false,\r\n dropUp: false,\r\n selectedClass: 'active',\r\n // Maximum height of the dropdown menu.\r\n // If maximum height is exceeded a scrollbar will be displayed.\r\n maxHeight: false,\r\n includeSelectAllOption: false,\r\n includeSelectAllIfMoreThan: 0,\r\n selectAllText: ' Select all',\r\n selectAllValue: 'multiselect-all',\r\n selectAllName: false,\r\n selectAllNumber: true,\r\n selectAllJustVisible: true,\r\n enableFiltering: false,\r\n enableCaseInsensitiveFiltering: false,\r\n enableFullValueFiltering: false,\r\n enableClickableOptGroups: false,\r\n enableCollapsibleOptGroups: false,\r\n collapseOptGroupsByDefault: false,\r\n filterPlaceholder: 'Search',\r\n // possible options: 'text', 'value', 'both'\r\n filterBehavior: 'text',\r\n includeFilterClearBtn: true,\r\n preventInputChangeEvent: false,\r\n nonSelectedText: '請選擇',\r\n nSelectedText: '個選擇',\r\n allSelectedText: '已選擇全部',\r\n numberDisplayed: 3,\r\n disableIfEmpty: false,\r\n disabledText: '',\r\n delimiterText: ', ',\r\n includeResetOption: false,\r\n includeResetDivider: false,\r\n resetText: 'Reset',\r\n templates: {\r\n button: '',\r\n ul: '