diff --git a/groups-clients.lp b/groups-clients.lp index 0c737a7c4d..81362bc645 100644 --- a/groups-clients.lp +++ b/groups-clients.lp @@ -105,7 +105,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/groups-domains.lp b/groups-domains.lp index b76ca0c6d0..376798b8fe 100644 --- a/groups-domains.lp +++ b/groups-domains.lp @@ -174,7 +174,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/groups-lists.lp b/groups-lists.lp index 6a3e17c060..e1ff665303 100644 --- a/groups-lists.lp +++ b/groups-lists.lp @@ -132,7 +132,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/groups.lp b/groups.lp index 21257cdcc0..e0f898797c 100644 --- a/groups.lp +++ b/groups.lp @@ -89,7 +89,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/package-lock.json b/package-lock.json index e8f8e764db..208b411266 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "admin-lte": "4.1.0", "animate.css": "4.1.1", "bootstrap": "5.3.8", + "bootstrap-multiselect": "2.0.0", "bootstrap-notify": "3.1.3", "bootstrap5-toggle": "5.4.1", "bstreeview": "1.2.0", @@ -35,8 +36,7 @@ "nprogress": "0.2.0", "qrious": "4.0.2", "select2": "4.1.0", - "select2-bootstrap-5-theme": "1.3.0", - "tom-select": "2.6.1" + "select2-bootstrap-5-theme": "1.3.0" }, "devDependencies": { "autoprefixer": "^10.5.0", @@ -615,21 +615,6 @@ "node": ">= 8" } }, - "node_modules/@orchidjs/sifter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@orchidjs/sifter/-/sifter-1.1.0.tgz", - "integrity": "sha512-mYwHCfr736cIWWdhhSZvDbf90AKt2xyrJspKFC3qyIJG1LtrJeJunYEqCGG4Aq2ijENbc4WkOjszcvNaIAS/pQ==", - "license": "Apache-2.0", - "dependencies": { - "@orchidjs/unicode-variants": "^1.1.2" - } - }, - "node_modules/@orchidjs/unicode-variants": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@orchidjs/unicode-variants/-/unicode-variants-1.1.2.tgz", - "integrity": "sha512-5DobW1CHgnBROOEpFlEXytED5OosEWESFvg/VYmH0143oXcijYTprRYJTs+55HzGM4IqxiLFSuqEzu9mPNwVsA==", - "license": "Apache-2.0" - }, "node_modules/@package-json/types": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/@package-json/types/-/types-0.0.12.tgz", @@ -1692,6 +1677,16 @@ "@popperjs/core": "^2.11.8" } }, + "node_modules/bootstrap-multiselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bootstrap-multiselect/-/bootstrap-multiselect-2.0.0.tgz", + "integrity": "sha512-m8dTwF+mLlpt8PtXfAXyERJLOGNuNrVuU9aQi2WMfwfwSzhgN+LbTaRuTk8Y15NZiMzy2m/FPfhKKgOOJxk2WQ==", + "license": "Apache License, Version 2.0 OR BSD 3-Clause License", + "dependencies": { + "bootstrap": "~5.3.x", + "jquery": ">= 2.2.4" + } + }, "node_modules/bootstrap-notify": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/bootstrap-notify/-/bootstrap-notify-3.1.3.tgz", @@ -6212,23 +6207,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tom-select": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tom-select/-/tom-select-2.6.1.tgz", - "integrity": "sha512-d/1kngVOQTGcI/2pVDfDLYjtjUgSSd3fSgkYUpi0y+yRtQQu2kzljj3aUdqMfqc45cjPvDEpfDt/hSX4awDFTg==", - "license": "Apache-2.0", - "dependencies": { - "@orchidjs/sifter": "^1.1.0", - "@orchidjs/unicode-variants": "^1.1.2" - }, - "engines": { - "node": "*" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tom-select" - } - }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", diff --git a/package.json b/package.json index de383d1c37..5d26190df7 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "bootstrap": "5.3.8", "bootstrap-notify": "3.1.3", "bootstrap5-toggle": "5.4.1", + "bootstrap-multiselect": "2.0.0", "bstreeview": "1.2.0", "chart.js": "4.5.1", "chartjs-adapter-moment": "1.0.1", @@ -51,8 +52,7 @@ "nprogress": "0.2.0", "qrious": "4.0.2", "select2": "4.1.0", - "select2-bootstrap-5-theme": "1.3.0", - "tom-select": "2.6.1" + "select2-bootstrap-5-theme": "1.3.0" }, "devDependencies": { "autoprefixer": "^10.5.0", diff --git a/queries.lp b/queries.lp index 954e1c16f7..6f295bb93a 100644 --- a/queries.lp +++ b/queries.lp @@ -179,7 +179,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/scripts/js/groups-clients.js b/scripts/js/groups-clients.js index 4918ab2d65..fbc0eed0c1 100644 --- a/scripts/js/groups-clients.js +++ b/scripts/js/groups-clients.js @@ -189,8 +189,8 @@ function initTable() { // Select assigned groups selectEl.val(data.groups); - // Initialize Tom Select - const ts = utils.createGroupSelect(selectEl, { + // Initialize group multi-select + const ms = utils.createGroupSelect(selectEl, { onChange() { // enable Apply button if ($(applyBtn).prop("disabled")) { @@ -198,6 +198,8 @@ function initTable() { .addClass("btn-success") .prop("disabled", false) .on("click", () => { + $(applyBtn).removeClass("btn-success").prop("disabled", true).off("click"); + ms.close(); editClient.call(selectEl); }); } @@ -208,12 +210,12 @@ function initTable() { return; } - ts.setValue(data.groups); + ms.setValue(data.groups); $(applyBtn).removeClass("btn-success").prop("disabled", true).off("click"); }, }); - $(ts.dropdown) - .find(".ts-actions-box") + $(ms.dropdown) + .find(".multiselect-actions-box") .append( '' + - '' + - ""; - actionsBox.querySelector(".select-all").addEventListener("click", () => { - ts.setValue(allValues); + const multiselect = select.data("multiselect"); + const container = multiselect ? multiselect.$container : $(); + const button = multiselect ? multiselect.$button : $(); + const dropdown = multiselect ? multiselect.$popupContainer : $(); + const dropdownParent = dropdown.parent(); + const updateDropdownPosition = () => { + if (button.length === 0 || dropdown.length === 0) { + return; + } + + const rect = button[0].getBoundingClientRect(); + dropdown[0].style.setProperty("--multiselect-trigger-left", `${rect.left}px`); + dropdown[0].style.setProperty("--multiselect-trigger-bottom", `${rect.bottom}px`); + dropdown[0].style.setProperty("--multiselect-trigger-width", `${rect.width}px`); + }; + + const cleanupDropdown = () => { + $(globalThis).off("resize", updateDropdownPosition).off("scroll", updateDropdownPosition); + + if (dropdown.length === 0 || dropdownParent.length === 0) { + return; + } + + dropdown.removeClass("multiselect-floating-menu show"); + dropdown[0].style.removeProperty("--multiselect-trigger-left"); + dropdown[0].style.removeProperty("--multiselect-trigger-bottom"); + dropdown[0].style.removeProperty("--multiselect-trigger-width"); + dropdown.appendTo(dropdownParent); + }; + + container + .on("shown.bs.dropdown.multiselectPortal", () => { + if (dropdown.length === 0 || dropdownParent.length === 0) { + return; + } + + dropdown.detach().appendTo(document.body); + dropdown.addClass("multiselect-floating-menu"); + updateDropdownPosition(); + $(globalThis).on("resize", updateDropdownPosition).on("scroll", updateDropdownPosition); + }) + .on("hidden.bs.dropdown.multiselectPortal", () => { + cleanupDropdown(); + }); + + const actionsItem = $( + '
' + + '
' + + '
' + + '' + + '' + + "
" + + "
" + + "
" + ); + + actionsItem.find(".select-all").on("click", event => { + event.preventDefault(); + select.multiselect("select", allValues, true); }); - actionsBox.querySelector(".select-none").addEventListener("click", () => { - ts.clear(); + + actionsItem.find(".select-none").on("click", event => { + event.preventDefault(); + const selectedValues = select + .find("option:selected") + .map((_, option) => option.value) + .get(); + select.multiselect("deselect", selectedValues, true); }); - ts.dropdown.prepend(actionsBox); - return ts; + dropdown.prepend(actionsItem); + + return { + setValue(values) { + const selectedValues = select + .find("option:selected") + .map((_, option) => option.value) + .get(); + + if (selectedValues.length > 0) { + select.multiselect("deselect", selectedValues); + } + + if (Array.isArray(values) && values.length > 0) { + select.multiselect("select", values); + } + + select.multiselect("updateButtonText"); + }, + clear() { + const selectedValues = select + .find("option:selected") + .map((_, option) => option.value) + .get(); + + if (selectedValues.length > 0) { + select.multiselect("deselect", selectedValues); + } + + select.multiselect("updateButtonText"); + }, + close() { + button.removeClass("show").attr("aria-expanded", "false"); + container.removeClass("show"); + cleanupDropdown(); + }, + dropdown, + }; } const backupStorage = {}; diff --git a/scripts/lua/header.lp b/scripts/lua/header.lp index d2824d2f12..e0f585b01c 100644 --- a/scripts/lua/header.lp +++ b/scripts/lua/header.lp @@ -121,7 +121,7 @@ end - + diff --git a/style/pi-hole.css b/style/pi-hole.css index aced076303..ec877a36a3 100644 --- a/style/pi-hole.css +++ b/style/pi-hole.css @@ -555,9 +555,7 @@ tfoot.add-new-item > tr > th { --bs-form-select-bg-img: url("../../style/icons/form-select-arrow-dark.svg"); } -/* Tom Select "Select all / Select none" actions, injected above the - options list to replace bootstrap-select's actionsBox feature */ -.ts-actions-box { +.multiselect-actions-box { display: flex; flex-wrap: wrap; gap: 0.25em; @@ -565,16 +563,41 @@ tfoot.add-new-item > tr > th { border-bottom: 1px solid var(--bs-border-color); } -.ts-actions-box .btn { +.multiselect-actions-box .btn { flex: 1 0 auto; } -.ts-actions-box .btn-group { +.multiselect-actions-box .btn-group { display: flex; gap: 2px; width: 100%; } +.multiselect-floating-menu { + position: fixed; + inset: auto auto auto auto; + top: var(--multiselect-trigger-bottom); + left: var(--multiselect-trigger-left); + min-width: var(--multiselect-trigger-width); + max-width: calc(100vw - var(--multiselect-trigger-left) - 16px); + z-index: 1055; +} + +.multiselect-container .multiselect-option.dropdown-item.active { + color: var(--bs-dropdown-link-active-color); + background-color: var(--bs-dropdown-link-active-bg); +} +.multiselect-container .multiselect-option.dropdown-item.active input.form-check-input { + filter: saturate(0) invert(1) brightness(2); +} + +.multiselect-container .multiselect-option.dropdown-item:active, +.multiselect-container .multiselect-option.dropdown-item:focus, +.multiselect-container .multiselect-option.dropdown-item:hover { + color: var(--bs-dropdown-link-hover-color) !important; + background-color: var(--bs-dropdown-link-hover-bg) !important; +} + .sidebar-menu .nav-link p { width: 100%; } @@ -1764,36 +1787,3 @@ td.dnssec i { min-width: 3.5rem; text-align: center; } - -/* Tom Select general styles */ -.ts-control, -.ts-control input, -.ts-dropdown { - font-size: 12px; -} - -/* Tom Select - Dark theme colors */ -/* Dropdown menu background and border alignment */ -[data-bs-theme="dark"] .ts-dropdown { - color: var(--bs-dropdown-link-color); -} - -/* Dropdown individual option items */ -[data-bs-theme="dark"] .ts-dropdown .option { - color: var(--bs-dropdown-link-color); -} - -/* Selected multi-select pills (Tags) */ -[data-bs-theme="dark"] .ts-wrapper.multi .ts-control > div { - background-color: var(--bs-tertiary-bg); - color: var(--bs-body-color); - border: 1px solid var(--bs-border-color); -} - -/* Remove button X inside multi-select pills */ -[data-bs-theme="dark"] .ts-wrapper.multi .ts-control > div .remove { - border-left-color: var(--bs-border-color); -} -[data-bs-theme="dark"] .ts-wrapper.multi .ts-control > div .remove:hover { - background: rgba(255, 255, 255, 0.1); -} diff --git a/vendor/bootstrap-multiselect/bootstrap-multiselect.min.css b/vendor/bootstrap-multiselect/bootstrap-multiselect.min.css new file mode 100644 index 0000000000..5159427ef2 --- /dev/null +++ b/vendor/bootstrap-multiselect/bootstrap-multiselect.min.css @@ -0,0 +1,44 @@ +/** + * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/) + * + * Apache License, Version 2.0: + * Copyright (c) 2012 - 2022 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 - 2022 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. + */ +span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect.dropdown-toggle:after{display:none}.multiselect{overflow:hidden;text-overflow:ellipsis}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container .multiselect-filter>.fa-search{z-index:1;padding-left:.75rem}.multiselect-container .multiselect-filter>input.multiselect-search{border:none;border-bottom:1px solid #d3d3d3;padding-left:2rem;margin-left:-1.625rem;border-bottom-right-radius:0;border-bottom-left-radius:0}.multiselect-container .multiselect-filter>input.multiselect-search:focus{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.multiselect-container .multiselect-filter>.multiselect-moz-clear-filter{margin-left:-1.5rem;display:none}.multiselect-container .multiselect-option.multiselect-group-option-indented-full{padding-left:2.6rem}.multiselect-container .multiselect-option.multiselect-group-option-indented{padding-left:1.8rem}.multiselect-container .multiselect-group{cursor:pointer}.multiselect-container .multiselect-group.closed .dropdown-toggle::after{transform:rotate(-90deg)}.multiselect-container .multiselect-group .caret-container~.form-check{margin-left:.5rem}.multiselect-container .multiselect-all,.multiselect-container .multiselect-group,.multiselect-container .multiselect-option{padding:.25rem .25rem .25rem .75rem}.multiselect-container .multiselect-all.dropdown-item,.multiselect-container .multiselect-all.dropdown-toggle,.multiselect-container .multiselect-group.dropdown-item,.multiselect-container .multiselect-group.dropdown-toggle,.multiselect-container .multiselect-option.dropdown-item,.multiselect-container .multiselect-option.dropdown-toggle{cursor:pointer}.multiselect-container .multiselect-all .form-check-label,.multiselect-container .multiselect-group .form-check-label,.multiselect-container .multiselect-option .form-check-label{cursor:pointer}.multiselect-container .multiselect-all.active:not(.multiselect-active-item-fallback),.multiselect-container .multiselect-all:not(.multiselect-active-item-fallback):active,.multiselect-container .multiselect-group.active:not(.multiselect-active-item-fallback),.multiselect-container .multiselect-group:not(.multiselect-active-item-fallback):active,.multiselect-container .multiselect-option.active:not(.multiselect-active-item-fallback),.multiselect-container .multiselect-option:not(.multiselect-active-item-fallback):active{background-color:#d3d3d3;color:#000}.multiselect-container .multiselect-all:focus,.multiselect-container .multiselect-all:hover,.multiselect-container .multiselect-group:focus,.multiselect-container .multiselect-group:hover,.multiselect-container .multiselect-option:focus,.multiselect-container .multiselect-option:hover{background-color:#a9a9a9!important}.multiselect-container .multiselect-all .form-check,.multiselect-container .multiselect-group .form-check,.multiselect-container .multiselect-option .form-check{padding:0 5px 0 20px}.multiselect-container .multiselect-all:focus,.multiselect-container .multiselect-group:focus,.multiselect-container .multiselect-option:focus{outline:0}.form-inline .multiselect-container span.form-check{padding:3px 20px 3px 40px}.input-group.input-group-sm>.multiselect-native-select .multiselect{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;padding-right:1.75rem;height:calc(1.5em + .5rem + 2px)}.input-group>.multiselect-native-select{flex:1 1 auto;width:1%}.input-group>.multiselect-native-select>div.btn-group{width:100%}.input-group>.multiselect-native-select:not(:first-child) .multiselect{border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.multiselect-native-select:not(:last-child) .multiselect{border-top-right-radius:0;border-bottom-right-radius:0} \ No newline at end of file diff --git a/vendor/bootstrap-multiselect/bootstrap-multiselect.min.js b/vendor/bootstrap-multiselect/bootstrap-multiselect.min.js new file mode 100644 index 0000000000..eaa0142e91 --- /dev/null +++ b/vendor/bootstrap-multiselect/bootstrap-multiselect.min.js @@ -0,0 +1,44 @@ +/** + * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/) + * + * Apache License, Version 2.0: + * Copyright (c) 2012 - 2022 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 - 2022 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(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('').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:'
',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:'',popupContainer:'',filter:'
',buttonGroup:'
',buttonGroupReset:'',option:'',divider:'',optionGroup:'',resetButton:'
'}},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;a0)!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("");a.addClass("form-check");var r=t('