slim-select 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{helper.d.ts → helpers.d.ts} +0 -0
- package/dist/index.d.ts +1 -7
- package/dist/render.d.ts +1 -1
- package/dist/settings.d.ts +1 -1
- package/dist/slimselect.cjs.js +1589 -2
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +1587 -2
- package/dist/slimselect.global.js +1592 -2
- package/dist/slimselect.js +1595 -2
- package/dist/slimselect.min.js +1 -0
- package/dist/slimselect.umd.js +1595 -2
- package/dist/slimselect.umd.min.js +1 -0
- package/dist/store.d.ts +5 -5
- package/docs/404.html +18 -12
- package/docs/assets/home.js +1 -1
- package/docs/assets/index.css +1 -1
- package/docs/assets/index.js +7 -7
- package/docs/assets/index3.js +25 -16
- package/docs/assets/index5.js +147 -0
- package/docs/assets/install.js +6 -6
- package/docs/index.html +20 -2
- package/index.html +20 -2
- package/package.json +17 -6
- package/public/404.html +18 -12
- package/src/docs/app.vue +10 -4
- package/{docs → src/docs/assets}/images/check-mark.svg +0 -0
- package/{docs → src/docs/assets}/images/chrome.svg +0 -0
- package/{docs → src/docs/assets}/images/firefox.svg +0 -0
- package/{docs → src/docs/assets}/images/github.png +0 -0
- package/{docs → src/docs/assets}/images/ie.svg +0 -0
- package/{docs → src/docs/assets}/images/npm.png +0 -0
- package/{docs → src/docs/assets}/images/opera.svg +0 -0
- package/{docs → src/docs/assets}/images/safari.svg +0 -0
- package/src/docs/assets/scss/_variables.scss +1 -1
- package/src/docs/assets/scss/misc.scss +7 -0
- package/src/docs/env.d.ts +1 -0
- package/src/docs/pages/events/addable.vue +22 -6
- package/src/docs/pages/events/before_after_change.vue +15 -1
- package/src/docs/pages/events/search.vue +2 -1
- package/src/docs/pages/frameworks/index.vue +18 -0
- package/src/docs/pages/frameworks/vue.vue +405 -0
- package/src/docs/pages/home.vue +19 -19
- package/src/docs/pages/install.vue +27 -6
- package/src/docs/pages/methods/get_data.vue +2 -1
- package/src/docs/pages/methods/open_close.vue +1 -1
- package/src/docs/router.ts +5 -0
- package/src/slim-select/{helper.ts → helpers.ts} +0 -0
- package/src/slim-select/index.ts +2 -12
- package/src/slim-select/render.ts +84 -26
- package/src/slim-select/rollup.config.mjs +117 -30
- package/src/slim-select/select.ts +15 -6
- package/src/slim-select/settings.ts +1 -1
- package/src/slim-select/slimselect.scss +7 -0
- package/src/slim-select/store.ts +1 -1
- package/src/vue/dist/slimselectvue.es.js +1655 -0
- package/src/vue/dist/slimselectvue.global.js +1658 -0
- package/src/vue/dist/slimselectvue.ssr.js +1657 -0
- package/src/vue/hello.ts +5 -0
- package/src/vue/package.json +27 -0
- package/src/vue/rollup.config.mjs +44 -0
- package/src/vue/slimselect.vue +59 -43
- package/src/vue/tsconfig.json +14 -0
- package/dist/slimselect.cjs.js.map +0 -1
- package/dist/slimselect.es.js.map +0 -1
- package/dist/slimselect.global.js.map +0 -1
- package/dist/slimselect.js.map +0 -1
- package/dist/slimselect.umd.js.map +0 -1
- package/public/images/check-mark.svg +0 -6
- package/public/images/chrome.svg +0 -22
- package/public/images/firefox.svg +0 -58
- package/public/images/github.png +0 -0
- package/public/images/ie.svg +0 -11
- package/public/images/npm.png +0 -0
- package/public/images/opera.svg +0 -15
- package/public/images/safari.svg +0 -22
- package/public/index.html +0 -28
- package/src/docs/images/check-mark.svg +0 -6
- package/src/docs/images/chrome.svg +0 -22
- package/src/docs/images/firefox.svg +0 -58
- package/src/docs/images/github.png +0 -0
- package/src/docs/images/ie.svg +0 -11
- package/src/docs/images/npm.png +0 -0
- package/src/docs/images/opera.svg +0 -15
- package/src/docs/images/safari.svg +0 -22
package/dist/slimselect.js
CHANGED
|
@@ -1,2 +1,1595 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).SlimSelect={})}(this,(function(e){"use strict";function t(){return Math.random().toString(36).substring(2,10)}function s(e,t){function s(e,s){return s&&e&&e.classList&&e.classList.contains(s)||s&&e&&e.dataset&&e.dataset.id&&e.dataset.id===t?e:null}return s(e,t)||function e(t,i){return t&&t!==document?s(t,i)?t:e(t.parentNode,i):null}(e,t)}function i(e,t=50,s=!1){let i;return function(...n){const a=self,l=s&&!i;clearTimeout(i),i=setTimeout((()=>{i=null,s||e.apply(a,n)}),t),l&&e.apply(a,n)}}function n(e){const t=e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase()));return e[0]===e[0].toUpperCase()?t.substring(1):t}class a{constructor(e){if(this.id=e.id&&""!==e.id?e.id:t(),this.label=e.label||"",this.options=[],e.options)for(const t of e.options)this.options.push(new l(t))}}class l{constructor(e){this.id=e.id&&""!==e.id?e.id:t(),this.value=void 0===e.value?e.text:e.value,this.text=e.text||"",this.html=e.html||"",this.selected=void 0!==e.selected&&e.selected,this.display=void 0===e.display||e.display,this.disabled=void 0!==e.disabled&&e.disabled,this.mandatory=void 0!==e.mandatory&&e.mandatory,this.placeholder=void 0!==e.placeholder&&e.placeholder,this.class=e.class||"",this.style=e.style||"",this.data=e.data||{}}}class o{constructor(e,t){this.selectType="single",this.data=[],this.selectType=e,this.setData(t)}validateDataArray(e){if(!Array.isArray(e))return new Error("Data must be an array");for(let t of e){if(!(t instanceof a||"label"in t))return t instanceof l||"text"in t?this.validateOption(t):new Error("Data object must be a valid optgroup or option");if(!("label"in t))return new Error("Optgroup must have a label");if("options"in t&&t.options)for(let e of t.options)return this.validateOption(e)}return null}validateOption(e){return"text"in e?null:new Error("Option must have a text")}partialToFullData(e){let t=[];return e.forEach((e=>{if(e instanceof a||"label"in e){let s=[];"options"in e&&e.options&&e.options.forEach((e=>{s.push(new l(e))})),s.length>0&&t.push(new a(e))}(e instanceof l||"text"in e)&&t.push(new l(e))})),t}setData(e){this.data=this.partialToFullData(e),"single"===this.selectType&&this.setSelectedBy("value",this.getSelected())}getData(){return this.filter(null,!0)}getDataOptions(){return this.filter(null,!1)}addOption(e){this.setData(this.getData().concat(new l(e)))}setSelectedBy(e,t){let s=null,i=!1;for(let n of this.data){if(n instanceof a)for(let a of n.options)s||(s=a),a.selected=!i&&t.includes(a[e]),a.selected&&"single"===this.selectType&&(i=!0);n instanceof l&&(s||(s=n),n.selected=!i&&t.includes(n[e]),n.selected&&"single"===this.selectType&&(i=!0))}"single"===this.selectType&&s&&!i&&(s.selected=!0)}getSelected(){let e=this.getSelectedOptions(),t=[];return e.forEach((e=>{t.push(e.value)})),t}getSelectedOptions(){return this.filter((e=>e.selected),!1)}getSelectedIDs(){let e=this.getSelectedOptions(),t=[];return e.forEach((e=>{t.push(e.id)})),t}getOptionByID(e){let t=this.filter((t=>t.id===e),!1);return t.length?t[0]:null}search(e,t){return""===(e=e.trim())?this.getData():this.filter((s=>t(s,e)),!0)}filter(e,t){const s=[];return this.data.forEach((i=>{if(i instanceof a)if(t){let t=[];i.options.forEach((s=>{e&&!e(s)||t.push(new l(s))})),t.length>0&&s.push(new a({id:i.id,label:i.label,options:t}))}else i.options.forEach((t=>{e&&e(t)&&s.push(t)}));i instanceof l&&(e&&!e(i)||s.push(new l(i)))})),s}}class h{constructor(e,t,s){this.classes={main:"ss-main",placeholder:"ss-placeholder",values:"ss-values",single:"ss-single",value:"ss-value",valueText:"ss-value-text",valueDelete:"ss-value-delete",valueOut:"ss-value-out",deselect:"ss-deselect",deselectPath:"M10,10 L90,90 M10,90 L90,10",arrow:"ss-arrow",arrowClose:"M10,30 L50,70 L90,30",arrowOpen:"M10,70 L50,30 L90,70",content:"ss-content",openAbove:"ss-open-above",openBelow:"ss-open-below",search:"ss-search",searchHighlighter:"ss-search-highlight",searching:"ss-searching",addable:"ss-addable",addablePath:"M50,10 L50,90 M10,50 L90,50",list:"ss-list",optgroup:"ss-optgroup",optgroupLabel:"ss-optgroup-label",optgroupSelectable:"ss-optgroup-selectable",option:"ss-option",optionSelected:"ss-option-selected",optionDelete:"M10,10 L90,90 M10,90 L90,10",highlighted:"ss-highlighted",error:"ss-error",disabled:"ss-disabled",hide:"ss-hide"},this.store=t,this.settings=e,this.callbacks=s,this.main=this.mainDiv(),this.content=this.contentDiv(),this.renderValues(),this.renderOptions(this.store.getData()),this.settings.contentLocation.appendChild(this.content.main)}enable(){this.main.main.classList.remove(this.classes.disabled),this.content.search.input.disabled=!1}disable(){this.main.main.classList.add(this.classes.disabled),this.content.search.input.disabled=!0}open(){this.main.arrow.path.setAttribute("d",this.classes.arrowOpen),this.main.main.classList.add("up"===this.settings.openPosition?this.classes.openAbove:this.classes.openBelow),this.moveContent(),this.renderOptions(this.store.getData()),"relative"===this.settings.contentPosition?this.moveContentBelow():"up"===this.settings.openPosition.toLowerCase()?this.moveContentAbove():"down"===this.settings.openPosition.toLowerCase()?this.moveContentBelow():"up"===this.putContent(this.content.main,this.settings.isOpen)?this.moveContentAbove():this.moveContentBelow();const e=this.store.getSelectedOptions();if(e.length){const t=e[e.length-1].id,s=this.content.list.querySelector('[data-id="'+t+'"]');s&&this.ensureElementInView(this.content.list,s)}}close(){this.main.main.classList.remove(this.classes.openAbove),this.main.main.classList.remove(this.classes.openBelow),this.content.main.classList.remove(this.classes.openAbove),this.content.main.classList.remove(this.classes.openBelow),this.main.arrow.path.setAttribute("d",this.classes.arrowClose)}mainDiv(){const e=document.createElement("div");if(e.tabIndex=0,e.style.cssText=""!==this.settings.style?this.settings.style:"",e.className="",e.classList.add(this.settings.id),e.classList.add(this.classes.main),this.settings.class)for(const t of this.settings.class)""!==t.trim()&&e.classList.add(t.trim());e.onfocus=()=>{this.settings.triggerFocus&&this.callbacks.open()},e.onkeydown=e=>{switch(e.key){case"ArrowUp":case"ArrowDown":return this.callbacks.open(),"ArrowDown"===e.key?this.highlight("down"):this.highlight("up"),!1;case"Tab":return this.callbacks.close(),!0;case"Enter":const t=this.content.list.querySelector("."+this.classes.highlighted);return t&&t.click(),!1;case"Escape":return this.callbacks.close(),!1}},e.onclick=e=>{this.settings.isEnabled&&(this.settings.isOpen?this.callbacks.close():this.callbacks.open())};const t=document.createElement("div");t.classList.add(this.classes.values),e.appendChild(t);const s=document.createElement("div");s.classList.add(this.classes.deselect),this.settings.allowDeselect&&!this.settings.isMultiple||s.classList.add(this.classes.hide),s.onclick=e=>{e.stopPropagation(),this.settings.isEnabled&&this.callbacks.setSelected([""])};const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("viewBox","0 0 100 100");const n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("d",this.classes.deselectPath),i.appendChild(n),s.appendChild(i),e.appendChild(s);const a=document.createElementNS("http://www.w3.org/2000/svg","svg");a.classList.add(this.classes.arrow),a.setAttribute("viewBox","0 0 100 100");const l=document.createElementNS("http://www.w3.org/2000/svg","path");return l.setAttribute("d",this.classes.arrowClose),this.settings.alwaysOpen&&a.classList.add(this.classes.hide),a.appendChild(l),e.appendChild(a),{main:e,values:t,deselect:{main:s,svg:i,path:n},arrow:{main:a,path:l}}}mainFocus(e){e||(this.settings.triggerFocus=!1),this.main.main.focus({preventScroll:!0}),this.settings.triggerFocus=!0}placeholder(){const e=this.store.filter((e=>e.placeholder),!1);let t=this.settings.placeholderText;e.length&&(""!==e[0].html?t=e[0].html:""!==e[0].text&&(t=e[0].text));const s=document.createElement("div");return s.classList.add(this.classes.placeholder),s.innerHTML=t,s}renderValues(){this.settings.isMultiple?this.renderMultipleValues():this.renderSingleValue()}renderSingleValue(){const e=this.store.filter((e=>e.selected&&!e.placeholder),!1),t=e.length>0?e[0]:null;if(t){const e=document.createElement("div");e.classList.add(this.classes.single),e.innerHTML=t.html?t.html:t.text,this.main.values.innerHTML=e.outerHTML}else this.main.values.innerHTML=this.placeholder().outerHTML;this.settings.allowDeselect&&e.length?this.main.deselect.main.classList.remove(this.classes.hide):this.main.deselect.main.classList.add(this.classes.hide)}renderMultipleValues(){let e=this.main.values.childNodes,t=this.store.filter((e=>e.selected&&e.display),!1);if(0===t.length)return void(this.main.values.innerHTML=this.placeholder().outerHTML);{const e=this.main.values.querySelector("."+this.classes.placeholder);e&&e.remove()}let s=[];for(let i=0;i<e.length;i++){const n=e[i],a=n.getAttribute("data-id");if(a){t.filter((e=>e.id===a),!1).length||s.push(n)}}for(const e of s)e.classList.add(this.classes.valueOut),setTimeout((()=>{this.main.values.removeChild(e)}),100);e=this.main.values.childNodes;for(let s=0;s<t.length;s++){let i=!0;for(let n=0;n<e.length;n++)t[s].id===String(e[n].dataset.id)&&(i=!1);i&&(0===e.length?this.main.values.appendChild(this.multipleValue(t[s])):0===s?this.main.values.insertBefore(this.multipleValue(t[s]),e[s]):e[s-1].insertAdjacentElement("afterend",this.multipleValue(t[s])))}}multipleValue(e){const t=document.createElement("div");t.classList.add(this.classes.value),t.dataset.id=e.id;const s=document.createElement("div");if(s.classList.add(this.classes.valueText),s.innerHTML=e.text,t.appendChild(s),!e.mandatory){const s=document.createElement("div");s.classList.add(this.classes.valueDelete),s.onclick=t=>{t.preventDefault(),t.stopPropagation();let s=!0;const i=this.store.getSelectedOptions(),n=i.filter((t=>t.selected&&t.id!==e.id),!0);if(!(this.settings.minSelected&&n.length<this.settings.minSelected)&&(this.callbacks.beforeChange&&(s=!0===this.callbacks.beforeChange(n,i)),s)){let e=[];for(const t of n){if(t instanceof a)for(const s of t.options)e.push(s.value);t instanceof l&&e.push(t.value)}this.callbacks.setSelected(e),this.settings.closeOnSelect&&this.callbacks.close(),this.callbacks.afterChange&&this.callbacks.afterChange(n)}};const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("viewBox","0 0 100 100");const n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("d",this.classes.optionDelete),i.appendChild(n),s.appendChild(i),t.appendChild(s)}return t}contentDiv(){const e=document.createElement("div");if(e.classList.add(this.classes.content),e.dataset.id=this.settings.id,""!==this.settings.style&&(e.style.cssText=this.settings.style),"relative"===this.settings.contentPosition&&e.classList.add("ss-"+this.settings.contentPosition),this.settings.class.length)for(const t of this.settings.class)""!==t.trim()&&e.classList.add(t.trim());const t=this.searchDiv();e.appendChild(t.main);const s=this.listDiv();return e.appendChild(s),{main:e,search:t,list:s}}moveContent(){if("relative"===this.settings.contentPosition)return;const e=this.main.main.getBoundingClientRect();this.content.main.style.top=e.top+e.height+window.scrollY+"px",this.content.main.style.left=e.left+window.scrollX+"px",this.content.main.style.width=e.width+"px"}searchDiv(){const e=document.createElement("div"),t=document.createElement("input"),s=document.createElement("div");e.classList.add(this.classes.search);const n={main:e,input:t};if(this.settings.showSearch||(e.classList.add(this.classes.hide),t.readOnly=!0),t.type="search",t.placeholder=this.settings.searchPlaceholder,t.tabIndex=-1,t.setAttribute("aria-label",this.settings.searchPlaceholder),t.setAttribute("autocapitalize","off"),t.setAttribute("autocomplete","off"),t.setAttribute("autocorrect","off"),t.oninput=i((e=>{this.callbacks.search(e.target.value)}),100),t.onkeydown=e=>{switch(e.key){case"ArrowUp":case"ArrowDown":return this.callbacks.open(),"ArrowDown"===e.key?this.highlight("down"):this.highlight("up"),!1;case"Tab":return this.callbacks.close(),!0;case"Escape":return this.callbacks.close(),!1;case"Enter":if(this.callbacks.addable&&e.ctrlKey)s.click();else{const e=this.content.list.querySelector("."+this.classes.highlighted);e&&e.click()}return!1}},t.onfocus=()=>{this.settings.isOpen||this.callbacks.open()},e.appendChild(t),this.callbacks.addable){s.classList.add(this.classes.addable);const t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.setAttribute("viewBox","0 0 100 100");const i=document.createElementNS("http://www.w3.org/2000/svg","path");i.setAttribute("d",this.classes.addablePath),t.appendChild(i),s.appendChild(t),s.onclick=e=>{if(e.preventDefault(),e.stopPropagation(),!this.callbacks.addable)return;const t=this.content.search.input.value.trim();if(""===t)return void this.content.search.input.focus();const s=this.callbacks.addable(t);"string"==typeof s?this.callbacks.addOption(new l({text:s,value:s})):this.callbacks.addOption(new l(s)),this.callbacks.setSelected([t]),this.callbacks.search(""),this.settings.closeOnSelect&&setTimeout((()=>{this.callbacks.close()}),100)},e.appendChild(s),n.addable={main:s,svg:t,path:i}}return n}searchFocus(e){e||(this.settings.triggerFocus=!1),this.content.search.input.focus(),this.settings.triggerFocus=!0}getOptions(e=!1,t=!1,s=!1){let i="."+this.classes.option;return e&&(i+=":not(."+this.classes.placeholder+")"),t&&(i+=":not(."+this.classes.disabled+")"),s&&(i+=":not(."+this.classes.hide+")"),Array.from(this.content.list.querySelectorAll(i))}highlight(e){const t=this.getOptions(!0,!0,!0);if(0!==t.length)if(1!==t.length||t[0].classList.contains(this.classes.highlighted)){for(let s=0;s<t.length;s++)if(t[s].classList.contains(this.classes.highlighted))return t[s].classList.remove(this.classes.highlighted),void("down"===e?s+1<t.length?(t[s+1].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t[s+1])):(t[0].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t[0])):s-1>=0?(t[s-1].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t[s-1])):(t[t.length-1].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t[t.length-1])));t["down"===e?0:t.length-1].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t["down"===e?0:t.length-1])}else t[0].classList.add(this.classes.highlighted)}listDiv(){const e=document.createElement("div");return e.classList.add(this.classes.list),e.setAttribute("role","listbox"),e}renderError(e){this.content.list.innerHTML="";const t=document.createElement("div");t.classList.add(this.classes.error),t.textContent=e,this.content.list.appendChild(t)}renderSearching(){this.content.list.innerHTML="";const e=document.createElement("div");e.classList.add(this.classes.searching),e.textContent=this.settings.searchingText,this.content.list.appendChild(e)}renderOptions(e){if(this.content.list.innerHTML="",0===e.length){const e=document.createElement("div");return e.classList.add(this.classes.option),e.classList.add(this.classes.disabled),e.innerHTML=this.settings.searchText,void this.content.list.appendChild(e)}for(const t of e){if(t instanceof a){const e=document.createElement("div");e.classList.add(this.classes.optgroup);const s=document.createElement("div");s.classList.add(this.classes.optgroupLabel),s.innerHTML=t.label,this.settings.selectByGroup&&this.settings.isMultiple&&(s.classList.add(this.classes.optgroupSelectable),s.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation();for(const t of e.children)-1!==t.className.indexOf(this.classes.option)&&t.click()}))),e.appendChild(s);for(const s of t.options)e.appendChild(this.option(s));this.content.list.appendChild(e)}t instanceof l&&this.content.list.appendChild(this.option(t))}}option(e){if(e.placeholder){const e=document.createElement("div");return e.classList.add(this.classes.option),e.classList.add(this.classes.hide),e}const t=document.createElement("div");if(t.dataset.id=e.id,t.classList.add(this.classes.option),t.setAttribute("role","option"),e.class&&e.class.split(" ").forEach((e=>{t.classList.add(e)})),e.style&&(t.style.cssText=e.style),this.settings.searchHighlight&&""!==this.content.search.input.value.trim()){const s=""!==e.html?e.html:e.text;t.innerHTML=this.highlightText(s,this.content.search.input.value,this.classes.searchHighlighter)}else""!==e.html?t.innerHTML=e.html:t.textContent=e.text;return this.settings.showOptionTooltips&&t.textContent&&t.setAttribute("title",t.textContent),(e.selected&&!this.settings.allowDeselect||e.disabled&&!this.settings.allowDeselect)&&t.classList.add(this.classes.disabled),e.selected&&this.settings.hideSelected&&t.classList.add(this.classes.hide),e.selected?t.classList.add(this.classes.optionSelected):t.classList.remove(this.classes.optionSelected),t.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation();const s=this.store.getSelected(),i=t.currentTarget,n=String(i.dataset.id);if(e.disabled||e.selected&&!this.settings.allowDeselect)return;if(this.settings.isMultiple&&Array.isArray(s)&&this.settings.maxSelected<=s.length)return;let a=!1;const l=this.store.getSelectedOptions();let o=[];this.settings.isMultiple&&(o=e.selected?l.filter((e=>e.id!==n)):l.concat(e)),this.settings.isMultiple||(o=e.selected?[]:[e]),this.callbacks.beforeChange||(a=!0),this.callbacks.beforeChange&&(a=!1!==this.callbacks.beforeChange(o,l)),a&&(this.store.getOptionByID(n)||this.callbacks.addOption(e),this.callbacks.setSelected(o.map((e=>e.value))),this.settings.closeOnSelect&&this.callbacks.close(),this.callbacks.afterChange&&this.callbacks.afterChange(o))})),t}destroy(){this.main.main.remove(),this.content.main.remove()}highlightText(e,t,s){let i=e;const n=new RegExp("("+t.trim()+")(?![^<]*>[^<>]*</)","i");if(!e.match(n))return e;const a=e.match(n).index,l=a+e.match(n)[0].toString().length,o=e.substring(a,l);return i=i.replace(n,`<mark class="${s}">${o}</mark>`),i}moveContentAbove(){const e=this.main.main.offsetHeight+this.content.main.offsetHeight-1;this.content.main.style.margin="-"+e+"px 0px 0px 0px",this.content.main.style.transformOrigin="center bottom",this.main.main.classList.remove(this.classes.openBelow),this.main.main.classList.add(this.classes.openAbove),this.content.main.classList.remove(this.classes.openBelow),this.content.main.classList.add(this.classes.openAbove)}moveContentBelow(){this.content.main.style.margin="-1px 0px 0px 0px",this.content.main.style.transformOrigin="center top",this.main.main.classList.remove(this.classes.openAbove),this.main.main.classList.add(this.classes.openBelow),this.content.main.classList.remove(this.classes.openAbove),this.content.main.classList.add(this.classes.openBelow)}ensureElementInView(e,t){const s=e.scrollTop+e.offsetTop,i=s+e.clientHeight,n=t.offsetTop,a=n+t.clientHeight;n<s?e.scrollTop-=s-n:a>i&&(e.scrollTop+=a-i)}putContent(e,t){const s=e.offsetHeight,i=e.getBoundingClientRect(),n=t?i.top:i.top-s,a=t?i.bottom:i.bottom+s;return n<=0?"down":a>=window.innerHeight?"up":"down"}}class c{constructor(e){this.listen=!1,this.observer=null,this.select=e}enable(){this.disconnectObserver(),this.select.disabled=!1,this.connectObserver()}disable(){this.disconnectObserver(),this.select.disabled=!0,this.connectObserver()}hideUI(){this.select.tabIndex=-1,this.select.style.display="none",this.select.setAttribute("aria-hidden","true")}showUI(){this.select.removeAttribute("tabindex"),this.select.style.display="",this.select.removeAttribute("aria-hidden")}changeListen(e){this.listen=e,this.listen?this.connectObserver():this.disconnectObserver()}addSelectChangeListener(e){this.onSelectChange=e,this.addObserver(),this.connectObserver(),this.changeListen(!0)}removeSelectChangeListener(){this.changeListen(!1),this.onSelectChange=void 0}addValueChangeListener(e){this.onValueChange=e,this.select.addEventListener("change",this.valueChange.bind(this))}removeValueChangeListener(){this.onValueChange=void 0,this.select.removeEventListener("change",this.valueChange.bind(this))}valueChange(e){this.onValueChange&&this.onValueChange(this.getSelectedValues())}observeWrapper(e){this.onSelectChange&&this.onSelectChange(this.getData())}addObserver(){this.observer&&(this.disconnectObserver(),this.observer=null),this.observer=new MutationObserver(this.observeWrapper)}connectObserver(){this.observer&&this.observer.observe(this.select,{attributes:!0,childList:!0,characterData:!0,subtree:!0})}disconnectObserver(){this.observer&&this.observer.disconnect()}getData(){let e=[];const t=this.select.childNodes;for(const s of t)"OPTGROUP"===s.nodeName&&e.push(this.getDataFromOptgroup(s)),"OPTION"===s.nodeName&&e.push(this.getDataFromOption(s));return e}getDataFromOptgroup(e){let t={id:"",label:e.label,options:[]};const s=e.childNodes;for(const e of s)"OPTION"===e.nodeName&&t.options.push(this.getDataFromOption(e));return t}getSelectedValues(){let e=[];const t=this.select.childNodes;for(const s of t){if("OPTGROUP"===s.nodeName){const t=s.childNodes;for(const s of t)if("OPTION"===s.nodeName){const t=s;t.selected&&e.push(t.value)}}if("OPTION"===s.nodeName){const t=s;t.selected&&e.push(t.value)}}return e}getDataFromOption(e){return{id:!!e.dataset&&e.dataset.id||t(),value:e.value,text:e.text,html:e.innerHTML,selected:e.selected,display:"none"!==e.style.display,disabled:e.disabled,mandatory:!!e.dataset&&"true"===e.dataset.mandatory,placeholder:"true"===e.dataset.placeholder,class:e.className,style:e.style.cssText,data:e.dataset}}setSelected(e){const t=this.select.childNodes;for(const s of t){if("OPTGROUP"===s.nodeName){const t=s.childNodes;for(const s of t)if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.value)}}if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.value)}}}updateSelect(e,t,s){this.changeListen(!1),e&&(this.select.id=e),t&&(this.select.style.cssText=t),s&&(this.select.className="",s.forEach((e=>{""!==e.trim()&&this.select.classList.add(e.trim())}))),this.changeListen(!0)}updateOptions(e){this.changeListen(!1),this.select.innerHTML="";for(const t of e)t instanceof a&&this.select.appendChild(this.createOptgroup(t)),t instanceof l&&this.select.appendChild(this.createOption(t));this.changeListen(!0)}createOptgroup(e){const t=document.createElement("optgroup");if(t.id=e.id,t.label=e.label,e.options)for(const s of e.options)t.appendChild(this.createOption(s));return t}createOption(e){const t=document.createElement("option");return t.value=""!==e.value?e.value:e.text,t.innerHTML=e.html||e.text,e.selected&&(t.selected=e.selected),e.disabled&&(t.disabled=!0),!1===e.display&&(t.style.display="none"),e.placeholder&&t.setAttribute("data-placeholder","true"),e.mandatory&&t.setAttribute("data-mandatory","true"),e.class&&e.class.split(" ").forEach((e=>{t.classList.add(e)})),e.data&&"object"==typeof e.data&&Object.keys(e.data).forEach((s=>{t.setAttribute("data-"+n(s),e.data[s])})),t}destroy(){this.changeListen(!1),this.disconnectObserver(),this.removeSelectChangeListener(),this.removeValueChangeListener(),this.showUI()}}class r{constructor(e){this.id="",this.style="",this.class=[],this.isMultiple=!1,this.isOpen=!1,this.triggerFocus=!0,this.intervalMove=null,this.mainHeight=30,this.contentHeight=0,e||(e={}),this.id="ss-"+t(),this.style=e.style||"",this.class=e.class||[],this.isEnabled=void 0===e.isEnabled||e.isEnabled,this.alwaysOpen=void 0!==e.alwaysOpen&&e.alwaysOpen,this.showSearch=void 0===e.showSearch||e.showSearch,this.searchPlaceholder=e.searchPlaceholder||"Search",this.searchText=e.searchText||"No Results",this.searchingText=e.searchingText||"Searching...",this.searchHighlight=void 0!==e.searchHighlight&&e.searchHighlight,this.closeOnSelect=void 0===e.closeOnSelect||e.closeOnSelect,this.contentLocation=e.contentLocation||document.body,this.contentPosition=e.contentPosition||"absolute",this.openPosition=e.openPosition||"auto",this.placeholderText=e.placeholderText||"Select Value",this.allowDeselect=void 0!==e.allowDeselect&&e.allowDeselect,this.hideSelected=void 0!==e.hideSelected&&e.hideSelected,this.showOptionTooltips=void 0!==e.showOptionTooltips&&e.showOptionTooltips,this.selectByGroup=void 0!==e.selectByGroup&&e.selectByGroup,this.minSelected=e.minSelected||0,this.maxSelected=e.maxSelected||1e3,this.timeoutDelay=e.timeoutDelay||200}}e.Optgroup=a,e.Option=l,e.Render=h,e.Select=c,e.Settings=r,e.Store=o,e.debounce=i,e.default=class{constructor(e){if(this.events={search:void 0,searchFilter:(e,t)=>-1!==e.text.toLowerCase().indexOf(t.toLowerCase()),addable:void 0,beforeChange:void 0,afterChange:void 0,beforeOpen:void 0,afterOpen:void 0,beforeClose:void 0,afterClose:void 0},this.windowResize=i((()=>{this.settings.isOpen&&this.render.moveContent()})),this.windowScroll=i((()=>{this.settings.isOpen&&("down"!==this.settings.openPosition?"up"!==this.settings.openPosition?"relative"===this.settings.contentPosition?this.render.moveContentBelow():"up"===this.render.putContent(this.render.content.main,this.settings.isOpen)?this.render.moveContentAbove():this.render.moveContentBelow():this.render.moveContentAbove():this.render.moveContentBelow())})),this.documentClick=e=>{this.settings.isOpen&&e.target&&!s(e.target,this.settings.id)&&this.close()},this.selectEl="string"==typeof e.select?document.querySelector(e.select):e.select,!this.selectEl)return void(e.events&&e.events.error&&e.events.error(new Error("Could not find select element")));if("SELECT"!==this.selectEl.tagName)return void(e.events&&e.events.error&&e.events.error(new Error("Element isnt of type select")));this.selectEl.dataset.ssid&&this.destroy(),this.settings=new r(e.settings);for(const t in e.events)e.events.hasOwnProperty(t)&&(this.events[t]=e.events[t]);this.settings.isMultiple=this.selectEl.multiple,this.settings.style=this.selectEl.style.cssText,this.settings.class=this.selectEl.className.split(" "),this.select=new c(this.selectEl),this.select.updateSelect(this.settings.id,this.settings.style,this.settings.class),this.select.hideUI(),this.select.addSelectChangeListener((e=>{this.setData(e)})),this.select.addValueChangeListener((e=>{this.setSelected(e)})),this.store=new o(this.settings.isMultiple?"multiple":"single",e.data?e.data:this.select.getData()),e.data&&this.select.updateOptions(this.store.getData());const t={open:this.open.bind(this),close:this.close.bind(this),addable:this.events.addable?this.events.addable:void 0,setSelected:this.setSelected.bind(this),addOption:this.addOption.bind(this),search:this.search.bind(this),beforeChange:this.events.beforeChange,afterChange:this.events.afterChange};this.render=new h(this.settings,this.store,t),this.selectEl.parentNode&&this.selectEl.parentNode.insertBefore(this.render.main.main,this.selectEl.nextSibling),document.addEventListener("click",this.documentClick),window.addEventListener("resize",this.windowResize,!1),"auto"===this.settings.openPosition&&window.addEventListener("scroll",this.windowScroll,!1),this.settings.isEnabled||this.disable(),this.settings.alwaysOpen&&this.open(),this.selectEl.slim=this}enable(){this.settings.isEnabled=!0,this.select.enable(),this.render.enable()}disable(){this.settings.isEnabled=!1,this.select.disable(),this.render.disable()}getData(){return this.store.getData()}setData(e){const t=this.store.validateDataArray(e);if(t)return void(this.events.error&&this.events.error(t));this.store.setData(e);const s=this.store.getData();this.select.updateOptions(s),this.render.renderValues(),this.render.renderOptions(s)}getSelected(){return this.store.getSelected()}setSelected(e){this.store.setSelectedBy("value",Array.isArray(e)?e:[e]);const t=this.store.getData();this.select.updateOptions(t),this.render.renderValues(),this.render.renderOptions(t)}addOption(e){this.store.addOption(e);const t=this.store.getData();this.select.updateOptions(t),this.render.renderValues(),this.render.renderOptions(t)}open(){this.settings.isEnabled&&!this.settings.isOpen&&(this.events.beforeOpen&&this.events.beforeOpen(),this.render.open(),this.settings.showSearch&&this.render.searchFocus(!1),setTimeout((()=>{this.events.afterOpen&&this.events.afterOpen(),this.settings.isOpen=!0}),this.settings.timeoutDelay),this.settings.intervalMove&&clearInterval(this.settings.intervalMove),this.settings.intervalMove=setInterval(this.render.moveContent.bind(this.render),500))}close(){this.settings.isOpen&&!this.settings.alwaysOpen&&(this.events.beforeClose&&this.events.beforeClose(),this.render.close(),this.search(""),this.render.mainFocus(!1),setTimeout((()=>{this.events.afterClose&&this.events.afterClose(),this.settings.isOpen=!1}),this.settings.timeoutDelay),this.settings.intervalMove&&clearInterval(this.settings.intervalMove))}search(e){if(this.render.content.search.input.value!==e&&(this.render.content.search.input.value=e),!this.events.search)return void this.render.renderOptions(""===e?this.store.getData():this.store.search(e,this.events.searchFilter));this.render.renderSearching();const t=this.events.search(e,this.store.getSelectedOptions());t instanceof Promise?t.then((e=>{this.render.renderOptions(this.store.partialToFullData(e))})).catch((e=>{this.render.renderError("string"==typeof e?e:e.message)})):Array.isArray(t)?this.render.renderOptions(this.store.partialToFullData(t)):this.render.renderError("Search event must return a promise or an array of data")}destroy(){document.removeEventListener("click",this.documentClick),window.removeEventListener("resize",this.windowResize,!1),"auto"===this.settings.openPosition&&window.removeEventListener("scroll",this.windowScroll,!1),this.store.setData([]),this.render.destroy(),this.select.destroy()}},e.generateID=t,e.hasClassInTree=s,e.kebabCase=n,Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
2
|
-
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SlimSelect = factory());
|
|
5
|
+
})(this, (function () { 'use strict';
|
|
6
|
+
|
|
7
|
+
function generateID() {
|
|
8
|
+
return Math.random().toString(36).substring(2, 10);
|
|
9
|
+
}
|
|
10
|
+
function hasClassInTree(element, className) {
|
|
11
|
+
function hasClass(e, c) {
|
|
12
|
+
if (c && e && e.classList && e.classList.contains(c)) {
|
|
13
|
+
return e;
|
|
14
|
+
}
|
|
15
|
+
if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {
|
|
16
|
+
return e;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function parentByClass(e, c) {
|
|
21
|
+
if (!e || e === document) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
else if (hasClass(e, c)) {
|
|
25
|
+
return e;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return parentByClass(e.parentNode, c);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return hasClass(element, className) || parentByClass(element, className);
|
|
32
|
+
}
|
|
33
|
+
function debounce(func, wait = 50, immediate = false) {
|
|
34
|
+
let timeout;
|
|
35
|
+
return function (...args) {
|
|
36
|
+
const context = self;
|
|
37
|
+
const later = () => {
|
|
38
|
+
timeout = null;
|
|
39
|
+
if (!immediate) {
|
|
40
|
+
func.apply(context, args);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const callNow = immediate && !timeout;
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
timeout = setTimeout(later, wait);
|
|
46
|
+
if (callNow) {
|
|
47
|
+
func.apply(context, args);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function kebabCase(str) {
|
|
52
|
+
const result = str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
|
|
53
|
+
return str[0] === str[0].toUpperCase() ? result.substring(1) : result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class Optgroup {
|
|
57
|
+
constructor(optgroup) {
|
|
58
|
+
this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id;
|
|
59
|
+
this.label = optgroup.label || '';
|
|
60
|
+
this.options = [];
|
|
61
|
+
if (optgroup.options) {
|
|
62
|
+
for (const o of optgroup.options) {
|
|
63
|
+
this.options.push(new Option(o));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class Option {
|
|
69
|
+
constructor(option) {
|
|
70
|
+
this.id = !option.id || option.id === '' ? generateID() : option.id;
|
|
71
|
+
this.value = option.value === undefined ? option.text : option.value;
|
|
72
|
+
this.text = option.text || '';
|
|
73
|
+
this.html = option.html || '';
|
|
74
|
+
this.selected = option.selected !== undefined ? option.selected : false;
|
|
75
|
+
this.display = option.display !== undefined ? option.display : true;
|
|
76
|
+
this.disabled = option.disabled !== undefined ? option.disabled : false;
|
|
77
|
+
this.mandatory = option.mandatory !== undefined ? option.mandatory : false;
|
|
78
|
+
this.placeholder = option.placeholder !== undefined ? option.placeholder : false;
|
|
79
|
+
this.class = option.class || '';
|
|
80
|
+
this.style = option.style || '';
|
|
81
|
+
this.data = option.data || {};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
class Store {
|
|
85
|
+
constructor(type, data) {
|
|
86
|
+
this.selectType = 'single';
|
|
87
|
+
this.data = [];
|
|
88
|
+
this.selectType = type;
|
|
89
|
+
this.setData(data);
|
|
90
|
+
}
|
|
91
|
+
validateDataArray(data) {
|
|
92
|
+
if (!Array.isArray(data)) {
|
|
93
|
+
return new Error('Data must be an array');
|
|
94
|
+
}
|
|
95
|
+
for (let dataObj of data) {
|
|
96
|
+
if (dataObj instanceof Optgroup || 'label' in dataObj) {
|
|
97
|
+
if (!('label' in dataObj)) {
|
|
98
|
+
return new Error('Optgroup must have a label');
|
|
99
|
+
}
|
|
100
|
+
if ('options' in dataObj && dataObj.options) {
|
|
101
|
+
for (let option of dataObj.options) {
|
|
102
|
+
return this.validateOption(option);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (dataObj instanceof Option || 'text' in dataObj) {
|
|
107
|
+
return this.validateOption(dataObj);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return new Error('Data object must be a valid optgroup or option');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
validateOption(option) {
|
|
116
|
+
if (!('text' in option)) {
|
|
117
|
+
return new Error('Option must have a text');
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
partialToFullData(data) {
|
|
122
|
+
let dataFinal = [];
|
|
123
|
+
data.forEach((dataObj) => {
|
|
124
|
+
if (dataObj instanceof Optgroup || 'label' in dataObj) {
|
|
125
|
+
let optOptions = [];
|
|
126
|
+
if ('options' in dataObj && dataObj.options) {
|
|
127
|
+
dataObj.options.forEach((option) => {
|
|
128
|
+
optOptions.push(new Option(option));
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (optOptions.length > 0) {
|
|
132
|
+
dataFinal.push(new Optgroup(dataObj));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (dataObj instanceof Option || 'text' in dataObj) {
|
|
136
|
+
dataFinal.push(new Option(dataObj));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
return dataFinal;
|
|
140
|
+
}
|
|
141
|
+
setData(data) {
|
|
142
|
+
this.data = this.partialToFullData(data);
|
|
143
|
+
if (this.selectType === 'single') {
|
|
144
|
+
this.setSelectedBy('value', this.getSelected());
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
getData() {
|
|
148
|
+
return this.filter(null, true);
|
|
149
|
+
}
|
|
150
|
+
getDataOptions() {
|
|
151
|
+
return this.filter(null, false);
|
|
152
|
+
}
|
|
153
|
+
addOption(option) {
|
|
154
|
+
this.setData(this.getData().concat(new Option(option)));
|
|
155
|
+
}
|
|
156
|
+
setSelectedBy(selectedType, selectedValues) {
|
|
157
|
+
let firstOption = null;
|
|
158
|
+
let hasSelected = false;
|
|
159
|
+
for (let dataObj of this.data) {
|
|
160
|
+
if (dataObj instanceof Optgroup) {
|
|
161
|
+
for (let option of dataObj.options) {
|
|
162
|
+
if (!firstOption) {
|
|
163
|
+
firstOption = option;
|
|
164
|
+
}
|
|
165
|
+
option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
|
|
166
|
+
if (option.selected && this.selectType === 'single') {
|
|
167
|
+
hasSelected = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (dataObj instanceof Option) {
|
|
172
|
+
if (!firstOption) {
|
|
173
|
+
firstOption = dataObj;
|
|
174
|
+
}
|
|
175
|
+
dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
|
|
176
|
+
if (dataObj.selected && this.selectType === 'single') {
|
|
177
|
+
hasSelected = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (this.selectType === 'single' && firstOption && !hasSelected) {
|
|
182
|
+
firstOption.selected = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
getSelected() {
|
|
186
|
+
let selectedOptions = this.getSelectedOptions();
|
|
187
|
+
let selectedValues = [];
|
|
188
|
+
selectedOptions.forEach((option) => {
|
|
189
|
+
selectedValues.push(option.value);
|
|
190
|
+
});
|
|
191
|
+
return selectedValues;
|
|
192
|
+
}
|
|
193
|
+
getSelectedOptions() {
|
|
194
|
+
return this.filter((opt) => {
|
|
195
|
+
return opt.selected;
|
|
196
|
+
}, false);
|
|
197
|
+
}
|
|
198
|
+
getSelectedIDs() {
|
|
199
|
+
let selectedOptions = this.getSelectedOptions();
|
|
200
|
+
let selectedIDs = [];
|
|
201
|
+
selectedOptions.forEach((op) => {
|
|
202
|
+
selectedIDs.push(op.id);
|
|
203
|
+
});
|
|
204
|
+
return selectedIDs;
|
|
205
|
+
}
|
|
206
|
+
getOptionByID(id) {
|
|
207
|
+
let options = this.filter((opt) => {
|
|
208
|
+
return opt.id === id;
|
|
209
|
+
}, false);
|
|
210
|
+
return options.length ? options[0] : null;
|
|
211
|
+
}
|
|
212
|
+
search(search, searchFilter) {
|
|
213
|
+
search = search.trim();
|
|
214
|
+
if (search === '') {
|
|
215
|
+
return this.getData();
|
|
216
|
+
}
|
|
217
|
+
return this.filter((opt) => {
|
|
218
|
+
return searchFilter(opt, search);
|
|
219
|
+
}, true);
|
|
220
|
+
}
|
|
221
|
+
filter(filter, includeOptgroup) {
|
|
222
|
+
const dataSearch = [];
|
|
223
|
+
this.data.forEach((dataObj) => {
|
|
224
|
+
if (dataObj instanceof Optgroup) {
|
|
225
|
+
if (!includeOptgroup) {
|
|
226
|
+
dataObj.options.forEach((option) => {
|
|
227
|
+
if (filter && filter(option)) {
|
|
228
|
+
dataSearch.push(option);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
let optOptions = [];
|
|
234
|
+
dataObj.options.forEach((option) => {
|
|
235
|
+
if (!filter || filter(option)) {
|
|
236
|
+
optOptions.push(new Option(option));
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
if (optOptions.length > 0) {
|
|
240
|
+
dataSearch.push(new Optgroup({ id: dataObj.id, label: dataObj.label, options: optOptions }));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (dataObj instanceof Option) {
|
|
245
|
+
if (!filter || filter(dataObj)) {
|
|
246
|
+
dataSearch.push(new Option(dataObj));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return dataSearch;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
class Render {
|
|
255
|
+
constructor(settings, store, callbacks) {
|
|
256
|
+
this.classes = {
|
|
257
|
+
main: 'ss-main',
|
|
258
|
+
placeholder: 'ss-placeholder',
|
|
259
|
+
values: 'ss-values',
|
|
260
|
+
single: 'ss-single',
|
|
261
|
+
value: 'ss-value',
|
|
262
|
+
valueText: 'ss-value-text',
|
|
263
|
+
valueDelete: 'ss-value-delete',
|
|
264
|
+
valueOut: 'ss-value-out',
|
|
265
|
+
deselect: 'ss-deselect',
|
|
266
|
+
deselectPath: 'M10,10 L90,90 M10,90 L90,10',
|
|
267
|
+
arrow: 'ss-arrow',
|
|
268
|
+
arrowClose: 'M10,30 L50,70 L90,30',
|
|
269
|
+
arrowOpen: 'M10,70 L50,30 L90,70',
|
|
270
|
+
content: 'ss-content',
|
|
271
|
+
openAbove: 'ss-open-above',
|
|
272
|
+
openBelow: 'ss-open-below',
|
|
273
|
+
search: 'ss-search',
|
|
274
|
+
searchHighlighter: 'ss-search-highlight',
|
|
275
|
+
searching: 'ss-searching',
|
|
276
|
+
addable: 'ss-addable',
|
|
277
|
+
addablePath: 'M50,10 L50,90 M10,50 L90,50',
|
|
278
|
+
list: 'ss-list',
|
|
279
|
+
optgroup: 'ss-optgroup',
|
|
280
|
+
optgroupLabel: 'ss-optgroup-label',
|
|
281
|
+
optgroupSelectable: 'ss-optgroup-selectable',
|
|
282
|
+
option: 'ss-option',
|
|
283
|
+
optionSelected: 'ss-option-selected',
|
|
284
|
+
optionDelete: 'M10,10 L90,90 M10,90 L90,10',
|
|
285
|
+
highlighted: 'ss-highlighted',
|
|
286
|
+
error: 'ss-error',
|
|
287
|
+
disabled: 'ss-disabled',
|
|
288
|
+
hide: 'ss-hide',
|
|
289
|
+
};
|
|
290
|
+
this.store = store;
|
|
291
|
+
this.settings = settings;
|
|
292
|
+
this.callbacks = callbacks;
|
|
293
|
+
this.main = this.mainDiv();
|
|
294
|
+
this.content = this.contentDiv();
|
|
295
|
+
this.renderValues();
|
|
296
|
+
this.renderOptions(this.store.getData());
|
|
297
|
+
this.settings.contentLocation.appendChild(this.content.main);
|
|
298
|
+
}
|
|
299
|
+
enable() {
|
|
300
|
+
this.main.main.classList.remove(this.classes.disabled);
|
|
301
|
+
this.content.search.input.disabled = false;
|
|
302
|
+
}
|
|
303
|
+
disable() {
|
|
304
|
+
this.main.main.classList.add(this.classes.disabled);
|
|
305
|
+
this.content.search.input.disabled = true;
|
|
306
|
+
}
|
|
307
|
+
open() {
|
|
308
|
+
this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
|
|
309
|
+
this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
|
|
310
|
+
this.moveContent();
|
|
311
|
+
this.renderOptions(this.store.getData());
|
|
312
|
+
if (this.settings.contentPosition === 'relative') {
|
|
313
|
+
this.moveContentBelow();
|
|
314
|
+
}
|
|
315
|
+
else if (this.settings.openPosition.toLowerCase() === 'up') {
|
|
316
|
+
this.moveContentAbove();
|
|
317
|
+
}
|
|
318
|
+
else if (this.settings.openPosition.toLowerCase() === 'down') {
|
|
319
|
+
this.moveContentBelow();
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
if (this.putContent(this.content.main, this.settings.isOpen) === 'up') {
|
|
323
|
+
this.moveContentAbove();
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
this.moveContentBelow();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const selectedOptions = this.store.getSelectedOptions();
|
|
330
|
+
if (selectedOptions.length) {
|
|
331
|
+
const selectedId = selectedOptions[selectedOptions.length - 1].id;
|
|
332
|
+
const selectedOption = this.content.list.querySelector('[data-id="' + selectedId + '"]');
|
|
333
|
+
if (selectedOption) {
|
|
334
|
+
this.ensureElementInView(this.content.list, selectedOption);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
close() {
|
|
339
|
+
this.main.main.classList.remove(this.classes.openAbove);
|
|
340
|
+
this.main.main.classList.remove(this.classes.openBelow);
|
|
341
|
+
this.content.main.classList.remove(this.classes.openAbove);
|
|
342
|
+
this.content.main.classList.remove(this.classes.openBelow);
|
|
343
|
+
this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
|
|
344
|
+
}
|
|
345
|
+
mainDiv() {
|
|
346
|
+
const main = document.createElement('div');
|
|
347
|
+
main.tabIndex = 0;
|
|
348
|
+
main.style.cssText = this.settings.style !== '' ? this.settings.style : '';
|
|
349
|
+
main.className = '';
|
|
350
|
+
main.classList.add(this.settings.id);
|
|
351
|
+
main.classList.add(this.classes.main);
|
|
352
|
+
if (this.settings.class) {
|
|
353
|
+
for (const c of this.settings.class) {
|
|
354
|
+
if (c.trim() !== '') {
|
|
355
|
+
main.classList.add(c.trim());
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
main.onfocus = () => {
|
|
360
|
+
if (this.settings.triggerFocus) {
|
|
361
|
+
this.callbacks.open();
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
main.onkeydown = (e) => {
|
|
365
|
+
switch (e.key) {
|
|
366
|
+
case 'ArrowUp':
|
|
367
|
+
case 'ArrowDown':
|
|
368
|
+
this.callbacks.open();
|
|
369
|
+
e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
|
|
370
|
+
return false;
|
|
371
|
+
case 'Tab':
|
|
372
|
+
this.callbacks.close();
|
|
373
|
+
return true;
|
|
374
|
+
case 'Enter':
|
|
375
|
+
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
376
|
+
if (highlighted) {
|
|
377
|
+
highlighted.click();
|
|
378
|
+
}
|
|
379
|
+
return false;
|
|
380
|
+
case 'Escape':
|
|
381
|
+
this.callbacks.close();
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
main.onclick = (e) => {
|
|
386
|
+
if (!this.settings.isEnabled) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
this.settings.isOpen ? this.callbacks.close() : this.callbacks.open();
|
|
390
|
+
};
|
|
391
|
+
const values = document.createElement('div');
|
|
392
|
+
values.classList.add(this.classes.values);
|
|
393
|
+
main.appendChild(values);
|
|
394
|
+
const deselect = document.createElement('div');
|
|
395
|
+
deselect.classList.add(this.classes.deselect);
|
|
396
|
+
if (!this.settings.allowDeselect || this.settings.isMultiple) {
|
|
397
|
+
deselect.classList.add(this.classes.hide);
|
|
398
|
+
}
|
|
399
|
+
deselect.onclick = (e) => {
|
|
400
|
+
e.stopPropagation();
|
|
401
|
+
if (!this.settings.isEnabled) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
let shouldDelete = true;
|
|
405
|
+
const before = this.store.getSelectedOptions();
|
|
406
|
+
const after = [];
|
|
407
|
+
if (this.callbacks.beforeChange) {
|
|
408
|
+
shouldDelete = this.callbacks.beforeChange(after, before) === true;
|
|
409
|
+
}
|
|
410
|
+
if (shouldDelete) {
|
|
411
|
+
this.callbacks.setSelected(['']);
|
|
412
|
+
if (this.settings.closeOnSelect) {
|
|
413
|
+
this.callbacks.close();
|
|
414
|
+
}
|
|
415
|
+
if (this.callbacks.afterChange) {
|
|
416
|
+
this.callbacks.afterChange(after);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
const deselectSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
421
|
+
deselectSvg.setAttribute('viewBox', '0 0 100 100');
|
|
422
|
+
const deselectPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
423
|
+
deselectPath.setAttribute('d', this.classes.deselectPath);
|
|
424
|
+
deselectSvg.appendChild(deselectPath);
|
|
425
|
+
deselect.appendChild(deselectSvg);
|
|
426
|
+
main.appendChild(deselect);
|
|
427
|
+
const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
428
|
+
arrow.classList.add(this.classes.arrow);
|
|
429
|
+
arrow.setAttribute('viewBox', '0 0 100 100');
|
|
430
|
+
const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
431
|
+
arrowPath.setAttribute('d', this.classes.arrowClose);
|
|
432
|
+
if (this.settings.alwaysOpen) {
|
|
433
|
+
arrow.classList.add(this.classes.hide);
|
|
434
|
+
}
|
|
435
|
+
arrow.appendChild(arrowPath);
|
|
436
|
+
main.appendChild(arrow);
|
|
437
|
+
return {
|
|
438
|
+
main: main,
|
|
439
|
+
values: values,
|
|
440
|
+
deselect: {
|
|
441
|
+
main: deselect,
|
|
442
|
+
svg: deselectSvg,
|
|
443
|
+
path: deselectPath,
|
|
444
|
+
},
|
|
445
|
+
arrow: {
|
|
446
|
+
main: arrow,
|
|
447
|
+
path: arrowPath,
|
|
448
|
+
},
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
mainFocus(trigger) {
|
|
452
|
+
if (!trigger) {
|
|
453
|
+
this.settings.triggerFocus = false;
|
|
454
|
+
}
|
|
455
|
+
this.main.main.focus({ preventScroll: true });
|
|
456
|
+
this.settings.triggerFocus = true;
|
|
457
|
+
}
|
|
458
|
+
placeholder() {
|
|
459
|
+
const placeholderOption = this.store.filter((o) => o.placeholder, false);
|
|
460
|
+
let placeholderText = this.settings.placeholderText;
|
|
461
|
+
if (placeholderOption.length) {
|
|
462
|
+
if (placeholderOption[0].html !== '') {
|
|
463
|
+
placeholderText = placeholderOption[0].html;
|
|
464
|
+
}
|
|
465
|
+
else if (placeholderOption[0].text !== '') {
|
|
466
|
+
placeholderText = placeholderOption[0].text;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const placeholder = document.createElement('div');
|
|
470
|
+
placeholder.classList.add(this.classes.placeholder);
|
|
471
|
+
placeholder.innerHTML = placeholderText;
|
|
472
|
+
return placeholder;
|
|
473
|
+
}
|
|
474
|
+
renderValues() {
|
|
475
|
+
if (!this.settings.isMultiple) {
|
|
476
|
+
this.renderSingleValue();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
this.renderMultipleValues();
|
|
480
|
+
}
|
|
481
|
+
renderSingleValue() {
|
|
482
|
+
const selected = this.store.filter((o) => {
|
|
483
|
+
return o.selected && !o.placeholder;
|
|
484
|
+
}, false);
|
|
485
|
+
const selectedSingle = selected.length > 0 ? selected[0] : null;
|
|
486
|
+
if (!selectedSingle) {
|
|
487
|
+
this.main.values.innerHTML = this.placeholder().outerHTML;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
const singleValue = document.createElement('div');
|
|
491
|
+
singleValue.classList.add(this.classes.single);
|
|
492
|
+
singleValue.innerHTML = selectedSingle.html ? selectedSingle.html : selectedSingle.text;
|
|
493
|
+
this.main.values.innerHTML = singleValue.outerHTML;
|
|
494
|
+
}
|
|
495
|
+
if (!this.settings.allowDeselect || !selected.length) {
|
|
496
|
+
this.main.deselect.main.classList.add(this.classes.hide);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
this.main.deselect.main.classList.remove(this.classes.hide);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
renderMultipleValues() {
|
|
503
|
+
let currentNodes = this.main.values.childNodes;
|
|
504
|
+
let selectedOptions = this.store.filter((opt) => {
|
|
505
|
+
return opt.selected && opt.display;
|
|
506
|
+
}, false);
|
|
507
|
+
if (selectedOptions.length === 0) {
|
|
508
|
+
this.main.values.innerHTML = this.placeholder().outerHTML;
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
const placeholder = this.main.values.querySelector('.' + this.classes.placeholder);
|
|
513
|
+
if (placeholder) {
|
|
514
|
+
placeholder.remove();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
let removeNodes = [];
|
|
518
|
+
for (let i = 0; i < currentNodes.length; i++) {
|
|
519
|
+
const node = currentNodes[i];
|
|
520
|
+
const id = node.getAttribute('data-id');
|
|
521
|
+
if (id) {
|
|
522
|
+
const found = selectedOptions.filter((opt) => {
|
|
523
|
+
return opt.id === id;
|
|
524
|
+
}, false);
|
|
525
|
+
if (!found.length) {
|
|
526
|
+
removeNodes.push(node);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
for (const n of removeNodes) {
|
|
531
|
+
n.classList.add(this.classes.valueOut);
|
|
532
|
+
setTimeout(() => {
|
|
533
|
+
this.main.values.removeChild(n);
|
|
534
|
+
}, 100);
|
|
535
|
+
}
|
|
536
|
+
currentNodes = this.main.values.childNodes;
|
|
537
|
+
for (let d = 0; d < selectedOptions.length; d++) {
|
|
538
|
+
let shouldAdd = true;
|
|
539
|
+
for (let i = 0; i < currentNodes.length; i++) {
|
|
540
|
+
if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {
|
|
541
|
+
shouldAdd = false;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (shouldAdd) {
|
|
545
|
+
if (currentNodes.length === 0) {
|
|
546
|
+
this.main.values.appendChild(this.multipleValue(selectedOptions[d]));
|
|
547
|
+
}
|
|
548
|
+
else if (d === 0) {
|
|
549
|
+
this.main.values.insertBefore(this.multipleValue(selectedOptions[d]), currentNodes[d]);
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
currentNodes[d - 1].insertAdjacentElement('afterend', this.multipleValue(selectedOptions[d]));
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
multipleValue(option) {
|
|
558
|
+
const value = document.createElement('div');
|
|
559
|
+
value.classList.add(this.classes.value);
|
|
560
|
+
value.dataset.id = option.id;
|
|
561
|
+
const text = document.createElement('div');
|
|
562
|
+
text.classList.add(this.classes.valueText);
|
|
563
|
+
text.innerHTML = option.text;
|
|
564
|
+
value.appendChild(text);
|
|
565
|
+
if (!option.mandatory) {
|
|
566
|
+
const deleteDiv = document.createElement('div');
|
|
567
|
+
deleteDiv.classList.add(this.classes.valueDelete);
|
|
568
|
+
deleteDiv.onclick = (e) => {
|
|
569
|
+
e.preventDefault();
|
|
570
|
+
e.stopPropagation();
|
|
571
|
+
let shouldDelete = true;
|
|
572
|
+
const before = this.store.getSelectedOptions();
|
|
573
|
+
const after = before.filter((o) => {
|
|
574
|
+
return o.selected && o.id !== option.id;
|
|
575
|
+
}, true);
|
|
576
|
+
if (this.settings.minSelected && after.length < this.settings.minSelected) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (this.callbacks.beforeChange) {
|
|
580
|
+
shouldDelete = this.callbacks.beforeChange(after, before) === true;
|
|
581
|
+
}
|
|
582
|
+
if (shouldDelete) {
|
|
583
|
+
let selectedValues = [];
|
|
584
|
+
for (const o of after) {
|
|
585
|
+
if (o instanceof Optgroup) {
|
|
586
|
+
for (const c of o.options) {
|
|
587
|
+
selectedValues.push(c.value);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (o instanceof Option) {
|
|
591
|
+
selectedValues.push(o.value);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
this.callbacks.setSelected(selectedValues);
|
|
595
|
+
if (this.settings.closeOnSelect) {
|
|
596
|
+
this.callbacks.close();
|
|
597
|
+
}
|
|
598
|
+
if (this.callbacks.afterChange) {
|
|
599
|
+
this.callbacks.afterChange(after);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
const deleteSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
604
|
+
deleteSvg.setAttribute('viewBox', '0 0 100 100');
|
|
605
|
+
const deletePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
606
|
+
deletePath.setAttribute('d', this.classes.optionDelete);
|
|
607
|
+
deleteSvg.appendChild(deletePath);
|
|
608
|
+
deleteDiv.appendChild(deleteSvg);
|
|
609
|
+
value.appendChild(deleteDiv);
|
|
610
|
+
}
|
|
611
|
+
return value;
|
|
612
|
+
}
|
|
613
|
+
contentDiv() {
|
|
614
|
+
const main = document.createElement('div');
|
|
615
|
+
main.classList.add(this.classes.content);
|
|
616
|
+
main.dataset.id = this.settings.id;
|
|
617
|
+
if (this.settings.style !== '') {
|
|
618
|
+
main.style.cssText = this.settings.style;
|
|
619
|
+
}
|
|
620
|
+
if (this.settings.contentPosition === 'relative') {
|
|
621
|
+
main.classList.add('ss-' + this.settings.contentPosition);
|
|
622
|
+
}
|
|
623
|
+
if (this.settings.class.length) {
|
|
624
|
+
for (const c of this.settings.class) {
|
|
625
|
+
if (c.trim() !== '') {
|
|
626
|
+
main.classList.add(c.trim());
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const search = this.searchDiv();
|
|
631
|
+
main.appendChild(search.main);
|
|
632
|
+
const list = this.listDiv();
|
|
633
|
+
main.appendChild(list);
|
|
634
|
+
return {
|
|
635
|
+
main: main,
|
|
636
|
+
search: search,
|
|
637
|
+
list: list,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
moveContent() {
|
|
641
|
+
if (this.settings.contentPosition === 'relative') {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const containerRect = this.main.main.getBoundingClientRect();
|
|
645
|
+
this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
|
|
646
|
+
this.content.main.style.left = containerRect.left + window.scrollX + 'px';
|
|
647
|
+
this.content.main.style.width = containerRect.width + 'px';
|
|
648
|
+
}
|
|
649
|
+
searchDiv() {
|
|
650
|
+
const main = document.createElement('div');
|
|
651
|
+
const input = document.createElement('input');
|
|
652
|
+
const addable = document.createElement('div');
|
|
653
|
+
main.classList.add(this.classes.search);
|
|
654
|
+
const searchReturn = {
|
|
655
|
+
main,
|
|
656
|
+
input,
|
|
657
|
+
};
|
|
658
|
+
if (!this.settings.showSearch) {
|
|
659
|
+
main.classList.add(this.classes.hide);
|
|
660
|
+
input.readOnly = true;
|
|
661
|
+
}
|
|
662
|
+
input.type = 'search';
|
|
663
|
+
input.placeholder = this.settings.searchPlaceholder;
|
|
664
|
+
input.tabIndex = -1;
|
|
665
|
+
input.setAttribute('aria-label', this.settings.searchPlaceholder);
|
|
666
|
+
input.setAttribute('autocapitalize', 'off');
|
|
667
|
+
input.setAttribute('autocomplete', 'off');
|
|
668
|
+
input.setAttribute('autocorrect', 'off');
|
|
669
|
+
input.oninput = debounce((e) => {
|
|
670
|
+
this.callbacks.search(e.target.value);
|
|
671
|
+
}, 100);
|
|
672
|
+
input.onkeydown = (e) => {
|
|
673
|
+
switch (e.key) {
|
|
674
|
+
case 'ArrowUp':
|
|
675
|
+
case 'ArrowDown':
|
|
676
|
+
this.callbacks.open();
|
|
677
|
+
e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
|
|
678
|
+
return false;
|
|
679
|
+
case 'Tab':
|
|
680
|
+
this.callbacks.close();
|
|
681
|
+
return true;
|
|
682
|
+
case 'Escape':
|
|
683
|
+
this.callbacks.close();
|
|
684
|
+
return false;
|
|
685
|
+
case 'Enter':
|
|
686
|
+
if (this.callbacks.addable && e.ctrlKey) {
|
|
687
|
+
addable.click();
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
691
|
+
if (highlighted) {
|
|
692
|
+
highlighted.click();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
input.onfocus = () => {
|
|
699
|
+
if (this.settings.isOpen) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
this.callbacks.open();
|
|
703
|
+
};
|
|
704
|
+
main.appendChild(input);
|
|
705
|
+
if (this.callbacks.addable) {
|
|
706
|
+
addable.classList.add(this.classes.addable);
|
|
707
|
+
const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
708
|
+
plus.setAttribute('viewBox', '0 0 100 100');
|
|
709
|
+
const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
710
|
+
plusPath.setAttribute('d', this.classes.addablePath);
|
|
711
|
+
plus.appendChild(plusPath);
|
|
712
|
+
addable.appendChild(plus);
|
|
713
|
+
addable.onclick = (e) => {
|
|
714
|
+
e.preventDefault();
|
|
715
|
+
e.stopPropagation();
|
|
716
|
+
if (!this.callbacks.addable) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const inputValue = this.content.search.input.value.trim();
|
|
720
|
+
if (inputValue === '') {
|
|
721
|
+
this.content.search.input.focus();
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const runFinish = (oo) => {
|
|
725
|
+
let newOption = new Option(oo);
|
|
726
|
+
this.callbacks.addOption(newOption);
|
|
727
|
+
if (this.settings.isMultiple) {
|
|
728
|
+
let values = this.store.getSelected();
|
|
729
|
+
values.push(newOption.value);
|
|
730
|
+
this.callbacks.setSelected(values);
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
this.callbacks.setSelected([newOption.value]);
|
|
734
|
+
}
|
|
735
|
+
this.callbacks.search('');
|
|
736
|
+
if (this.settings.closeOnSelect) {
|
|
737
|
+
setTimeout(() => {
|
|
738
|
+
this.callbacks.close();
|
|
739
|
+
}, 100);
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
const addableValue = this.callbacks.addable(inputValue);
|
|
743
|
+
if (addableValue instanceof Promise) {
|
|
744
|
+
addableValue.then((value) => {
|
|
745
|
+
if (typeof value === 'string') {
|
|
746
|
+
runFinish({
|
|
747
|
+
text: value,
|
|
748
|
+
value: value,
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
runFinish(value);
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
else if (typeof addableValue === 'string') {
|
|
757
|
+
runFinish({
|
|
758
|
+
text: addableValue,
|
|
759
|
+
value: addableValue,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
runFinish(addableValue);
|
|
764
|
+
}
|
|
765
|
+
return;
|
|
766
|
+
};
|
|
767
|
+
main.appendChild(addable);
|
|
768
|
+
searchReturn.addable = {
|
|
769
|
+
main: addable,
|
|
770
|
+
svg: plus,
|
|
771
|
+
path: plusPath,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
return searchReturn;
|
|
775
|
+
}
|
|
776
|
+
searchFocus(trigger) {
|
|
777
|
+
if (!trigger) {
|
|
778
|
+
this.settings.triggerFocus = false;
|
|
779
|
+
}
|
|
780
|
+
this.content.search.input.focus();
|
|
781
|
+
this.settings.triggerFocus = true;
|
|
782
|
+
}
|
|
783
|
+
getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
|
|
784
|
+
let query = '.' + this.classes.option;
|
|
785
|
+
if (notPlaceholder) {
|
|
786
|
+
query += ':not(.' + this.classes.placeholder + ')';
|
|
787
|
+
}
|
|
788
|
+
if (notDisabled) {
|
|
789
|
+
query += ':not(.' + this.classes.disabled + ')';
|
|
790
|
+
}
|
|
791
|
+
if (notHidden) {
|
|
792
|
+
query += ':not(.' + this.classes.hide + ')';
|
|
793
|
+
}
|
|
794
|
+
return Array.from(this.content.list.querySelectorAll(query));
|
|
795
|
+
}
|
|
796
|
+
highlight(dir) {
|
|
797
|
+
const options = this.getOptions(true, true, true);
|
|
798
|
+
if (options.length === 0) {
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
if (options.length === 1) {
|
|
802
|
+
if (!options[0].classList.contains(this.classes.highlighted)) {
|
|
803
|
+
options[0].classList.add(this.classes.highlighted);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
for (let i = 0; i < options.length; i++) {
|
|
808
|
+
if (options[i].classList.contains(this.classes.highlighted)) {
|
|
809
|
+
options[i].classList.remove(this.classes.highlighted);
|
|
810
|
+
if (dir === 'down') {
|
|
811
|
+
if (i + 1 < options.length) {
|
|
812
|
+
options[i + 1].classList.add(this.classes.highlighted);
|
|
813
|
+
this.ensureElementInView(this.content.list, options[i + 1]);
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
options[0].classList.add(this.classes.highlighted);
|
|
817
|
+
this.ensureElementInView(this.content.list, options[0]);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
if (i - 1 >= 0) {
|
|
822
|
+
options[i - 1].classList.add(this.classes.highlighted);
|
|
823
|
+
this.ensureElementInView(this.content.list, options[i - 1]);
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
options[options.length - 1].classList.add(this.classes.highlighted);
|
|
827
|
+
this.ensureElementInView(this.content.list, options[options.length - 1]);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
options[dir === 'down' ? 0 : options.length - 1].classList.add(this.classes.highlighted);
|
|
834
|
+
this.ensureElementInView(this.content.list, options[dir === 'down' ? 0 : options.length - 1]);
|
|
835
|
+
}
|
|
836
|
+
listDiv() {
|
|
837
|
+
const options = document.createElement('div');
|
|
838
|
+
options.classList.add(this.classes.list);
|
|
839
|
+
options.setAttribute('role', 'listbox');
|
|
840
|
+
return options;
|
|
841
|
+
}
|
|
842
|
+
renderError(error) {
|
|
843
|
+
this.content.list.innerHTML = '';
|
|
844
|
+
const errorDiv = document.createElement('div');
|
|
845
|
+
errorDiv.classList.add(this.classes.error);
|
|
846
|
+
errorDiv.textContent = error;
|
|
847
|
+
this.content.list.appendChild(errorDiv);
|
|
848
|
+
}
|
|
849
|
+
renderSearching() {
|
|
850
|
+
this.content.list.innerHTML = '';
|
|
851
|
+
const searchingDiv = document.createElement('div');
|
|
852
|
+
searchingDiv.classList.add(this.classes.searching);
|
|
853
|
+
searchingDiv.textContent = this.settings.searchingText;
|
|
854
|
+
this.content.list.appendChild(searchingDiv);
|
|
855
|
+
}
|
|
856
|
+
renderOptions(data) {
|
|
857
|
+
this.content.list.innerHTML = '';
|
|
858
|
+
if (data.length === 0) {
|
|
859
|
+
const noResults = document.createElement('div');
|
|
860
|
+
noResults.classList.add(this.classes.option);
|
|
861
|
+
noResults.classList.add(this.classes.disabled);
|
|
862
|
+
noResults.innerHTML = this.settings.searchText;
|
|
863
|
+
this.content.list.appendChild(noResults);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
for (const d of data) {
|
|
867
|
+
if (d instanceof Optgroup) {
|
|
868
|
+
const optgroupEl = document.createElement('div');
|
|
869
|
+
optgroupEl.classList.add(this.classes.optgroup);
|
|
870
|
+
const optgroupLabel = document.createElement('div');
|
|
871
|
+
optgroupLabel.classList.add(this.classes.optgroupLabel);
|
|
872
|
+
optgroupLabel.innerHTML = d.label;
|
|
873
|
+
if (this.settings.selectByGroup && this.settings.isMultiple) {
|
|
874
|
+
optgroupLabel.classList.add(this.classes.optgroupSelectable);
|
|
875
|
+
optgroupLabel.addEventListener('click', (e) => {
|
|
876
|
+
e.preventDefault();
|
|
877
|
+
e.stopPropagation();
|
|
878
|
+
for (const childEl of optgroupEl.children) {
|
|
879
|
+
if (childEl.className.indexOf(this.classes.option) !== -1) {
|
|
880
|
+
childEl.click();
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
optgroupEl.appendChild(optgroupLabel);
|
|
886
|
+
for (const o of d.options) {
|
|
887
|
+
optgroupEl.appendChild(this.option(o));
|
|
888
|
+
}
|
|
889
|
+
this.content.list.appendChild(optgroupEl);
|
|
890
|
+
}
|
|
891
|
+
if (d instanceof Option) {
|
|
892
|
+
this.content.list.appendChild(this.option(d));
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
option(option) {
|
|
897
|
+
if (option.placeholder) {
|
|
898
|
+
const placeholder = document.createElement('div');
|
|
899
|
+
placeholder.classList.add(this.classes.option);
|
|
900
|
+
placeholder.classList.add(this.classes.hide);
|
|
901
|
+
return placeholder;
|
|
902
|
+
}
|
|
903
|
+
const optionEl = document.createElement('div');
|
|
904
|
+
optionEl.dataset.id = option.id;
|
|
905
|
+
optionEl.classList.add(this.classes.option);
|
|
906
|
+
optionEl.setAttribute('role', 'option');
|
|
907
|
+
if (option.class) {
|
|
908
|
+
option.class.split(' ').forEach((dataClass) => {
|
|
909
|
+
optionEl.classList.add(dataClass);
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
if (option.style) {
|
|
913
|
+
optionEl.style.cssText = option.style;
|
|
914
|
+
}
|
|
915
|
+
if (this.settings.searchHighlight && this.content.search.input.value.trim() !== '') {
|
|
916
|
+
const textOrHtml = option.html !== '' ? option.html : option.text;
|
|
917
|
+
optionEl.innerHTML = this.highlightText(textOrHtml, this.content.search.input.value, this.classes.searchHighlighter);
|
|
918
|
+
}
|
|
919
|
+
else if (option.html !== '') {
|
|
920
|
+
optionEl.innerHTML = option.html;
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
optionEl.textContent = option.text;
|
|
924
|
+
}
|
|
925
|
+
if (this.settings.showOptionTooltips && optionEl.textContent) {
|
|
926
|
+
optionEl.setAttribute('title', optionEl.textContent);
|
|
927
|
+
}
|
|
928
|
+
if ((option.selected && !this.settings.allowDeselect) || (option.disabled && !this.settings.allowDeselect)) {
|
|
929
|
+
optionEl.classList.add(this.classes.disabled);
|
|
930
|
+
}
|
|
931
|
+
if (option.selected && this.settings.hideSelected) {
|
|
932
|
+
optionEl.classList.add(this.classes.hide);
|
|
933
|
+
}
|
|
934
|
+
if (option.selected) {
|
|
935
|
+
optionEl.classList.add(this.classes.optionSelected);
|
|
936
|
+
}
|
|
937
|
+
else {
|
|
938
|
+
optionEl.classList.remove(this.classes.optionSelected);
|
|
939
|
+
}
|
|
940
|
+
optionEl.addEventListener('click', (e) => {
|
|
941
|
+
e.preventDefault();
|
|
942
|
+
e.stopPropagation();
|
|
943
|
+
const selectedOptions = this.store.getSelected();
|
|
944
|
+
const element = e.currentTarget;
|
|
945
|
+
const elementID = String(element.dataset.id);
|
|
946
|
+
if (option.disabled || (option.selected && !this.settings.allowDeselect)) {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (this.settings.isMultiple &&
|
|
950
|
+
Array.isArray(selectedOptions) &&
|
|
951
|
+
this.settings.maxSelected <= selectedOptions.length) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
let shouldUpdate = false;
|
|
955
|
+
const before = this.store.getSelectedOptions();
|
|
956
|
+
let after = [];
|
|
957
|
+
if (this.settings.isMultiple) {
|
|
958
|
+
if (option.selected) {
|
|
959
|
+
after = before.filter((o) => o.id !== elementID);
|
|
960
|
+
}
|
|
961
|
+
else {
|
|
962
|
+
after = before.concat(option);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (!this.settings.isMultiple) {
|
|
966
|
+
if (option.selected) {
|
|
967
|
+
after = [];
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
after = [option];
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (!this.callbacks.beforeChange) {
|
|
974
|
+
shouldUpdate = true;
|
|
975
|
+
}
|
|
976
|
+
if (this.callbacks.beforeChange) {
|
|
977
|
+
if (this.callbacks.beforeChange(after, before) === false) {
|
|
978
|
+
shouldUpdate = false;
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
shouldUpdate = true;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
if (shouldUpdate) {
|
|
985
|
+
if (!this.store.getOptionByID(elementID)) {
|
|
986
|
+
this.callbacks.addOption(option);
|
|
987
|
+
}
|
|
988
|
+
this.callbacks.setSelected(after.map((o) => o.value));
|
|
989
|
+
if (this.settings.closeOnSelect) {
|
|
990
|
+
this.callbacks.close();
|
|
991
|
+
}
|
|
992
|
+
if (this.callbacks.afterChange) {
|
|
993
|
+
this.callbacks.afterChange(after);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
return optionEl;
|
|
998
|
+
}
|
|
999
|
+
destroy() {
|
|
1000
|
+
this.main.main.remove();
|
|
1001
|
+
this.content.main.remove();
|
|
1002
|
+
}
|
|
1003
|
+
highlightText(str, search, className) {
|
|
1004
|
+
let completedString = str;
|
|
1005
|
+
const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
|
|
1006
|
+
if (!str.match(regex)) {
|
|
1007
|
+
return str;
|
|
1008
|
+
}
|
|
1009
|
+
const matchStartPosition = str.match(regex).index;
|
|
1010
|
+
const matchEndPosition = matchStartPosition + str.match(regex)[0].toString().length;
|
|
1011
|
+
const originalTextFoundByRegex = str.substring(matchStartPosition, matchEndPosition);
|
|
1012
|
+
completedString = completedString.replace(regex, `<mark class="${className}">${originalTextFoundByRegex}</mark>`);
|
|
1013
|
+
return completedString;
|
|
1014
|
+
}
|
|
1015
|
+
moveContentAbove() {
|
|
1016
|
+
let mainHeight = this.main.main.offsetHeight;
|
|
1017
|
+
const contentHeight = this.content.main.offsetHeight;
|
|
1018
|
+
const height = mainHeight + contentHeight - 1;
|
|
1019
|
+
this.content.main.style.margin = '-' + height + 'px 0px 0px 0px';
|
|
1020
|
+
this.content.main.style.transformOrigin = 'center bottom';
|
|
1021
|
+
this.main.main.classList.remove(this.classes.openBelow);
|
|
1022
|
+
this.main.main.classList.add(this.classes.openAbove);
|
|
1023
|
+
this.content.main.classList.remove(this.classes.openBelow);
|
|
1024
|
+
this.content.main.classList.add(this.classes.openAbove);
|
|
1025
|
+
}
|
|
1026
|
+
moveContentBelow() {
|
|
1027
|
+
this.content.main.style.margin = '-1px 0px 0px 0px';
|
|
1028
|
+
this.content.main.style.transformOrigin = 'center top';
|
|
1029
|
+
this.main.main.classList.remove(this.classes.openAbove);
|
|
1030
|
+
this.main.main.classList.add(this.classes.openBelow);
|
|
1031
|
+
this.content.main.classList.remove(this.classes.openAbove);
|
|
1032
|
+
this.content.main.classList.add(this.classes.openBelow);
|
|
1033
|
+
}
|
|
1034
|
+
ensureElementInView(container, element) {
|
|
1035
|
+
const cTop = container.scrollTop + container.offsetTop;
|
|
1036
|
+
const cBottom = cTop + container.clientHeight;
|
|
1037
|
+
const eTop = element.offsetTop;
|
|
1038
|
+
const eBottom = eTop + element.clientHeight;
|
|
1039
|
+
if (eTop < cTop) {
|
|
1040
|
+
container.scrollTop -= cTop - eTop;
|
|
1041
|
+
}
|
|
1042
|
+
else if (eBottom > cBottom) {
|
|
1043
|
+
container.scrollTop += eBottom - cBottom;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
putContent(el, isOpen) {
|
|
1047
|
+
const height = el.offsetHeight;
|
|
1048
|
+
const rect = el.getBoundingClientRect();
|
|
1049
|
+
const elemTop = isOpen ? rect.top : rect.top - height;
|
|
1050
|
+
const elemBottom = isOpen ? rect.bottom : rect.bottom + height;
|
|
1051
|
+
if (elemTop <= 0) {
|
|
1052
|
+
return 'down';
|
|
1053
|
+
}
|
|
1054
|
+
if (elemBottom >= window.innerHeight) {
|
|
1055
|
+
return 'up';
|
|
1056
|
+
}
|
|
1057
|
+
return 'down';
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
class Select {
|
|
1062
|
+
constructor(select) {
|
|
1063
|
+
this.listen = false;
|
|
1064
|
+
this.observer = null;
|
|
1065
|
+
this.select = select;
|
|
1066
|
+
}
|
|
1067
|
+
enable() {
|
|
1068
|
+
this.disconnectObserver();
|
|
1069
|
+
this.select.disabled = false;
|
|
1070
|
+
this.connectObserver();
|
|
1071
|
+
}
|
|
1072
|
+
disable() {
|
|
1073
|
+
this.disconnectObserver();
|
|
1074
|
+
this.select.disabled = true;
|
|
1075
|
+
this.connectObserver();
|
|
1076
|
+
}
|
|
1077
|
+
hideUI() {
|
|
1078
|
+
this.select.tabIndex = -1;
|
|
1079
|
+
this.select.style.display = 'none';
|
|
1080
|
+
this.select.setAttribute('aria-hidden', 'true');
|
|
1081
|
+
}
|
|
1082
|
+
showUI() {
|
|
1083
|
+
this.select.removeAttribute('tabindex');
|
|
1084
|
+
this.select.style.display = '';
|
|
1085
|
+
this.select.removeAttribute('aria-hidden');
|
|
1086
|
+
}
|
|
1087
|
+
changeListen(on) {
|
|
1088
|
+
this.listen = on;
|
|
1089
|
+
if (this.listen) {
|
|
1090
|
+
this.connectObserver();
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
this.disconnectObserver();
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
addSelectChangeListener(func) {
|
|
1097
|
+
this.onSelectChange = func;
|
|
1098
|
+
this.addObserver();
|
|
1099
|
+
this.connectObserver();
|
|
1100
|
+
this.changeListen(true);
|
|
1101
|
+
}
|
|
1102
|
+
removeSelectChangeListener() {
|
|
1103
|
+
this.changeListen(false);
|
|
1104
|
+
this.onSelectChange = undefined;
|
|
1105
|
+
}
|
|
1106
|
+
addValueChangeListener(func) {
|
|
1107
|
+
this.onValueChange = func;
|
|
1108
|
+
this.select.addEventListener('change', this.valueChange.bind(this));
|
|
1109
|
+
}
|
|
1110
|
+
removeValueChangeListener() {
|
|
1111
|
+
this.onValueChange = undefined;
|
|
1112
|
+
this.select.removeEventListener('change', this.valueChange.bind(this));
|
|
1113
|
+
}
|
|
1114
|
+
valueChange(ev) {
|
|
1115
|
+
if (this.onValueChange) {
|
|
1116
|
+
this.onValueChange(this.getSelectedValues());
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
observeWrapper(mutations) {
|
|
1120
|
+
if (this.onSelectChange) {
|
|
1121
|
+
this.changeListen(false);
|
|
1122
|
+
this.onSelectChange(this.getData());
|
|
1123
|
+
this.changeListen(true);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
addObserver() {
|
|
1127
|
+
if (this.observer) {
|
|
1128
|
+
this.disconnectObserver();
|
|
1129
|
+
this.observer = null;
|
|
1130
|
+
}
|
|
1131
|
+
this.observer = new MutationObserver(this.observeWrapper.bind(this));
|
|
1132
|
+
}
|
|
1133
|
+
connectObserver() {
|
|
1134
|
+
if (this.observer) {
|
|
1135
|
+
this.observer.observe(this.select, {
|
|
1136
|
+
childList: true,
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
disconnectObserver() {
|
|
1141
|
+
if (this.observer) {
|
|
1142
|
+
this.observer.disconnect();
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
getData() {
|
|
1146
|
+
let data = [];
|
|
1147
|
+
const nodes = this.select.childNodes;
|
|
1148
|
+
for (const n of nodes) {
|
|
1149
|
+
if (n.nodeName === 'OPTGROUP') {
|
|
1150
|
+
data.push(this.getDataFromOptgroup(n));
|
|
1151
|
+
}
|
|
1152
|
+
if (n.nodeName === 'OPTION') {
|
|
1153
|
+
data.push(this.getDataFromOption(n));
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return data;
|
|
1157
|
+
}
|
|
1158
|
+
getDataFromOptgroup(optgroup) {
|
|
1159
|
+
let data = {
|
|
1160
|
+
id: '',
|
|
1161
|
+
label: optgroup.label,
|
|
1162
|
+
options: [],
|
|
1163
|
+
};
|
|
1164
|
+
const options = optgroup.childNodes;
|
|
1165
|
+
for (const o of options) {
|
|
1166
|
+
if (o.nodeName === 'OPTION') {
|
|
1167
|
+
data.options.push(this.getDataFromOption(o));
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
return data;
|
|
1171
|
+
}
|
|
1172
|
+
getSelectedValues() {
|
|
1173
|
+
let values = [];
|
|
1174
|
+
const options = this.select.childNodes;
|
|
1175
|
+
for (const o of options) {
|
|
1176
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
1177
|
+
const optgroupOptions = o.childNodes;
|
|
1178
|
+
for (const oo of optgroupOptions) {
|
|
1179
|
+
if (oo.nodeName === 'OPTION') {
|
|
1180
|
+
const option = oo;
|
|
1181
|
+
if (option.selected) {
|
|
1182
|
+
values.push(option.value);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
if (o.nodeName === 'OPTION') {
|
|
1188
|
+
const option = o;
|
|
1189
|
+
if (option.selected) {
|
|
1190
|
+
values.push(option.value);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return values;
|
|
1195
|
+
}
|
|
1196
|
+
getDataFromOption(option) {
|
|
1197
|
+
return {
|
|
1198
|
+
id: (option.dataset ? option.dataset.id : false) || generateID(),
|
|
1199
|
+
value: option.value,
|
|
1200
|
+
text: option.text,
|
|
1201
|
+
html: option.innerHTML,
|
|
1202
|
+
selected: option.selected,
|
|
1203
|
+
display: option.style.display === 'none' ? false : true,
|
|
1204
|
+
disabled: option.disabled,
|
|
1205
|
+
mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
|
|
1206
|
+
placeholder: option.dataset.placeholder === 'true',
|
|
1207
|
+
class: option.className,
|
|
1208
|
+
style: option.style.cssText,
|
|
1209
|
+
data: option.dataset,
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
setSelected(value) {
|
|
1213
|
+
const options = this.select.childNodes;
|
|
1214
|
+
for (const o of options) {
|
|
1215
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
1216
|
+
const optgroup = o;
|
|
1217
|
+
const optgroupOptions = optgroup.childNodes;
|
|
1218
|
+
for (const oo of optgroupOptions) {
|
|
1219
|
+
if (oo.nodeName === 'OPTION') {
|
|
1220
|
+
const option = oo;
|
|
1221
|
+
option.selected = value.includes(option.value);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (o.nodeName === 'OPTION') {
|
|
1226
|
+
const option = o;
|
|
1227
|
+
option.selected = value.includes(option.value);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
updateSelect(id, style, classes) {
|
|
1232
|
+
this.changeListen(false);
|
|
1233
|
+
if (id) {
|
|
1234
|
+
this.select.id = id;
|
|
1235
|
+
}
|
|
1236
|
+
if (style) {
|
|
1237
|
+
this.select.style.cssText = style;
|
|
1238
|
+
}
|
|
1239
|
+
if (classes) {
|
|
1240
|
+
this.select.className = '';
|
|
1241
|
+
classes.forEach((c) => {
|
|
1242
|
+
if (c.trim() !== '') {
|
|
1243
|
+
this.select.classList.add(c.trim());
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
this.changeListen(true);
|
|
1248
|
+
}
|
|
1249
|
+
updateOptions(data) {
|
|
1250
|
+
this.changeListen(false);
|
|
1251
|
+
this.select.innerHTML = '';
|
|
1252
|
+
for (const d of data) {
|
|
1253
|
+
if (d instanceof Optgroup) {
|
|
1254
|
+
this.select.appendChild(this.createOptgroup(d));
|
|
1255
|
+
}
|
|
1256
|
+
if (d instanceof Option) {
|
|
1257
|
+
this.select.appendChild(this.createOption(d));
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
this.changeListen(true);
|
|
1261
|
+
}
|
|
1262
|
+
createOptgroup(optgroup) {
|
|
1263
|
+
const optgroupEl = document.createElement('optgroup');
|
|
1264
|
+
optgroupEl.id = optgroup.id;
|
|
1265
|
+
optgroupEl.label = optgroup.label;
|
|
1266
|
+
if (optgroup.options) {
|
|
1267
|
+
for (const o of optgroup.options) {
|
|
1268
|
+
optgroupEl.appendChild(this.createOption(o));
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
return optgroupEl;
|
|
1272
|
+
}
|
|
1273
|
+
createOption(info) {
|
|
1274
|
+
const optionEl = document.createElement('option');
|
|
1275
|
+
optionEl.value = info.value !== '' ? info.value : info.text;
|
|
1276
|
+
optionEl.innerHTML = info.html || info.text;
|
|
1277
|
+
if (info.selected) {
|
|
1278
|
+
optionEl.selected = info.selected;
|
|
1279
|
+
}
|
|
1280
|
+
if (info.disabled) {
|
|
1281
|
+
optionEl.disabled = true;
|
|
1282
|
+
}
|
|
1283
|
+
if (info.display === false) {
|
|
1284
|
+
optionEl.style.display = 'none';
|
|
1285
|
+
}
|
|
1286
|
+
if (info.placeholder) {
|
|
1287
|
+
optionEl.setAttribute('data-placeholder', 'true');
|
|
1288
|
+
}
|
|
1289
|
+
if (info.mandatory) {
|
|
1290
|
+
optionEl.setAttribute('data-mandatory', 'true');
|
|
1291
|
+
}
|
|
1292
|
+
if (info.class) {
|
|
1293
|
+
info.class.split(' ').forEach((optionClass) => {
|
|
1294
|
+
optionEl.classList.add(optionClass);
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
if (info.data && typeof info.data === 'object') {
|
|
1298
|
+
Object.keys(info.data).forEach((key) => {
|
|
1299
|
+
optionEl.setAttribute('data-' + kebabCase(key), info.data[key]);
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
return optionEl;
|
|
1303
|
+
}
|
|
1304
|
+
destroy() {
|
|
1305
|
+
this.changeListen(false);
|
|
1306
|
+
this.disconnectObserver();
|
|
1307
|
+
this.removeSelectChangeListener();
|
|
1308
|
+
this.removeValueChangeListener();
|
|
1309
|
+
this.showUI();
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
class Settings {
|
|
1314
|
+
constructor(settings) {
|
|
1315
|
+
this.id = '';
|
|
1316
|
+
this.style = '';
|
|
1317
|
+
this.class = [];
|
|
1318
|
+
this.isMultiple = false;
|
|
1319
|
+
this.isOpen = false;
|
|
1320
|
+
this.triggerFocus = true;
|
|
1321
|
+
this.intervalMove = null;
|
|
1322
|
+
this.mainHeight = 30;
|
|
1323
|
+
this.contentHeight = 0;
|
|
1324
|
+
if (!settings) {
|
|
1325
|
+
settings = {};
|
|
1326
|
+
}
|
|
1327
|
+
this.id = 'ss-' + generateID();
|
|
1328
|
+
this.style = settings.style || '';
|
|
1329
|
+
this.class = settings.class || [];
|
|
1330
|
+
this.isEnabled = settings.isEnabled !== undefined ? settings.isEnabled : true;
|
|
1331
|
+
this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
|
|
1332
|
+
this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
|
|
1333
|
+
this.searchPlaceholder = settings.searchPlaceholder || 'Search';
|
|
1334
|
+
this.searchText = settings.searchText || 'No Results';
|
|
1335
|
+
this.searchingText = settings.searchingText || 'Searching...';
|
|
1336
|
+
this.searchHighlight = settings.searchHighlight !== undefined ? settings.searchHighlight : false;
|
|
1337
|
+
this.closeOnSelect = settings.closeOnSelect !== undefined ? settings.closeOnSelect : true;
|
|
1338
|
+
this.contentLocation = settings.contentLocation || document.body;
|
|
1339
|
+
this.contentPosition = settings.contentPosition || 'absolute';
|
|
1340
|
+
this.openPosition = settings.openPosition || 'auto';
|
|
1341
|
+
this.placeholderText = settings.placeholderText || 'Select Value';
|
|
1342
|
+
this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false;
|
|
1343
|
+
this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false;
|
|
1344
|
+
this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false;
|
|
1345
|
+
this.selectByGroup = settings.selectByGroup !== undefined ? settings.selectByGroup : false;
|
|
1346
|
+
this.minSelected = settings.minSelected || 0;
|
|
1347
|
+
this.maxSelected = settings.maxSelected || 1000;
|
|
1348
|
+
this.timeoutDelay = settings.timeoutDelay || 200;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
class SlimSelect {
|
|
1353
|
+
constructor(config) {
|
|
1354
|
+
this.events = {
|
|
1355
|
+
search: undefined,
|
|
1356
|
+
searchFilter: (opt, search) => {
|
|
1357
|
+
return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1;
|
|
1358
|
+
},
|
|
1359
|
+
addable: undefined,
|
|
1360
|
+
beforeChange: undefined,
|
|
1361
|
+
afterChange: undefined,
|
|
1362
|
+
beforeOpen: undefined,
|
|
1363
|
+
afterOpen: undefined,
|
|
1364
|
+
beforeClose: undefined,
|
|
1365
|
+
afterClose: undefined,
|
|
1366
|
+
};
|
|
1367
|
+
this.windowResize = debounce(() => {
|
|
1368
|
+
if (!this.settings.isOpen) {
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
this.render.moveContent();
|
|
1372
|
+
});
|
|
1373
|
+
this.windowScroll = debounce(() => {
|
|
1374
|
+
if (!this.settings.isOpen) {
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (this.settings.openPosition === 'down') {
|
|
1378
|
+
this.render.moveContentBelow();
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
else if (this.settings.openPosition === 'up') {
|
|
1382
|
+
this.render.moveContentAbove();
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
if (this.settings.contentPosition === 'relative') {
|
|
1386
|
+
this.render.moveContentBelow();
|
|
1387
|
+
}
|
|
1388
|
+
else if (this.render.putContent(this.render.content.main, this.settings.isOpen) === 'up') {
|
|
1389
|
+
this.render.moveContentAbove();
|
|
1390
|
+
}
|
|
1391
|
+
else {
|
|
1392
|
+
this.render.moveContentBelow();
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
this.documentClick = (e) => {
|
|
1396
|
+
if (!this.settings.isOpen) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
if (e.target && !hasClassInTree(e.target, this.settings.id)) {
|
|
1400
|
+
this.close();
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
|
|
1404
|
+
if (!this.selectEl) {
|
|
1405
|
+
if (config.events && config.events.error) {
|
|
1406
|
+
config.events.error(new Error('Could not find select element'));
|
|
1407
|
+
}
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (this.selectEl.tagName !== 'SELECT') {
|
|
1411
|
+
if (config.events && config.events.error) {
|
|
1412
|
+
config.events.error(new Error('Element isnt of type select'));
|
|
1413
|
+
}
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
if (this.selectEl.dataset.ssid) {
|
|
1417
|
+
this.destroy();
|
|
1418
|
+
}
|
|
1419
|
+
this.settings = new Settings(config.settings);
|
|
1420
|
+
for (const key in config.events) {
|
|
1421
|
+
if (config.events.hasOwnProperty(key)) {
|
|
1422
|
+
this.events[key] = config.events[key];
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
this.settings.isMultiple = this.selectEl.multiple;
|
|
1426
|
+
this.settings.style = this.selectEl.style.cssText;
|
|
1427
|
+
this.settings.class = this.selectEl.className.split(' ');
|
|
1428
|
+
this.select = new Select(this.selectEl);
|
|
1429
|
+
this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
|
|
1430
|
+
this.select.hideUI();
|
|
1431
|
+
this.select.addSelectChangeListener((data) => {
|
|
1432
|
+
this.setData(data);
|
|
1433
|
+
});
|
|
1434
|
+
this.select.addValueChangeListener((values) => {
|
|
1435
|
+
this.setSelected(values);
|
|
1436
|
+
});
|
|
1437
|
+
this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', config.data ? config.data : this.select.getData());
|
|
1438
|
+
if (config.data) {
|
|
1439
|
+
this.select.updateOptions(this.store.getData());
|
|
1440
|
+
}
|
|
1441
|
+
const callbacks = {
|
|
1442
|
+
open: this.open.bind(this),
|
|
1443
|
+
close: this.close.bind(this),
|
|
1444
|
+
addable: this.events.addable ? this.events.addable : undefined,
|
|
1445
|
+
setSelected: this.setSelected.bind(this),
|
|
1446
|
+
addOption: this.addOption.bind(this),
|
|
1447
|
+
search: this.search.bind(this),
|
|
1448
|
+
beforeChange: this.events.beforeChange,
|
|
1449
|
+
afterChange: this.events.afterChange,
|
|
1450
|
+
};
|
|
1451
|
+
this.render = new Render(this.settings, this.store, callbacks);
|
|
1452
|
+
if (this.selectEl.parentNode) {
|
|
1453
|
+
this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
|
|
1454
|
+
}
|
|
1455
|
+
document.addEventListener('click', this.documentClick);
|
|
1456
|
+
window.addEventListener('resize', this.windowResize, false);
|
|
1457
|
+
if (this.settings.openPosition === 'auto') {
|
|
1458
|
+
window.addEventListener('scroll', this.windowScroll, false);
|
|
1459
|
+
}
|
|
1460
|
+
if (!this.settings.isEnabled) {
|
|
1461
|
+
this.disable();
|
|
1462
|
+
}
|
|
1463
|
+
if (this.settings.alwaysOpen) {
|
|
1464
|
+
this.open();
|
|
1465
|
+
}
|
|
1466
|
+
this.selectEl.slim = this;
|
|
1467
|
+
}
|
|
1468
|
+
enable() {
|
|
1469
|
+
this.settings.isEnabled = true;
|
|
1470
|
+
this.select.enable();
|
|
1471
|
+
this.render.enable();
|
|
1472
|
+
}
|
|
1473
|
+
disable() {
|
|
1474
|
+
this.settings.isEnabled = false;
|
|
1475
|
+
this.select.disable();
|
|
1476
|
+
this.render.disable();
|
|
1477
|
+
}
|
|
1478
|
+
getData() {
|
|
1479
|
+
return this.store.getData();
|
|
1480
|
+
}
|
|
1481
|
+
setData(data) {
|
|
1482
|
+
const err = this.store.validateDataArray(data);
|
|
1483
|
+
if (err) {
|
|
1484
|
+
if (this.events.error) {
|
|
1485
|
+
this.events.error(err);
|
|
1486
|
+
}
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
this.store.setData(data);
|
|
1490
|
+
const dataClean = this.store.getData();
|
|
1491
|
+
this.select.updateOptions(dataClean);
|
|
1492
|
+
this.render.renderValues();
|
|
1493
|
+
this.render.renderOptions(dataClean);
|
|
1494
|
+
}
|
|
1495
|
+
getSelected() {
|
|
1496
|
+
return this.store.getSelected();
|
|
1497
|
+
}
|
|
1498
|
+
setSelected(value) {
|
|
1499
|
+
this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
|
|
1500
|
+
const data = this.store.getData();
|
|
1501
|
+
this.select.updateOptions(data);
|
|
1502
|
+
this.render.renderValues();
|
|
1503
|
+
this.render.renderOptions(data);
|
|
1504
|
+
}
|
|
1505
|
+
addOption(option) {
|
|
1506
|
+
this.store.addOption(option);
|
|
1507
|
+
const data = this.store.getData();
|
|
1508
|
+
this.select.updateOptions(data);
|
|
1509
|
+
this.render.renderValues();
|
|
1510
|
+
this.render.renderOptions(data);
|
|
1511
|
+
}
|
|
1512
|
+
open() {
|
|
1513
|
+
if (!this.settings.isEnabled || this.settings.isOpen) {
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
if (this.events.beforeOpen) {
|
|
1517
|
+
this.events.beforeOpen();
|
|
1518
|
+
}
|
|
1519
|
+
this.render.open();
|
|
1520
|
+
if (this.settings.showSearch) {
|
|
1521
|
+
this.render.searchFocus(false);
|
|
1522
|
+
}
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
if (this.events.afterOpen) {
|
|
1525
|
+
this.events.afterOpen();
|
|
1526
|
+
}
|
|
1527
|
+
this.settings.isOpen = true;
|
|
1528
|
+
}, this.settings.timeoutDelay);
|
|
1529
|
+
if (this.settings.intervalMove) {
|
|
1530
|
+
clearInterval(this.settings.intervalMove);
|
|
1531
|
+
}
|
|
1532
|
+
this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
|
|
1533
|
+
}
|
|
1534
|
+
close() {
|
|
1535
|
+
if (!this.settings.isOpen || this.settings.alwaysOpen) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (this.events.beforeClose) {
|
|
1539
|
+
this.events.beforeClose();
|
|
1540
|
+
}
|
|
1541
|
+
this.render.close();
|
|
1542
|
+
this.search('');
|
|
1543
|
+
this.render.mainFocus(false);
|
|
1544
|
+
setTimeout(() => {
|
|
1545
|
+
if (this.events.afterClose) {
|
|
1546
|
+
this.events.afterClose();
|
|
1547
|
+
}
|
|
1548
|
+
this.settings.isOpen = false;
|
|
1549
|
+
}, this.settings.timeoutDelay);
|
|
1550
|
+
if (this.settings.intervalMove) {
|
|
1551
|
+
clearInterval(this.settings.intervalMove);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
search(value) {
|
|
1555
|
+
if (this.render.content.search.input.value !== value) {
|
|
1556
|
+
this.render.content.search.input.value = value;
|
|
1557
|
+
}
|
|
1558
|
+
if (!this.events.search) {
|
|
1559
|
+
this.render.renderOptions(value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter));
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
this.render.renderSearching();
|
|
1563
|
+
const searchResp = this.events.search(value, this.store.getSelectedOptions());
|
|
1564
|
+
if (searchResp instanceof Promise) {
|
|
1565
|
+
searchResp
|
|
1566
|
+
.then((data) => {
|
|
1567
|
+
this.render.renderOptions(this.store.partialToFullData(data));
|
|
1568
|
+
})
|
|
1569
|
+
.catch((err) => {
|
|
1570
|
+
this.render.renderError(typeof err === 'string' ? err : err.message);
|
|
1571
|
+
});
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
else if (Array.isArray(searchResp)) {
|
|
1575
|
+
this.render.renderOptions(this.store.partialToFullData(searchResp));
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
this.render.renderError('Search event must return a promise or an array of data');
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
destroy() {
|
|
1582
|
+
document.removeEventListener('click', this.documentClick);
|
|
1583
|
+
window.removeEventListener('resize', this.windowResize, false);
|
|
1584
|
+
if (this.settings.openPosition === 'auto') {
|
|
1585
|
+
window.removeEventListener('scroll', this.windowScroll, false);
|
|
1586
|
+
}
|
|
1587
|
+
this.store.setData([]);
|
|
1588
|
+
this.render.destroy();
|
|
1589
|
+
this.select.destroy();
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
return SlimSelect;
|
|
1594
|
+
|
|
1595
|
+
}));
|