diff --git a/package.json b/package.json index 32f9228..de46e0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap5-tags", - "version": "1.3.2", + "version": "1.3.3", "description": "Replace select[multiple] with nices badges", "main": "tags", "scripts": { diff --git a/tags.js b/tags.js index 4404eba..2be9bb5 100644 --- a/tags.js +++ b/tags.js @@ -530,7 +530,7 @@ class Tags { } /** - * Find if label is already selected + * Find if label is already selected (based on attribute) * @param {string} text * @returns {boolean} */ @@ -616,9 +616,9 @@ class Tags { }); } - // update select + // update select, we need to set attribute for isSelected if (opt) { - opt.selected = true; + opt.setAttribute("selected", "selected"); } else { // we need to create a new option opt = document.createElement("option"); @@ -628,7 +628,7 @@ class Tags { for (const [key, value] of Object.entries(data)) { opt.dataset[key] = value; } - opt.selected = true; + opt.setAttribute("selected", "selected"); this.selectElement.appendChild(opt); } diff --git a/tags.min.js b/tags.min.js index 9c2c59c..b973129 100644 --- a/tags.min.js +++ b/tags.min.js @@ -1,2 +1,2 @@ -var m="is-active",o=["is-active","bg-primary","text-white"],d="data-value",u=class{constructor(t,e={}){for(this.selectElement=t,this.selectElement.style.display="none",this.placeholder=this.getPlaceholder(),this.allowNew=!!t.dataset.allowNew,this.showAllSuggestions=!!t.dataset.showAllSuggestions,this.badgeStyle=t.dataset.badgeStyle||"primary",this.allowClear=!!t.dataset.allowClear,this.server=t.dataset.server||!1,this.liveServer=!!t.dataset.liveServer,this.suggestionsThreshold=t.dataset.suggestionsThreshold?parseInt(t.dataset.suggestionsThreshold):1,this.validationRegex=t.dataset.regex||"",this.keyboardNavigation=!1,this.clearLabel=e.clearLabel||"Clear",this.searchLabel=e.searchLabel||"Type a value",this.parentForm=t.parentElement;this.parentForm&&(this.parentForm=this.parentForm.parentElement,this.parentForm.nodeName!="FORM"););if(this.parentForm.addEventListener("reset",s=>{this.reset()}),this.holderElement=document.createElement("div"),this.containerElement=document.createElement("div"),this.dropElement=document.createElement("ul"),this.searchInput=document.createElement("input"),this.holderElement.appendChild(this.containerElement),this.containerElement.appendChild(this.searchInput),this.holderElement.appendChild(this.dropElement),this.selectElement.parentNode.insertBefore(this.holderElement,this.selectElement.nextSibling),this.configureSearchInput(),this.configureHolderElement(),this.configureDropElement(),this.configureContainerElement(),this.server&&!this.liveServer)this.loadFromServer();else{let s=Array.from(this.selectElement.querySelectorAll("option")).map(l=>({value:l.getAttribute("value"),label:l.innerText}));this.buildSuggestions(s)}}static init(t="select[multiple]",e={}){let s=document.querySelectorAll(t);for(let l=0;l{this.keyboardNavigation=!1})}configureHolderElement(){this.holderElement.classList.add("form-control"),this.holderElement.classList.add("dropdown"),this.getBootstrapVersion()===4&&(this.holderElement.style.height="auto")}configureContainerElement(){this.containerElement.addEventListener("click",e=>{this.searchInput.focus()});let t=this.selectElement.querySelectorAll("option[selected]");for(let e=0;e{this.adjustWidth(),this.searchInput.value.length>=this.suggestionsThreshold?this.liveServer?this.loadFromServer(!0):this.showSuggestions():this.hideSuggestions()}),this.searchInput.addEventListener("focus",e=>{this.searchInput.value.length>=this.suggestionsThreshold&&this.showSuggestions()}),this.searchInput.addEventListener("focusout",e=>{t.hideSuggestions()}),this.searchInput.addEventListener("keydown",e=>{switch(e.keyCode||e.key){case 13:case"Enter":let l=this.getActiveSelection();l?l.click():this.allowNew&&!this.isSelected(this.searchInput.value)&&this.addItem(this.searchInput.value,null)&&(this.resetSearchInput(),this.hideSuggestions()),e.preventDefault();break;case 38:case"ArrowUp":e.preventDefault(),this.keyboardNavigation=!0;let i=this.moveSelectionUp();this.searchInput.value.length==0&&this.dropElement.classList.contains("show")&&!i&&this.hideSuggestions();break;case 40:case"ArrowDown":e.preventDefault(),this.keyboardNavigation=!0,this.moveSelectionDown(),this.searchInput.value.length==0&&!this.dropElement.classList.contains("show")&&this.showSuggestions();break;case 8:case"Backspace":this.searchInput.value.length==0&&(this.removeLastItem(),this.adjustWidth(),this.hideSuggestions());break}})}moveSelectionUp(){let t=this.getActiveSelection();if(t){let e=t.parentNode;do e=e.previousSibling;while(e&&e.style.display=="none");return e?(t.classList.remove(...o),e.querySelector("a").classList.add(...o),e.parentNode.scrollTop=e.offsetTop-e.parentNode.offsetTop,e):null}return null}moveSelectionDown(){let t=this.getActiveSelection();if(t){let e=t.parentNode;do e=e.nextSibling;while(e&&e.style.display=="none");return e?(t.classList.remove(...o),e.querySelector("a").classList.add(...o),e.offsetTop>e.parentNode.offsetHeight-e.offsetHeight&&(e.parentNode.scrollTop+=e.offsetHeight),e):null}return null}adjustWidth(){this.searchInput.value?this.searchInput.size=this.searchInput.value.length+1:this.getSelectedValues().length?(this.searchInput.placeholder="",this.searchInput.size=1):(this.searchInput.size=this.placeholder.length,this.searchInput.placeholder=this.placeholder)}buildSuggestions(t=null){for(;this.dropElement.lastChild;)this.dropElement.removeChild(this.dropElement.lastChild);for(let e=0;e{this.keyboardNavigation||(this.removeActiveSelection(),l.querySelector("a").classList.add(...o))}),i.addEventListener("mousemove",r=>{this.keyboardNavigation=!1}),i.addEventListener("mousedown",r=>{r.preventDefault()}),i.addEventListener("click",r=>{r.preventDefault(),this.addItem(i.innerText,i.getAttribute(d),i.dataset),this.resetSearchInput(),this.hideSuggestions()})}}reset(){this.removeAll();let t=this.selectElement.querySelectorAll("option[data-init]");for(let e=0;ee.value)}showSuggestions(){this.dropElement.classList.contains("show")||this.dropElement.classList.add("show"),this.dropElement.style.left=this.searchInput.offsetLeft+"px";let t=this.searchInput.value.toLocaleLowerCase(),e=this.getSelectedValues(),s=this.dropElement.querySelectorAll("li"),l=!1,i=null,r=!1;for(let n=0;n{this.removeLastItem()})}removeLastItem(){let t=this.containerElement.querySelectorAll("span");if(!t.length)return;let e=t[t.length-1];this.removeItem(e.getAttribute(d))}getBootstrapVersion(){let t=5;return window.jQuery&&$.fn.tooltip!=null&&$.fn.tooltip.Constructor!=null&&(t=parseInt($.fn.tooltip.Constructor.VERSION.charAt(0))),t}isSelected(t){let e=Array.from(this.selectElement.querySelectorAll("option")).find(s=>s.textContent==t);return!!(e&&e.getAttribute("selected"))}validateRegex(t){return new RegExp(this.validationRegex.trim()).test(t)}addItem(t,e=null,s={}){if(e||(e=t),this.validationRegex&&!this.validateRegex(t))return this.holderElement.classList.add("is-invalid"),!1;let l=this.getBootstrapVersion(),i=this.selectElement.querySelector('option[value="'+e+'"]');i&&(s=i.dataset);let r=t,n=document.createElement("span"),a=this.badgeStyle;if(n.classList.add("badge"),s.badgeStyle&&(a=s.badgeStyle),s.badgeClass&&n.classList.add(s.badgeClass),l===5?(n.classList.add("bg-"+a),n.classList.add("me-2")):(n.classList.add("badge-"+a),n.classList.add("mr-2")),n.setAttribute(d,e),this.allowClear&&(r=(l===5?'':'')+r),n.innerHTML=r,this.containerElement.insertBefore(n,this.searchInput),this.allowClear&&n.querySelector("button").addEventListener("click",h=>{h.preventDefault(),h.stopPropagation(),this.removeItem(e),document.activeElement.blur()}),i)i.selected=!0;else{i=document.createElement("option"),i.value=e,i.innerText=t;for(let[h,c]of Object.entries(s))i.dataset[h]=c;i.selected=!0,this.selectElement.appendChild(i)}return!0}removeItem(t){let e=this.containerElement.querySelector("span["+d+'="'+t+'"]');if(!e)return;e.remove();let s=this.selectElement.querySelector('option[value="'+t+'"]');s&&s.removeAttribute("selected")}},f=u;export{f as default}; +var m="is-active",o=["is-active","bg-primary","text-white"],d="data-value",u=class{constructor(t,e={}){for(this.selectElement=t,this.selectElement.style.display="none",this.placeholder=this.getPlaceholder(),this.allowNew=!!t.dataset.allowNew,this.showAllSuggestions=!!t.dataset.showAllSuggestions,this.badgeStyle=t.dataset.badgeStyle||"primary",this.allowClear=!!t.dataset.allowClear,this.server=t.dataset.server||!1,this.liveServer=!!t.dataset.liveServer,this.suggestionsThreshold=t.dataset.suggestionsThreshold?parseInt(t.dataset.suggestionsThreshold):1,this.validationRegex=t.dataset.regex||"",this.keyboardNavigation=!1,this.clearLabel=e.clearLabel||"Clear",this.searchLabel=e.searchLabel||"Type a value",this.parentForm=t.parentElement;this.parentForm&&(this.parentForm=this.parentForm.parentElement,this.parentForm.nodeName!="FORM"););if(this.parentForm.addEventListener("reset",s=>{this.reset()}),this.holderElement=document.createElement("div"),this.containerElement=document.createElement("div"),this.dropElement=document.createElement("ul"),this.searchInput=document.createElement("input"),this.holderElement.appendChild(this.containerElement),this.containerElement.appendChild(this.searchInput),this.holderElement.appendChild(this.dropElement),this.selectElement.parentNode.insertBefore(this.holderElement,this.selectElement.nextSibling),this.configureSearchInput(),this.configureHolderElement(),this.configureDropElement(),this.configureContainerElement(),this.server&&!this.liveServer)this.loadFromServer();else{let s=Array.from(this.selectElement.querySelectorAll("option")).map(l=>({value:l.getAttribute("value"),label:l.innerText}));this.buildSuggestions(s)}}static init(t="select[multiple]",e={}){let s=document.querySelectorAll(t);for(let l=0;l{this.keyboardNavigation=!1})}configureHolderElement(){this.holderElement.classList.add("form-control"),this.holderElement.classList.add("dropdown"),this.getBootstrapVersion()===4&&(this.holderElement.style.height="auto")}configureContainerElement(){this.containerElement.addEventListener("click",e=>{this.searchInput.focus()});let t=this.selectElement.querySelectorAll("option[selected]");for(let e=0;e{this.adjustWidth(),this.searchInput.value.length>=this.suggestionsThreshold?this.liveServer?this.loadFromServer(!0):this.showSuggestions():this.hideSuggestions()}),this.searchInput.addEventListener("focus",e=>{this.searchInput.value.length>=this.suggestionsThreshold&&this.showSuggestions()}),this.searchInput.addEventListener("focusout",e=>{t.hideSuggestions()}),this.searchInput.addEventListener("keydown",e=>{switch(e.keyCode||e.key){case 13:case"Enter":let l=this.getActiveSelection();l?l.click():this.allowNew&&!this.isSelected(this.searchInput.value)&&this.addItem(this.searchInput.value,null)&&(this.resetSearchInput(),this.hideSuggestions()),e.preventDefault();break;case 38:case"ArrowUp":e.preventDefault(),this.keyboardNavigation=!0;let i=this.moveSelectionUp();this.searchInput.value.length==0&&this.dropElement.classList.contains("show")&&!i&&this.hideSuggestions();break;case 40:case"ArrowDown":e.preventDefault(),this.keyboardNavigation=!0,this.moveSelectionDown(),this.searchInput.value.length==0&&!this.dropElement.classList.contains("show")&&this.showSuggestions();break;case 8:case"Backspace":this.searchInput.value.length==0&&(this.removeLastItem(),this.adjustWidth(),this.hideSuggestions());break}})}moveSelectionUp(){let t=this.getActiveSelection();if(t){let e=t.parentNode;do e=e.previousSibling;while(e&&e.style.display=="none");return e?(t.classList.remove(...o),e.querySelector("a").classList.add(...o),e.parentNode.scrollTop=e.offsetTop-e.parentNode.offsetTop,e):null}return null}moveSelectionDown(){let t=this.getActiveSelection();if(t){let e=t.parentNode;do e=e.nextSibling;while(e&&e.style.display=="none");return e?(t.classList.remove(...o),e.querySelector("a").classList.add(...o),e.offsetTop>e.parentNode.offsetHeight-e.offsetHeight&&(e.parentNode.scrollTop+=e.offsetHeight),e):null}return null}adjustWidth(){this.searchInput.value?this.searchInput.size=this.searchInput.value.length+1:this.getSelectedValues().length?(this.searchInput.placeholder="",this.searchInput.size=1):(this.searchInput.size=this.placeholder.length,this.searchInput.placeholder=this.placeholder)}buildSuggestions(t=null){for(;this.dropElement.lastChild;)this.dropElement.removeChild(this.dropElement.lastChild);for(let e=0;e{this.keyboardNavigation||(this.removeActiveSelection(),l.querySelector("a").classList.add(...o))}),i.addEventListener("mousemove",r=>{this.keyboardNavigation=!1}),i.addEventListener("mousedown",r=>{r.preventDefault()}),i.addEventListener("click",r=>{r.preventDefault(),this.addItem(i.innerText,i.getAttribute(d),i.dataset),this.resetSearchInput(),this.hideSuggestions()})}}reset(){this.removeAll();let t=this.selectElement.querySelectorAll("option[data-init]");for(let e=0;ee.value)}showSuggestions(){this.dropElement.classList.contains("show")||this.dropElement.classList.add("show"),this.dropElement.style.left=this.searchInput.offsetLeft+"px";let t=this.searchInput.value.toLocaleLowerCase(),e=this.getSelectedValues(),s=this.dropElement.querySelectorAll("li"),l=!1,i=null,r=!1;for(let n=0;n{this.removeLastItem()})}removeLastItem(){let t=this.containerElement.querySelectorAll("span");if(!t.length)return;let e=t[t.length-1];this.removeItem(e.getAttribute(d))}getBootstrapVersion(){let t=5;return window.jQuery&&$.fn.tooltip!=null&&$.fn.tooltip.Constructor!=null&&(t=parseInt($.fn.tooltip.Constructor.VERSION.charAt(0))),t}isSelected(t){let e=Array.from(this.selectElement.querySelectorAll("option")).find(s=>s.textContent==t);return!!(e&&e.getAttribute("selected"))}validateRegex(t){return new RegExp(this.validationRegex.trim()).test(t)}addItem(t,e=null,s={}){if(e||(e=t),this.validationRegex&&!this.validateRegex(t))return this.holderElement.classList.add("is-invalid"),!1;let l=this.getBootstrapVersion(),i=this.selectElement.querySelector('option[value="'+e+'"]');i&&(s=i.dataset);let r=t,n=document.createElement("span"),a=this.badgeStyle;if(n.classList.add("badge"),s.badgeStyle&&(a=s.badgeStyle),s.badgeClass&&n.classList.add(s.badgeClass),l===5?(n.classList.add("bg-"+a),n.classList.add("me-2")):(n.classList.add("badge-"+a),n.classList.add("mr-2")),n.setAttribute(d,e),this.allowClear&&(r=(l===5?'':'')+r),n.innerHTML=r,this.containerElement.insertBefore(n,this.searchInput),this.allowClear&&n.querySelector("button").addEventListener("click",h=>{h.preventDefault(),h.stopPropagation(),this.removeItem(e),document.activeElement.blur()}),i)i.setAttribute("selected","selected");else{i=document.createElement("option"),i.value=e,i.innerText=t;for(let[h,c]of Object.entries(s))i.dataset[h]=c;i.setAttribute("selected","selected"),this.selectElement.appendChild(i)}return!0}removeItem(t){let e=this.containerElement.querySelector("span["+d+'="'+t+'"]');if(!e)return;e.remove();let s=this.selectElement.querySelector('option[value="'+t+'"]');s&&s.removeAttribute("selected")}},f=u;export{f as default}; //# sourceMappingURL=tags.min.js.map diff --git a/tags.min.js.map b/tags.min.js.map index 4c645f2..636bdf1 100644 --- a/tags.min.js.map +++ b/tags.min.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["tags.js"], - "sourcesContent": ["/**\r\n * Bootstrap 5 (and 4!) tags\r\n *\r\n * Turns your select[multiple] into nice tags lists\r\n *\r\n * Required Bootstrap 5 styles:\r\n * - badge\r\n * - background-color utility\r\n * - margin-end utility\r\n * - forms\r\n * - dropdown\r\n */\r\n\r\nconst ACTIVE_CLASS = \"is-active\";\r\nconst ACTIVE_CLASSES = [\"is-active\", \"bg-primary\", \"text-white\"];\r\nconst VALUE_ATTRIBUTE = \"data-value\";\r\n\r\nclass Tags {\r\n /**\r\n * @param {HTMLSelectElement} selectElement\r\n * @param {Object} opts\r\n */\r\n constructor(selectElement, opts = {}) {\r\n this.selectElement = selectElement;\r\n this.selectElement.style.display = \"none\";\r\n this.placeholder = this.getPlaceholder();\r\n this.allowNew = selectElement.dataset.allowNew ? true : false;\r\n this.showAllSuggestions = selectElement.dataset.showAllSuggestions ? true : false;\r\n this.badgeStyle = selectElement.dataset.badgeStyle || \"primary\";\r\n this.allowClear = selectElement.dataset.allowClear ? true : false;\r\n this.server = selectElement.dataset.server || false;\r\n this.liveServer = selectElement.dataset.liveServer ? true : false;\r\n this.suggestionsThreshold = selectElement.dataset.suggestionsThreshold ? parseInt(selectElement.dataset.suggestionsThreshold) : 1;\r\n this.validationRegex = selectElement.dataset.regex || \"\";\r\n this.keyboardNavigation = false;\r\n this.clearLabel = opts.clearLabel || \"Clear\";\r\n this.searchLabel = opts.searchLabel || \"Type a value\";\r\n\r\n this.parentForm = selectElement.parentElement;\r\n while (this.parentForm) {\r\n this.parentForm = this.parentForm.parentElement;\r\n if (this.parentForm.nodeName == \"FORM\") {\r\n break;\r\n }\r\n }\r\n this.parentForm.addEventListener(\"reset\", (ev) => {\r\n this.reset();\r\n });\r\n\r\n // Create elements\r\n this.holderElement = document.createElement(\"div\"); // this is the one holding the fake input and the dropmenu\r\n this.containerElement = document.createElement(\"div\"); // this is the one for the fake input (labels + input)\r\n this.dropElement = document.createElement(\"ul\");\r\n this.searchInput = document.createElement(\"input\");\r\n\r\n this.holderElement.appendChild(this.containerElement);\r\n this.containerElement.appendChild(this.searchInput);\r\n this.holderElement.appendChild(this.dropElement);\r\n // insert after\r\n this.selectElement.parentNode.insertBefore(this.holderElement, this.selectElement.nextSibling);\r\n\r\n // Configure them\r\n this.configureSearchInput();\r\n this.configureHolderElement();\r\n this.configureDropElement();\r\n this.configureContainerElement();\r\n\r\n if (this.server && !this.liveServer) {\r\n this.loadFromServer();\r\n } else {\r\n let suggestions = Array.from(this.selectElement.querySelectorAll(\"option\")).map((option) => {\r\n return {\r\n value: option.getAttribute(\"value\"),\r\n label: option.innerText,\r\n };\r\n });\r\n this.buildSuggestions(suggestions);\r\n }\r\n }\r\n\r\n /**\r\n * Attach to all elements matched by the selector\r\n * @param {string} selector\r\n * @param {Object} opts\r\n */\r\n static init(selector = \"select[multiple]\", opts = {}) {\r\n let list = document.querySelectorAll(selector);\r\n for (let i = 0; i < list.length; i++) {\r\n let el = list[i];\r\n let inst = new Tags(el, opts);\r\n }\r\n }\r\n\r\n /**\r\n * @param {boolean} show\r\n */\r\n loadFromServer(show = false) {\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n }\r\n this.abortController = new AbortController();\r\n fetch(this.server + \"?query=\" + encodeURIComponent(this.searchInput.value), { signal: this.abortController.signal })\r\n .then((r) => r.json())\r\n .then((suggestions) => {\r\n let data = suggestions.data || suggestions;\r\n this.buildSuggestions(data);\r\n this.abortController = null;\r\n if (show) {\r\n this.showSuggestions();\r\n }\r\n })\r\n .catch((e) => {\r\n if (e.name === \"AbortError\") {\r\n return;\r\n }\r\n console.error(e);\r\n });\r\n }\r\n\r\n /**\r\n * @returns {string}\r\n */\r\n getPlaceholder() {\r\n let firstOption = this.selectElement.querySelector(\"option\");\r\n if (!firstOption) {\r\n return;\r\n }\r\n if (!firstOption.value) {\r\n let placeholder = firstOption.innerText;\r\n firstOption.remove();\r\n return placeholder;\r\n }\r\n if (this.selectElement.getAttribute(\"placeholder\")) {\r\n return this.selectElement.getAttribute(\"placeholder\");\r\n }\r\n if (this.selectElement.getAttribute(\"data-placeholder\")) {\r\n return this.selectElement.getAttribute(\"data-placeholder\");\r\n }\r\n return \"\";\r\n }\r\n\r\n configureDropElement() {\r\n this.dropElement.classList.add(\"dropdown-menu\");\r\n this.dropElement.classList.add(\"p-0\");\r\n this.dropElement.style.maxHeight = \"280px\";\r\n this.dropElement.style.overflowY = \"auto\";\r\n\r\n // If the mouse was outside, entering remove keyboard nav mode\r\n this.dropElement.addEventListener(\"mouseenter\", (event) => {\r\n this.keyboardNavigation = false;\r\n });\r\n }\r\n\r\n configureHolderElement() {\r\n this.holderElement.classList.add(\"form-control\");\r\n this.holderElement.classList.add(\"dropdown\");\r\n if (this.getBootstrapVersion() === 4) {\r\n // Prevent fixed height due to form-control\r\n this.holderElement.style.height = \"auto\";\r\n }\r\n }\r\n\r\n configureContainerElement() {\r\n this.containerElement.addEventListener(\"click\", (event) => {\r\n this.searchInput.focus();\r\n });\r\n\r\n // add initial values\r\n let initialValues = this.selectElement.querySelectorAll(\"option[selected]\");\r\n for (let j = 0; j < initialValues.length; j++) {\r\n let initialValue = initialValues[j];\r\n if (!initialValue.value) {\r\n continue;\r\n }\r\n initialValue.dataset.init = 1;\r\n this.addItem(initialValue.innerText, initialValue.value);\r\n }\r\n }\r\n\r\n configureSearchInput() {\r\n let self = this;\r\n this.searchInput.type = \"text\";\r\n this.searchInput.autocomplete = \"off\";\r\n this.searchInput.style.border = 0;\r\n this.searchInput.style.outline = 0;\r\n this.searchInput.style.maxWidth = \"100%\";\r\n this.searchInput.ariaLabel = this.searchLabel;\r\n\r\n this.adjustWidth();\r\n\r\n this.searchInput.addEventListener(\"input\", (event) => {\r\n this.adjustWidth();\r\n if (this.searchInput.value.length >= this.suggestionsThreshold) {\r\n if (this.liveServer) {\r\n this.loadFromServer(true);\r\n } else {\r\n this.showSuggestions();\r\n }\r\n } else {\r\n this.hideSuggestions();\r\n }\r\n });\r\n this.searchInput.addEventListener(\"focus\", (event) => {\r\n if (this.searchInput.value.length >= this.suggestionsThreshold) {\r\n this.showSuggestions();\r\n }\r\n });\r\n this.searchInput.addEventListener(\"focusout\", (event) => {\r\n self.hideSuggestions();\r\n });\r\n // keypress doesn't send arrow keys\r\n this.searchInput.addEventListener(\"keydown\", (event) => {\r\n // Keycode reference : https://css-tricks.com/snippets/javascript/javascript-keycodes/\r\n let key = event.keyCode || event.key;\r\n switch (key) {\r\n case 13:\r\n case \"Enter\":\r\n let selection = this.getActiveSelection();\r\n if (selection) {\r\n selection.click();\r\n } else {\r\n // We use what is typed\r\n if (this.allowNew && !this.isSelected(this.searchInput.value)) {\r\n let res = this.addItem(this.searchInput.value, null);\r\n if (res) {\r\n this.resetSearchInput();\r\n this.hideSuggestions();\r\n }\r\n }\r\n }\r\n event.preventDefault();\r\n break;\r\n case 38:\r\n case \"ArrowUp\":\r\n event.preventDefault();\r\n this.keyboardNavigation = true;\r\n let newSelection = this.moveSelectionUp();\r\n // If we use arrow up without input and there is no new selection, hide suggestions\r\n if (this.searchInput.value.length == 0 && this.dropElement.classList.contains(\"show\") && !newSelection) {\r\n this.hideSuggestions();\r\n }\r\n break;\r\n case 40:\r\n case \"ArrowDown\":\r\n event.preventDefault();\r\n this.keyboardNavigation = true;\r\n this.moveSelectionDown();\r\n // If we use arrow down without input, show suggestions\r\n if (this.searchInput.value.length == 0 && !this.dropElement.classList.contains(\"show\")) {\r\n this.showSuggestions();\r\n }\r\n break;\r\n case 8:\r\n case \"Backspace\":\r\n if (this.searchInput.value.length == 0) {\r\n this.removeLastItem();\r\n this.adjustWidth();\r\n this.hideSuggestions();\r\n }\r\n break;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n moveSelectionUp() {\r\n let active = this.getActiveSelection();\r\n if (active) {\r\n let prev = active.parentNode;\r\n do {\r\n prev = prev.previousSibling;\r\n } while (prev && prev.style.display == \"none\");\r\n if (!prev) {\r\n return null;\r\n }\r\n active.classList.remove(...ACTIVE_CLASSES);\r\n prev.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n // Don't use scrollIntoView as it scrolls the whole window\r\n prev.parentNode.scrollTop = prev.offsetTop - prev.parentNode.offsetTop;\r\n return prev;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n moveSelectionDown() {\r\n let active = this.getActiveSelection();\r\n if (active) {\r\n let next = active.parentNode;\r\n do {\r\n next = next.nextSibling;\r\n } while (next && next.style.display == \"none\");\r\n if (!next) {\r\n return null;\r\n }\r\n active.classList.remove(...ACTIVE_CLASSES);\r\n next.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n // This is the equivalent of scrollIntoView(false) but only for parent node\r\n if (next.offsetTop > next.parentNode.offsetHeight - next.offsetHeight) {\r\n next.parentNode.scrollTop += next.offsetHeight;\r\n }\r\n return next;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Adjust the field to fit its content\r\n */\r\n adjustWidth() {\r\n if (this.searchInput.value) {\r\n this.searchInput.size = this.searchInput.value.length + 1;\r\n } else {\r\n // Show the placeholder only if empty\r\n if (this.getSelectedValues().length) {\r\n this.searchInput.placeholder = \"\";\r\n this.searchInput.size = 1;\r\n } else {\r\n this.searchInput.size = this.placeholder.length;\r\n this.searchInput.placeholder = this.placeholder;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Add suggestions to the drop element\r\n * @param {array}\r\n */\r\n buildSuggestions(suggestions = null) {\r\n while (this.dropElement.lastChild) {\r\n this.dropElement.removeChild(this.dropElement.lastChild);\r\n }\r\n for (let i = 0; i < suggestions.length; i++) {\r\n let suggestion = suggestions[i];\r\n if (!suggestion.value) {\r\n continue;\r\n }\r\n let newChild = document.createElement(\"li\");\r\n let newChildLink = document.createElement(\"a\");\r\n newChild.append(newChildLink);\r\n newChildLink.classList.add(\"dropdown-item\");\r\n newChildLink.setAttribute(VALUE_ATTRIBUTE, suggestion.value);\r\n newChildLink.setAttribute(\"href\", \"#\");\r\n newChildLink.innerText = suggestion.label;\r\n if (suggestion.data) {\r\n for (const [key, value] of Object.entries(suggestion.data)) {\r\n newChildLink.dataset[key] = value;\r\n }\r\n }\r\n this.dropElement.appendChild(newChild);\r\n\r\n // Hover sets active item\r\n newChildLink.addEventListener(\"mouseenter\", (event) => {\r\n // Don't trigger enter if using arrows\r\n if (this.keyboardNavigation) {\r\n return;\r\n }\r\n this.removeActiveSelection();\r\n newChild.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n });\r\n // Moving the mouse means no longer using keyboard\r\n newChildLink.addEventListener(\"mousemove\", (event) => {\r\n this.keyboardNavigation = false;\r\n });\r\n\r\n newChildLink.addEventListener(\"mousedown\", (event) => {\r\n // Otherwise searchInput would lose focus and close the menu\r\n event.preventDefault();\r\n });\r\n newChildLink.addEventListener(\"click\", (event) => {\r\n event.preventDefault();\r\n this.addItem(newChildLink.innerText, newChildLink.getAttribute(VALUE_ATTRIBUTE), newChildLink.dataset);\r\n this.resetSearchInput();\r\n this.hideSuggestions();\r\n });\r\n }\r\n }\r\n\r\n reset() {\r\n this.removeAll();\r\n let initialValues = this.selectElement.querySelectorAll(\"option[data-init]\");\r\n for (let j = 0; j < initialValues.length; j++) {\r\n let initialValue = initialValues[j];\r\n this.addItem(initialValue.innerText, initialValue.value);\r\n }\r\n }\r\n\r\n resetSearchInput() {\r\n this.searchInput.value = \"\";\r\n this.adjustWidth();\r\n }\r\n\r\n /**\r\n * @returns {array}\r\n */\r\n getSelectedValues() {\r\n let selected = this.selectElement.querySelectorAll(\"option:checked\");\r\n return Array.from(selected).map((el) => el.value);\r\n }\r\n\r\n /**\r\n * The element create with buildSuggestions\r\n */\r\n showSuggestions() {\r\n if (!this.dropElement.classList.contains(\"show\")) {\r\n this.dropElement.classList.add(\"show\");\r\n }\r\n\r\n // Position next to search input\r\n this.dropElement.style.left = this.searchInput.offsetLeft + \"px\";\r\n\r\n // Get search value\r\n let search = this.searchInput.value.toLocaleLowerCase();\r\n\r\n // Get current values\r\n let values = this.getSelectedValues();\r\n\r\n // Filter the list according to search string\r\n let list = this.dropElement.querySelectorAll(\"li\");\r\n let found = false;\r\n let firstItem = null;\r\n let hasPossibleValues = false;\r\n for (let i = 0; i < list.length; i++) {\r\n let item = list[i];\r\n let text = item.innerText.toLocaleLowerCase();\r\n let link = item.querySelector(\"a\");\r\n\r\n // Remove previous selection\r\n link.classList.remove(...ACTIVE_CLASSES);\r\n\r\n // Hide selected values\r\n if (values.indexOf(link.getAttribute(VALUE_ATTRIBUTE)) != -1) {\r\n item.style.display = \"none\";\r\n continue;\r\n }\r\n\r\n hasPossibleValues = true;\r\n\r\n // Check search length since we can trigger dropdown with arrow\r\n let isMatched = search.length === 0 || text.indexOf(search) !== -1;\r\n if (this.showAllSuggestions || this.suggestionsThreshold === 0 || isMatched) {\r\n item.style.display = \"list-item\";\r\n found = true;\r\n if (!firstItem && isMatched) {\r\n firstItem = item;\r\n }\r\n } else {\r\n item.style.display = \"none\";\r\n }\r\n }\r\n\r\n // Special case if nothing matches\r\n if (!found) {\r\n this.dropElement.classList.remove(\"show\");\r\n }\r\n\r\n // Always select first item\r\n if (firstItem) {\r\n if (this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n firstItem.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n firstItem.parentNode.scrollTop = firstItem.offsetTop - firstItem.parentNode.offsetTop;\r\n } else {\r\n // No item and we don't allow new items => error\r\n if (!this.allowNew && !(search.length === 0 && !hasPossibleValues)) {\r\n this.holderElement.classList.add(\"is-invalid\");\r\n } else if (this.validationRegex && this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * The element create with buildSuggestions\r\n */\r\n hideSuggestions() {\r\n if (this.dropElement.classList.contains(\"show\")) {\r\n this.dropElement.classList.remove(\"show\");\r\n }\r\n if (this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n getActiveSelection() {\r\n return this.dropElement.querySelector(\"a.\" + ACTIVE_CLASS);\r\n }\r\n\r\n removeActiveSelection() {\r\n let selection = this.getActiveSelection();\r\n if (selection) {\r\n selection.classList.remove(...ACTIVE_CLASSES);\r\n }\r\n }\r\n\r\n removeAll() {\r\n let items = this.containerElement.querySelectorAll(\"span\");\r\n items.forEach((item) => {\r\n this.removeLastItem();\r\n });\r\n }\r\n\r\n removeLastItem() {\r\n let items = this.containerElement.querySelectorAll(\"span\");\r\n if (!items.length) {\r\n return;\r\n }\r\n let lastItem = items[items.length - 1];\r\n this.removeItem(lastItem.getAttribute(VALUE_ATTRIBUTE));\r\n }\r\n\r\n /**\r\n * @returns {Number}\r\n */\r\n getBootstrapVersion() {\r\n let ver = 5;\r\n // If we have jQuery and the tooltip plugin for BS4\r\n if (window.jQuery && $.fn.tooltip != undefined && $.fn.tooltip.Constructor != undefined) {\r\n ver = parseInt($.fn.tooltip.Constructor.VERSION.charAt(0));\r\n }\r\n return ver;\r\n }\r\n\r\n /**\r\n * Find if label is already selected\r\n * @param {string} text\r\n * @returns {boolean}\r\n */\r\n isSelected(text) {\r\n const opt = Array.from(this.selectElement.querySelectorAll(\"option\")).find((el) => el.textContent == text);\r\n if (opt && opt.getAttribute(\"selected\")) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Checks if value matches a configured regex\r\n * @param {string} value\r\n * @returns {boolean}\r\n */\r\n validateRegex(value) {\r\n const regex = new RegExp(this.validationRegex.trim());\r\n return regex.test(value);\r\n }\r\n\r\n /**\r\n * @param {string} text\r\n * @param {string} value\r\n * @param {object} data\r\n * @return {boolean}\r\n */\r\n addItem(text, value = null, data = {}) {\r\n if (!value) {\r\n value = text;\r\n }\r\n\r\n if (this.validationRegex && !this.validateRegex(text)) {\r\n this.holderElement.classList.add(\"is-invalid\");\r\n return false;\r\n }\r\n\r\n const bver = this.getBootstrapVersion();\r\n let opt = this.selectElement.querySelector('option[value=\"' + value + '\"]');\r\n if (opt) {\r\n data = opt.dataset;\r\n }\r\n\r\n // create span\r\n let html = text;\r\n let span = document.createElement(\"span\");\r\n let badgeStyle = this.badgeStyle;\r\n span.classList.add(\"badge\");\r\n if (data.badgeStyle) {\r\n badgeStyle = data.badgeStyle;\r\n }\r\n if (data.badgeClass) {\r\n span.classList.add(data.badgeClass);\r\n }\r\n if (bver === 5) {\r\n //https://getbootstrap.com/docs/5.1/components/badge/\r\n span.classList.add(\"bg-\" + badgeStyle);\r\n span.classList.add(\"me-2\");\r\n } else {\r\n // https://getbootstrap.com/docs/4.6/components/badge/\r\n span.classList.add(\"badge-\" + badgeStyle);\r\n span.classList.add(\"mr-2\");\r\n }\r\n span.setAttribute(VALUE_ATTRIBUTE, value);\r\n\r\n if (this.allowClear) {\r\n const btn =\r\n bver === 5\r\n ? ''\r\n : '';\r\n html = btn + html;\r\n }\r\n\r\n span.innerHTML = html;\r\n this.containerElement.insertBefore(span, this.searchInput);\r\n\r\n if (this.allowClear) {\r\n span.querySelector(\"button\").addEventListener(\"click\", (event) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.removeItem(value);\r\n document.activeElement.blur();\r\n });\r\n }\r\n\r\n // update select\r\n if (opt) {\r\n opt.selected = true;\r\n } else {\r\n // we need to create a new option\r\n opt = document.createElement(\"option\");\r\n opt.value = value;\r\n opt.innerText = text;\r\n // Pass along data provided\r\n for (const [key, value] of Object.entries(data)) {\r\n opt.dataset[key] = value;\r\n }\r\n opt.selected = true;\r\n this.selectElement.appendChild(opt);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * @param {string} value\r\n */\r\n removeItem(value) {\r\n let item = this.containerElement.querySelector(\"span[\" + VALUE_ATTRIBUTE + '=\"' + value + '\"]');\r\n if (!item) {\r\n return;\r\n }\r\n item.remove();\r\n\r\n // update select\r\n let opt = this.selectElement.querySelector('option[value=\"' + value + '\"]');\r\n if (opt) {\r\n opt.removeAttribute(\"selected\");\r\n }\r\n }\r\n}\r\n\r\nexport default Tags;\r\n"], - "mappings": "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", + "sourcesContent": ["/**\r\n * Bootstrap 5 (and 4!) tags\r\n *\r\n * Turns your select[multiple] into nice tags lists\r\n *\r\n * Required Bootstrap 5 styles:\r\n * - badge\r\n * - background-color utility\r\n * - margin-end utility\r\n * - forms\r\n * - dropdown\r\n */\r\n\r\nconst ACTIVE_CLASS = \"is-active\";\r\nconst ACTIVE_CLASSES = [\"is-active\", \"bg-primary\", \"text-white\"];\r\nconst VALUE_ATTRIBUTE = \"data-value\";\r\n\r\nclass Tags {\r\n /**\r\n * @param {HTMLSelectElement} selectElement\r\n * @param {Object} opts\r\n */\r\n constructor(selectElement, opts = {}) {\r\n this.selectElement = selectElement;\r\n this.selectElement.style.display = \"none\";\r\n this.placeholder = this.getPlaceholder();\r\n this.allowNew = selectElement.dataset.allowNew ? true : false;\r\n this.showAllSuggestions = selectElement.dataset.showAllSuggestions ? true : false;\r\n this.badgeStyle = selectElement.dataset.badgeStyle || \"primary\";\r\n this.allowClear = selectElement.dataset.allowClear ? true : false;\r\n this.server = selectElement.dataset.server || false;\r\n this.liveServer = selectElement.dataset.liveServer ? true : false;\r\n this.suggestionsThreshold = selectElement.dataset.suggestionsThreshold ? parseInt(selectElement.dataset.suggestionsThreshold) : 1;\r\n this.validationRegex = selectElement.dataset.regex || \"\";\r\n this.keyboardNavigation = false;\r\n this.clearLabel = opts.clearLabel || \"Clear\";\r\n this.searchLabel = opts.searchLabel || \"Type a value\";\r\n\r\n this.parentForm = selectElement.parentElement;\r\n while (this.parentForm) {\r\n this.parentForm = this.parentForm.parentElement;\r\n if (this.parentForm.nodeName == \"FORM\") {\r\n break;\r\n }\r\n }\r\n this.parentForm.addEventListener(\"reset\", (ev) => {\r\n this.reset();\r\n });\r\n\r\n // Create elements\r\n this.holderElement = document.createElement(\"div\"); // this is the one holding the fake input and the dropmenu\r\n this.containerElement = document.createElement(\"div\"); // this is the one for the fake input (labels + input)\r\n this.dropElement = document.createElement(\"ul\");\r\n this.searchInput = document.createElement(\"input\");\r\n\r\n this.holderElement.appendChild(this.containerElement);\r\n this.containerElement.appendChild(this.searchInput);\r\n this.holderElement.appendChild(this.dropElement);\r\n // insert after\r\n this.selectElement.parentNode.insertBefore(this.holderElement, this.selectElement.nextSibling);\r\n\r\n // Configure them\r\n this.configureSearchInput();\r\n this.configureHolderElement();\r\n this.configureDropElement();\r\n this.configureContainerElement();\r\n\r\n if (this.server && !this.liveServer) {\r\n this.loadFromServer();\r\n } else {\r\n let suggestions = Array.from(this.selectElement.querySelectorAll(\"option\")).map((option) => {\r\n return {\r\n value: option.getAttribute(\"value\"),\r\n label: option.innerText,\r\n };\r\n });\r\n this.buildSuggestions(suggestions);\r\n }\r\n }\r\n\r\n /**\r\n * Attach to all elements matched by the selector\r\n * @param {string} selector\r\n * @param {Object} opts\r\n */\r\n static init(selector = \"select[multiple]\", opts = {}) {\r\n let list = document.querySelectorAll(selector);\r\n for (let i = 0; i < list.length; i++) {\r\n let el = list[i];\r\n let inst = new Tags(el, opts);\r\n }\r\n }\r\n\r\n /**\r\n * @param {boolean} show\r\n */\r\n loadFromServer(show = false) {\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n }\r\n this.abortController = new AbortController();\r\n fetch(this.server + \"?query=\" + encodeURIComponent(this.searchInput.value), { signal: this.abortController.signal })\r\n .then((r) => r.json())\r\n .then((suggestions) => {\r\n let data = suggestions.data || suggestions;\r\n this.buildSuggestions(data);\r\n this.abortController = null;\r\n if (show) {\r\n this.showSuggestions();\r\n }\r\n })\r\n .catch((e) => {\r\n if (e.name === \"AbortError\") {\r\n return;\r\n }\r\n console.error(e);\r\n });\r\n }\r\n\r\n /**\r\n * @returns {string}\r\n */\r\n getPlaceholder() {\r\n let firstOption = this.selectElement.querySelector(\"option\");\r\n if (!firstOption) {\r\n return;\r\n }\r\n if (!firstOption.value) {\r\n let placeholder = firstOption.innerText;\r\n firstOption.remove();\r\n return placeholder;\r\n }\r\n if (this.selectElement.getAttribute(\"placeholder\")) {\r\n return this.selectElement.getAttribute(\"placeholder\");\r\n }\r\n if (this.selectElement.getAttribute(\"data-placeholder\")) {\r\n return this.selectElement.getAttribute(\"data-placeholder\");\r\n }\r\n return \"\";\r\n }\r\n\r\n configureDropElement() {\r\n this.dropElement.classList.add(\"dropdown-menu\");\r\n this.dropElement.classList.add(\"p-0\");\r\n this.dropElement.style.maxHeight = \"280px\";\r\n this.dropElement.style.overflowY = \"auto\";\r\n\r\n // If the mouse was outside, entering remove keyboard nav mode\r\n this.dropElement.addEventListener(\"mouseenter\", (event) => {\r\n this.keyboardNavigation = false;\r\n });\r\n }\r\n\r\n configureHolderElement() {\r\n this.holderElement.classList.add(\"form-control\");\r\n this.holderElement.classList.add(\"dropdown\");\r\n if (this.getBootstrapVersion() === 4) {\r\n // Prevent fixed height due to form-control\r\n this.holderElement.style.height = \"auto\";\r\n }\r\n }\r\n\r\n configureContainerElement() {\r\n this.containerElement.addEventListener(\"click\", (event) => {\r\n this.searchInput.focus();\r\n });\r\n\r\n // add initial values\r\n let initialValues = this.selectElement.querySelectorAll(\"option[selected]\");\r\n for (let j = 0; j < initialValues.length; j++) {\r\n let initialValue = initialValues[j];\r\n if (!initialValue.value) {\r\n continue;\r\n }\r\n initialValue.dataset.init = 1;\r\n this.addItem(initialValue.innerText, initialValue.value);\r\n }\r\n }\r\n\r\n configureSearchInput() {\r\n let self = this;\r\n this.searchInput.type = \"text\";\r\n this.searchInput.autocomplete = \"off\";\r\n this.searchInput.style.border = 0;\r\n this.searchInput.style.outline = 0;\r\n this.searchInput.style.maxWidth = \"100%\";\r\n this.searchInput.ariaLabel = this.searchLabel;\r\n\r\n this.adjustWidth();\r\n\r\n this.searchInput.addEventListener(\"input\", (event) => {\r\n this.adjustWidth();\r\n if (this.searchInput.value.length >= this.suggestionsThreshold) {\r\n if (this.liveServer) {\r\n this.loadFromServer(true);\r\n } else {\r\n this.showSuggestions();\r\n }\r\n } else {\r\n this.hideSuggestions();\r\n }\r\n });\r\n this.searchInput.addEventListener(\"focus\", (event) => {\r\n if (this.searchInput.value.length >= this.suggestionsThreshold) {\r\n this.showSuggestions();\r\n }\r\n });\r\n this.searchInput.addEventListener(\"focusout\", (event) => {\r\n self.hideSuggestions();\r\n });\r\n // keypress doesn't send arrow keys\r\n this.searchInput.addEventListener(\"keydown\", (event) => {\r\n // Keycode reference : https://css-tricks.com/snippets/javascript/javascript-keycodes/\r\n let key = event.keyCode || event.key;\r\n switch (key) {\r\n case 13:\r\n case \"Enter\":\r\n let selection = this.getActiveSelection();\r\n if (selection) {\r\n selection.click();\r\n } else {\r\n // We use what is typed\r\n if (this.allowNew && !this.isSelected(this.searchInput.value)) {\r\n let res = this.addItem(this.searchInput.value, null);\r\n if (res) {\r\n this.resetSearchInput();\r\n this.hideSuggestions();\r\n }\r\n }\r\n }\r\n event.preventDefault();\r\n break;\r\n case 38:\r\n case \"ArrowUp\":\r\n event.preventDefault();\r\n this.keyboardNavigation = true;\r\n let newSelection = this.moveSelectionUp();\r\n // If we use arrow up without input and there is no new selection, hide suggestions\r\n if (this.searchInput.value.length == 0 && this.dropElement.classList.contains(\"show\") && !newSelection) {\r\n this.hideSuggestions();\r\n }\r\n break;\r\n case 40:\r\n case \"ArrowDown\":\r\n event.preventDefault();\r\n this.keyboardNavigation = true;\r\n this.moveSelectionDown();\r\n // If we use arrow down without input, show suggestions\r\n if (this.searchInput.value.length == 0 && !this.dropElement.classList.contains(\"show\")) {\r\n this.showSuggestions();\r\n }\r\n break;\r\n case 8:\r\n case \"Backspace\":\r\n if (this.searchInput.value.length == 0) {\r\n this.removeLastItem();\r\n this.adjustWidth();\r\n this.hideSuggestions();\r\n }\r\n break;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n moveSelectionUp() {\r\n let active = this.getActiveSelection();\r\n if (active) {\r\n let prev = active.parentNode;\r\n do {\r\n prev = prev.previousSibling;\r\n } while (prev && prev.style.display == \"none\");\r\n if (!prev) {\r\n return null;\r\n }\r\n active.classList.remove(...ACTIVE_CLASSES);\r\n prev.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n // Don't use scrollIntoView as it scrolls the whole window\r\n prev.parentNode.scrollTop = prev.offsetTop - prev.parentNode.offsetTop;\r\n return prev;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n moveSelectionDown() {\r\n let active = this.getActiveSelection();\r\n if (active) {\r\n let next = active.parentNode;\r\n do {\r\n next = next.nextSibling;\r\n } while (next && next.style.display == \"none\");\r\n if (!next) {\r\n return null;\r\n }\r\n active.classList.remove(...ACTIVE_CLASSES);\r\n next.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n // This is the equivalent of scrollIntoView(false) but only for parent node\r\n if (next.offsetTop > next.parentNode.offsetHeight - next.offsetHeight) {\r\n next.parentNode.scrollTop += next.offsetHeight;\r\n }\r\n return next;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Adjust the field to fit its content\r\n */\r\n adjustWidth() {\r\n if (this.searchInput.value) {\r\n this.searchInput.size = this.searchInput.value.length + 1;\r\n } else {\r\n // Show the placeholder only if empty\r\n if (this.getSelectedValues().length) {\r\n this.searchInput.placeholder = \"\";\r\n this.searchInput.size = 1;\r\n } else {\r\n this.searchInput.size = this.placeholder.length;\r\n this.searchInput.placeholder = this.placeholder;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Add suggestions to the drop element\r\n * @param {array}\r\n */\r\n buildSuggestions(suggestions = null) {\r\n while (this.dropElement.lastChild) {\r\n this.dropElement.removeChild(this.dropElement.lastChild);\r\n }\r\n for (let i = 0; i < suggestions.length; i++) {\r\n let suggestion = suggestions[i];\r\n if (!suggestion.value) {\r\n continue;\r\n }\r\n let newChild = document.createElement(\"li\");\r\n let newChildLink = document.createElement(\"a\");\r\n newChild.append(newChildLink);\r\n newChildLink.classList.add(\"dropdown-item\");\r\n newChildLink.setAttribute(VALUE_ATTRIBUTE, suggestion.value);\r\n newChildLink.setAttribute(\"href\", \"#\");\r\n newChildLink.innerText = suggestion.label;\r\n if (suggestion.data) {\r\n for (const [key, value] of Object.entries(suggestion.data)) {\r\n newChildLink.dataset[key] = value;\r\n }\r\n }\r\n this.dropElement.appendChild(newChild);\r\n\r\n // Hover sets active item\r\n newChildLink.addEventListener(\"mouseenter\", (event) => {\r\n // Don't trigger enter if using arrows\r\n if (this.keyboardNavigation) {\r\n return;\r\n }\r\n this.removeActiveSelection();\r\n newChild.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n });\r\n // Moving the mouse means no longer using keyboard\r\n newChildLink.addEventListener(\"mousemove\", (event) => {\r\n this.keyboardNavigation = false;\r\n });\r\n\r\n newChildLink.addEventListener(\"mousedown\", (event) => {\r\n // Otherwise searchInput would lose focus and close the menu\r\n event.preventDefault();\r\n });\r\n newChildLink.addEventListener(\"click\", (event) => {\r\n event.preventDefault();\r\n this.addItem(newChildLink.innerText, newChildLink.getAttribute(VALUE_ATTRIBUTE), newChildLink.dataset);\r\n this.resetSearchInput();\r\n this.hideSuggestions();\r\n });\r\n }\r\n }\r\n\r\n reset() {\r\n this.removeAll();\r\n let initialValues = this.selectElement.querySelectorAll(\"option[data-init]\");\r\n for (let j = 0; j < initialValues.length; j++) {\r\n let initialValue = initialValues[j];\r\n this.addItem(initialValue.innerText, initialValue.value);\r\n }\r\n }\r\n\r\n resetSearchInput() {\r\n this.searchInput.value = \"\";\r\n this.adjustWidth();\r\n }\r\n\r\n /**\r\n * @returns {array}\r\n */\r\n getSelectedValues() {\r\n let selected = this.selectElement.querySelectorAll(\"option:checked\");\r\n return Array.from(selected).map((el) => el.value);\r\n }\r\n\r\n /**\r\n * The element create with buildSuggestions\r\n */\r\n showSuggestions() {\r\n if (!this.dropElement.classList.contains(\"show\")) {\r\n this.dropElement.classList.add(\"show\");\r\n }\r\n\r\n // Position next to search input\r\n this.dropElement.style.left = this.searchInput.offsetLeft + \"px\";\r\n\r\n // Get search value\r\n let search = this.searchInput.value.toLocaleLowerCase();\r\n\r\n // Get current values\r\n let values = this.getSelectedValues();\r\n\r\n // Filter the list according to search string\r\n let list = this.dropElement.querySelectorAll(\"li\");\r\n let found = false;\r\n let firstItem = null;\r\n let hasPossibleValues = false;\r\n for (let i = 0; i < list.length; i++) {\r\n let item = list[i];\r\n let text = item.innerText.toLocaleLowerCase();\r\n let link = item.querySelector(\"a\");\r\n\r\n // Remove previous selection\r\n link.classList.remove(...ACTIVE_CLASSES);\r\n\r\n // Hide selected values\r\n if (values.indexOf(link.getAttribute(VALUE_ATTRIBUTE)) != -1) {\r\n item.style.display = \"none\";\r\n continue;\r\n }\r\n\r\n hasPossibleValues = true;\r\n\r\n // Check search length since we can trigger dropdown with arrow\r\n let isMatched = search.length === 0 || text.indexOf(search) !== -1;\r\n if (this.showAllSuggestions || this.suggestionsThreshold === 0 || isMatched) {\r\n item.style.display = \"list-item\";\r\n found = true;\r\n if (!firstItem && isMatched) {\r\n firstItem = item;\r\n }\r\n } else {\r\n item.style.display = \"none\";\r\n }\r\n }\r\n\r\n // Special case if nothing matches\r\n if (!found) {\r\n this.dropElement.classList.remove(\"show\");\r\n }\r\n\r\n // Always select first item\r\n if (firstItem) {\r\n if (this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n firstItem.querySelector(\"a\").classList.add(...ACTIVE_CLASSES);\r\n firstItem.parentNode.scrollTop = firstItem.offsetTop - firstItem.parentNode.offsetTop;\r\n } else {\r\n // No item and we don't allow new items => error\r\n if (!this.allowNew && !(search.length === 0 && !hasPossibleValues)) {\r\n this.holderElement.classList.add(\"is-invalid\");\r\n } else if (this.validationRegex && this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * The element create with buildSuggestions\r\n */\r\n hideSuggestions() {\r\n if (this.dropElement.classList.contains(\"show\")) {\r\n this.dropElement.classList.remove(\"show\");\r\n }\r\n if (this.holderElement.classList.contains(\"is-invalid\")) {\r\n this.holderElement.classList.remove(\"is-invalid\");\r\n }\r\n }\r\n\r\n /**\r\n * @returns {HTMLElement}\r\n */\r\n getActiveSelection() {\r\n return this.dropElement.querySelector(\"a.\" + ACTIVE_CLASS);\r\n }\r\n\r\n removeActiveSelection() {\r\n let selection = this.getActiveSelection();\r\n if (selection) {\r\n selection.classList.remove(...ACTIVE_CLASSES);\r\n }\r\n }\r\n\r\n removeAll() {\r\n let items = this.containerElement.querySelectorAll(\"span\");\r\n items.forEach((item) => {\r\n this.removeLastItem();\r\n });\r\n }\r\n\r\n removeLastItem() {\r\n let items = this.containerElement.querySelectorAll(\"span\");\r\n if (!items.length) {\r\n return;\r\n }\r\n let lastItem = items[items.length - 1];\r\n this.removeItem(lastItem.getAttribute(VALUE_ATTRIBUTE));\r\n }\r\n\r\n /**\r\n * @returns {Number}\r\n */\r\n getBootstrapVersion() {\r\n let ver = 5;\r\n // If we have jQuery and the tooltip plugin for BS4\r\n if (window.jQuery && $.fn.tooltip != undefined && $.fn.tooltip.Constructor != undefined) {\r\n ver = parseInt($.fn.tooltip.Constructor.VERSION.charAt(0));\r\n }\r\n return ver;\r\n }\r\n\r\n /**\r\n * Find if label is already selected (based on attribute)\r\n * @param {string} text\r\n * @returns {boolean}\r\n */\r\n isSelected(text) {\r\n const opt = Array.from(this.selectElement.querySelectorAll(\"option\")).find((el) => el.textContent == text);\r\n if (opt && opt.getAttribute(\"selected\")) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Checks if value matches a configured regex\r\n * @param {string} value\r\n * @returns {boolean}\r\n */\r\n validateRegex(value) {\r\n const regex = new RegExp(this.validationRegex.trim());\r\n return regex.test(value);\r\n }\r\n\r\n /**\r\n * @param {string} text\r\n * @param {string} value\r\n * @param {object} data\r\n * @return {boolean}\r\n */\r\n addItem(text, value = null, data = {}) {\r\n if (!value) {\r\n value = text;\r\n }\r\n\r\n if (this.validationRegex && !this.validateRegex(text)) {\r\n this.holderElement.classList.add(\"is-invalid\");\r\n return false;\r\n }\r\n\r\n const bver = this.getBootstrapVersion();\r\n let opt = this.selectElement.querySelector('option[value=\"' + value + '\"]');\r\n if (opt) {\r\n data = opt.dataset;\r\n }\r\n\r\n // create span\r\n let html = text;\r\n let span = document.createElement(\"span\");\r\n let badgeStyle = this.badgeStyle;\r\n span.classList.add(\"badge\");\r\n if (data.badgeStyle) {\r\n badgeStyle = data.badgeStyle;\r\n }\r\n if (data.badgeClass) {\r\n span.classList.add(data.badgeClass);\r\n }\r\n if (bver === 5) {\r\n //https://getbootstrap.com/docs/5.1/components/badge/\r\n span.classList.add(\"bg-\" + badgeStyle);\r\n span.classList.add(\"me-2\");\r\n } else {\r\n // https://getbootstrap.com/docs/4.6/components/badge/\r\n span.classList.add(\"badge-\" + badgeStyle);\r\n span.classList.add(\"mr-2\");\r\n }\r\n span.setAttribute(VALUE_ATTRIBUTE, value);\r\n\r\n if (this.allowClear) {\r\n const btn =\r\n bver === 5\r\n ? ''\r\n : '';\r\n html = btn + html;\r\n }\r\n\r\n span.innerHTML = html;\r\n this.containerElement.insertBefore(span, this.searchInput);\r\n\r\n if (this.allowClear) {\r\n span.querySelector(\"button\").addEventListener(\"click\", (event) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.removeItem(value);\r\n document.activeElement.blur();\r\n });\r\n }\r\n\r\n // update select, we need to set attribute for isSelected\r\n if (opt) {\r\n opt.setAttribute(\"selected\", \"selected\");\r\n } else {\r\n // we need to create a new option\r\n opt = document.createElement(\"option\");\r\n opt.value = value;\r\n opt.innerText = text;\r\n // Pass along data provided\r\n for (const [key, value] of Object.entries(data)) {\r\n opt.dataset[key] = value;\r\n }\r\n opt.setAttribute(\"selected\", \"selected\");\r\n this.selectElement.appendChild(opt);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * @param {string} value\r\n */\r\n removeItem(value) {\r\n let item = this.containerElement.querySelector(\"span[\" + VALUE_ATTRIBUTE + '=\"' + value + '\"]');\r\n if (!item) {\r\n return;\r\n }\r\n item.remove();\r\n\r\n // update select\r\n let opt = this.selectElement.querySelector('option[value=\"' + value + '\"]');\r\n if (opt) {\r\n opt.removeAttribute(\"selected\");\r\n }\r\n }\r\n}\r\n\r\nexport default Tags;\r\n"], + "mappings": "AAaA,GAAM,GAAe,YACf,EAAiB,CAAC,YAAa,aAAc,cAC7C,EAAkB,aAExB,OAAW,CAKT,YAAY,EAAe,EAAO,GAAI,CAiBpC,IAhBA,KAAK,cAAgB,EACrB,KAAK,cAAc,MAAM,QAAU,OACnC,KAAK,YAAc,KAAK,iBACxB,KAAK,SAAW,IAAc,QAAQ,SACtC,KAAK,mBAAqB,IAAc,QAAQ,mBAChD,KAAK,WAAa,EAAc,QAAQ,YAAc,UACtD,KAAK,WAAa,IAAc,QAAQ,WACxC,KAAK,OAAS,EAAc,QAAQ,QAAU,GAC9C,KAAK,WAAa,IAAc,QAAQ,WACxC,KAAK,qBAAuB,EAAc,QAAQ,qBAAuB,SAAS,EAAc,QAAQ,sBAAwB,EAChI,KAAK,gBAAkB,EAAc,QAAQ,OAAS,GACtD,KAAK,mBAAqB,GAC1B,KAAK,WAAa,EAAK,YAAc,QACrC,KAAK,YAAc,EAAK,aAAe,eAEvC,KAAK,WAAa,EAAc,cACzB,KAAK,YACV,MAAK,WAAa,KAAK,WAAW,cAC9B,KAAK,WAAW,UAAY,SAAhC,CA0BF,GAtBA,KAAK,WAAW,iBAAiB,QAAS,AAAC,GAAO,CAChD,KAAK,UAIP,KAAK,cAAgB,SAAS,cAAc,OAC5C,KAAK,iBAAmB,SAAS,cAAc,OAC/C,KAAK,YAAc,SAAS,cAAc,MAC1C,KAAK,YAAc,SAAS,cAAc,SAE1C,KAAK,cAAc,YAAY,KAAK,kBACpC,KAAK,iBAAiB,YAAY,KAAK,aACvC,KAAK,cAAc,YAAY,KAAK,aAEpC,KAAK,cAAc,WAAW,aAAa,KAAK,cAAe,KAAK,cAAc,aAGlF,KAAK,uBACL,KAAK,yBACL,KAAK,uBACL,KAAK,4BAED,KAAK,QAAU,CAAC,KAAK,WACvB,KAAK,qBACA,CACL,GAAI,GAAc,MAAM,KAAK,KAAK,cAAc,iBAAiB,WAAW,IAAI,AAAC,GACxE,EACL,MAAO,EAAO,aAAa,SAC3B,MAAO,EAAO,aAGlB,KAAK,iBAAiB,UASnB,MAAK,EAAW,mBAAoB,EAAO,GAAI,CACpD,GAAI,GAAO,SAAS,iBAAiB,GACrC,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAK,EAAK,GACV,EAAO,GAAI,GAAK,EAAI,IAO5B,eAAe,EAAO,GAAO,CAC3B,AAAI,KAAK,iBACP,KAAK,gBAAgB,QAEvB,KAAK,gBAAkB,GAAI,iBAC3B,MAAM,KAAK,OAAS,UAAY,mBAAmB,KAAK,YAAY,OAAQ,CAAE,OAAQ,KAAK,gBAAgB,SACxG,KAAK,AAAC,GAAM,EAAE,QACd,KAAK,AAAC,GAAgB,CACrB,GAAI,GAAO,EAAY,MAAQ,EAC/B,KAAK,iBAAiB,GACtB,KAAK,gBAAkB,KACnB,GACF,KAAK,oBAGR,MAAM,AAAC,GAAM,CACZ,AAAI,EAAE,OAAS,cAGf,QAAQ,MAAM,KAOpB,gBAAiB,CACf,GAAI,GAAc,KAAK,cAAc,cAAc,UACnD,GAAI,EAAC,EAGL,IAAI,CAAC,EAAY,MAAO,CACtB,GAAI,GAAc,EAAY,UAC9B,SAAY,SACL,EAET,MAAI,MAAK,cAAc,aAAa,eAC3B,KAAK,cAAc,aAAa,eAErC,KAAK,cAAc,aAAa,oBAC3B,KAAK,cAAc,aAAa,oBAElC,IAGT,sBAAuB,CACrB,KAAK,YAAY,UAAU,IAAI,iBAC/B,KAAK,YAAY,UAAU,IAAI,OAC/B,KAAK,YAAY,MAAM,UAAY,QACnC,KAAK,YAAY,MAAM,UAAY,OAGnC,KAAK,YAAY,iBAAiB,aAAc,AAAC,GAAU,CACzD,KAAK,mBAAqB,KAI9B,wBAAyB,CACvB,KAAK,cAAc,UAAU,IAAI,gBACjC,KAAK,cAAc,UAAU,IAAI,YAC7B,KAAK,wBAA0B,GAEjC,MAAK,cAAc,MAAM,OAAS,QAItC,2BAA4B,CAC1B,KAAK,iBAAiB,iBAAiB,QAAS,AAAC,GAAU,CACzD,KAAK,YAAY,UAInB,GAAI,GAAgB,KAAK,cAAc,iBAAiB,oBACxD,OAAS,GAAI,EAAG,EAAI,EAAc,OAAQ,IAAK,CAC7C,GAAI,GAAe,EAAc,GACjC,AAAI,CAAC,EAAa,OAGlB,GAAa,QAAQ,KAAO,EAC5B,KAAK,QAAQ,EAAa,UAAW,EAAa,SAItD,sBAAuB,CACrB,GAAI,GAAO,KACX,KAAK,YAAY,KAAO,OACxB,KAAK,YAAY,aAAe,MAChC,KAAK,YAAY,MAAM,OAAS,EAChC,KAAK,YAAY,MAAM,QAAU,EACjC,KAAK,YAAY,MAAM,SAAW,OAClC,KAAK,YAAY,UAAY,KAAK,YAElC,KAAK,cAEL,KAAK,YAAY,iBAAiB,QAAS,AAAC,GAAU,CACpD,KAAK,cACL,AAAI,KAAK,YAAY,MAAM,QAAU,KAAK,qBACxC,AAAI,KAAK,WACP,KAAK,eAAe,IAEpB,KAAK,kBAGP,KAAK,oBAGT,KAAK,YAAY,iBAAiB,QAAS,AAAC,GAAU,CACpD,AAAI,KAAK,YAAY,MAAM,QAAU,KAAK,sBACxC,KAAK,oBAGT,KAAK,YAAY,iBAAiB,WAAY,AAAC,GAAU,CACvD,EAAK,oBAGP,KAAK,YAAY,iBAAiB,UAAW,AAAC,GAAU,CAGtD,OADU,EAAM,SAAW,EAAM,SAE1B,QACA,QACH,GAAI,GAAY,KAAK,qBACrB,AAAI,EACF,EAAU,QAGN,KAAK,UAAY,CAAC,KAAK,WAAW,KAAK,YAAY,QAC3C,KAAK,QAAQ,KAAK,YAAY,MAAO,OAE7C,MAAK,mBACL,KAAK,mBAIX,EAAM,iBACN,UACG,QACA,UACH,EAAM,iBACN,KAAK,mBAAqB,GAC1B,GAAI,GAAe,KAAK,kBAExB,AAAI,KAAK,YAAY,MAAM,QAAU,GAAK,KAAK,YAAY,UAAU,SAAS,SAAW,CAAC,GACxF,KAAK,kBAEP,UACG,QACA,YACH,EAAM,iBACN,KAAK,mBAAqB,GAC1B,KAAK,oBAED,KAAK,YAAY,MAAM,QAAU,GAAK,CAAC,KAAK,YAAY,UAAU,SAAS,SAC7E,KAAK,kBAEP,UACG,OACA,YACH,AAAI,KAAK,YAAY,MAAM,QAAU,GACnC,MAAK,iBACL,KAAK,cACL,KAAK,mBAEP,SAQR,iBAAkB,CAChB,GAAI,GAAS,KAAK,qBAClB,GAAI,EAAQ,CACV,GAAI,GAAO,EAAO,WAClB,EACE,GAAO,EAAK,sBACL,GAAQ,EAAK,MAAM,SAAW,QACvC,MAAK,GAGL,GAAO,UAAU,OAAO,GAAG,GAC3B,EAAK,cAAc,KAAK,UAAU,IAAI,GAAG,GAEzC,EAAK,WAAW,UAAY,EAAK,UAAY,EAAK,WAAW,UACtD,GANE,KAQX,MAAO,MAMT,mBAAoB,CAClB,GAAI,GAAS,KAAK,qBAClB,GAAI,EAAQ,CACV,GAAI,GAAO,EAAO,WAClB,EACE,GAAO,EAAK,kBACL,GAAQ,EAAK,MAAM,SAAW,QACvC,MAAK,GAGL,GAAO,UAAU,OAAO,GAAG,GAC3B,EAAK,cAAc,KAAK,UAAU,IAAI,GAAG,GAErC,EAAK,UAAY,EAAK,WAAW,aAAe,EAAK,cACvD,GAAK,WAAW,WAAa,EAAK,cAE7B,GARE,KAUX,MAAO,MAMT,aAAc,CACZ,AAAI,KAAK,YAAY,MACnB,KAAK,YAAY,KAAO,KAAK,YAAY,MAAM,OAAS,EAGxD,AAAI,KAAK,oBAAoB,OAC3B,MAAK,YAAY,YAAc,GAC/B,KAAK,YAAY,KAAO,GAExB,MAAK,YAAY,KAAO,KAAK,YAAY,OACzC,KAAK,YAAY,YAAc,KAAK,aAS1C,iBAAiB,EAAc,KAAM,CACnC,KAAO,KAAK,YAAY,WACtB,KAAK,YAAY,YAAY,KAAK,YAAY,WAEhD,OAAS,GAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,GAAI,GAAa,EAAY,GAC7B,GAAI,CAAC,EAAW,MACd,SAEF,GAAI,GAAW,SAAS,cAAc,MAClC,EAAe,SAAS,cAAc,KAM1C,GALA,EAAS,OAAO,GAChB,EAAa,UAAU,IAAI,iBAC3B,EAAa,aAAa,EAAiB,EAAW,OACtD,EAAa,aAAa,OAAQ,KAClC,EAAa,UAAY,EAAW,MAChC,EAAW,KACb,OAAW,CAAC,EAAK,IAAU,QAAO,QAAQ,EAAW,MACnD,EAAa,QAAQ,GAAO,EAGhC,KAAK,YAAY,YAAY,GAG7B,EAAa,iBAAiB,aAAc,AAAC,GAAU,CAErD,AAAI,KAAK,oBAGT,MAAK,wBACL,EAAS,cAAc,KAAK,UAAU,IAAI,GAAG,MAG/C,EAAa,iBAAiB,YAAa,AAAC,GAAU,CACpD,KAAK,mBAAqB,KAG5B,EAAa,iBAAiB,YAAa,AAAC,GAAU,CAEpD,EAAM,mBAER,EAAa,iBAAiB,QAAS,AAAC,GAAU,CAChD,EAAM,iBACN,KAAK,QAAQ,EAAa,UAAW,EAAa,aAAa,GAAkB,EAAa,SAC9F,KAAK,mBACL,KAAK,qBAKX,OAAQ,CACN,KAAK,YACL,GAAI,GAAgB,KAAK,cAAc,iBAAiB,qBACxD,OAAS,GAAI,EAAG,EAAI,EAAc,OAAQ,IAAK,CAC7C,GAAI,GAAe,EAAc,GACjC,KAAK,QAAQ,EAAa,UAAW,EAAa,QAItD,kBAAmB,CACjB,KAAK,YAAY,MAAQ,GACzB,KAAK,cAMP,mBAAoB,CAClB,GAAI,GAAW,KAAK,cAAc,iBAAiB,kBACnD,MAAO,OAAM,KAAK,GAAU,IAAI,AAAC,GAAO,EAAG,OAM7C,iBAAkB,CAChB,AAAK,KAAK,YAAY,UAAU,SAAS,SACvC,KAAK,YAAY,UAAU,IAAI,QAIjC,KAAK,YAAY,MAAM,KAAO,KAAK,YAAY,WAAa,KAG5D,GAAI,GAAS,KAAK,YAAY,MAAM,oBAGhC,EAAS,KAAK,oBAGd,EAAO,KAAK,YAAY,iBAAiB,MACzC,EAAQ,GACR,EAAY,KACZ,EAAoB,GACxB,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAO,EAAK,GACZ,EAAO,EAAK,UAAU,oBACtB,EAAO,EAAK,cAAc,KAM9B,GAHA,EAAK,UAAU,OAAO,GAAG,GAGrB,EAAO,QAAQ,EAAK,aAAa,KAAqB,GAAI,CAC5D,EAAK,MAAM,QAAU,OACrB,SAGF,EAAoB,GAGpB,GAAI,GAAY,EAAO,SAAW,GAAK,EAAK,QAAQ,KAAY,GAChE,AAAI,KAAK,oBAAsB,KAAK,uBAAyB,GAAK,EAChE,GAAK,MAAM,QAAU,YACrB,EAAQ,GACJ,CAAC,GAAa,GAChB,GAAY,IAGd,EAAK,MAAM,QAAU,OAKzB,AAAK,GACH,KAAK,YAAY,UAAU,OAAO,QAIpC,AAAI,EACE,MAAK,cAAc,UAAU,SAAS,eACxC,KAAK,cAAc,UAAU,OAAO,cAEtC,EAAU,cAAc,KAAK,UAAU,IAAI,GAAG,GAC9C,EAAU,WAAW,UAAY,EAAU,UAAY,EAAU,WAAW,WAG5E,AAAI,CAAC,KAAK,UAAY,CAAE,GAAO,SAAW,GAAK,CAAC,GAC9C,KAAK,cAAc,UAAU,IAAI,cACxB,KAAK,iBAAmB,KAAK,cAAc,UAAU,SAAS,eACvE,KAAK,cAAc,UAAU,OAAO,cAQ1C,iBAAkB,CAChB,AAAI,KAAK,YAAY,UAAU,SAAS,SACtC,KAAK,YAAY,UAAU,OAAO,QAEhC,KAAK,cAAc,UAAU,SAAS,eACxC,KAAK,cAAc,UAAU,OAAO,cAOxC,oBAAqB,CACnB,MAAO,MAAK,YAAY,cAAc,KAAO,GAG/C,uBAAwB,CACtB,GAAI,GAAY,KAAK,qBACrB,AAAI,GACF,EAAU,UAAU,OAAO,GAAG,GAIlC,WAAY,CAEV,AADY,KAAK,iBAAiB,iBAAiB,QAC7C,QAAQ,AAAC,GAAS,CACtB,KAAK,mBAIT,gBAAiB,CACf,GAAI,GAAQ,KAAK,iBAAiB,iBAAiB,QACnD,GAAI,CAAC,EAAM,OACT,OAEF,GAAI,GAAW,EAAM,EAAM,OAAS,GACpC,KAAK,WAAW,EAAS,aAAa,IAMxC,qBAAsB,CACpB,GAAI,GAAM,EAEV,MAAI,QAAO,QAAU,EAAE,GAAG,SAAW,MAAa,EAAE,GAAG,QAAQ,aAAe,MAC5E,GAAM,SAAS,EAAE,GAAG,QAAQ,YAAY,QAAQ,OAAO,KAElD,EAQT,WAAW,EAAM,CACf,GAAM,GAAM,MAAM,KAAK,KAAK,cAAc,iBAAiB,WAAW,KAAK,AAAC,GAAO,EAAG,aAAe,GACrG,MAAI,MAAO,EAAI,aAAa,aAW9B,cAAc,EAAO,CAEnB,MAAO,AADO,IAAI,QAAO,KAAK,gBAAgB,QACjC,KAAK,GASpB,QAAQ,EAAM,EAAQ,KAAM,EAAO,GAAI,CAKrC,GAJK,GACH,GAAQ,GAGN,KAAK,iBAAmB,CAAC,KAAK,cAAc,GAC9C,YAAK,cAAc,UAAU,IAAI,cAC1B,GAGT,GAAM,GAAO,KAAK,sBACd,EAAM,KAAK,cAAc,cAAc,iBAAmB,EAAQ,MACtE,AAAI,GACF,GAAO,EAAI,SAIb,GAAI,GAAO,EACP,EAAO,SAAS,cAAc,QAC9B,EAAa,KAAK,WAwCtB,GAvCA,EAAK,UAAU,IAAI,SACf,EAAK,YACP,GAAa,EAAK,YAEhB,EAAK,YACP,EAAK,UAAU,IAAI,EAAK,YAE1B,AAAI,IAAS,EAEX,GAAK,UAAU,IAAI,MAAQ,GAC3B,EAAK,UAAU,IAAI,SAGnB,GAAK,UAAU,IAAI,SAAW,GAC9B,EAAK,UAAU,IAAI,SAErB,EAAK,aAAa,EAAiB,GAE/B,KAAK,YAKP,GAAO,AAHL,KAAS,EACL,qGAAuG,KAAK,WAAa,cACzH,8HAAgI,KAAK,WAAa,sDAC3I,GAGf,EAAK,UAAY,EACjB,KAAK,iBAAiB,aAAa,EAAM,KAAK,aAE1C,KAAK,YACP,EAAK,cAAc,UAAU,iBAAiB,QAAS,AAAC,GAAU,CAChE,EAAM,iBACN,EAAM,kBACN,KAAK,WAAW,GAChB,SAAS,cAAc,SAKvB,EACF,EAAI,aAAa,WAAY,gBACxB,CAEL,EAAM,SAAS,cAAc,UAC7B,EAAI,MAAQ,EACZ,EAAI,UAAY,EAEhB,OAAW,CAAC,EAAK,IAAU,QAAO,QAAQ,GACxC,EAAI,QAAQ,GAAO,EAErB,EAAI,aAAa,WAAY,YAC7B,KAAK,cAAc,YAAY,GAGjC,MAAO,GAMT,WAAW,EAAO,CAChB,GAAI,GAAO,KAAK,iBAAiB,cAAc,QAAU,EAAkB,KAAO,EAAQ,MAC1F,GAAI,CAAC,EACH,OAEF,EAAK,SAGL,GAAI,GAAM,KAAK,cAAc,cAAc,iBAAmB,EAAQ,MACtE,AAAI,GACF,EAAI,gBAAgB,cAKnB,EAAQ", "names": [] }