| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- window.makeMultiselect = (items => {
- class MultiSelect {
- #htmlSelectElement;
- #htmlRootElement;
- #htmlInput;
- #htmlInputList;
- #htmlWrapper;
- #htmlDropdown;
- #ignoreMouseOut = false;
- #options = [];
- #eventHandlers = [];
- constructor(htmlElement) {
- this.#htmlSelectElement = htmlElement;
- this.#htmlRootElement = htmlElement.parentElement;
- for (let i of this.#htmlSelectElement.querySelectorAll("option"))
- this.#options.push({
- value: i.textContent,
- checked: !!i.selected,
- indeterminate: !!i.indeterminate,
- htmlListItem: null
- });
- }
- addEventListener(fncHandler) {
- this.#eventHandlers.push(fncHandler);
- }
- #onUpdate() {
- for (let i of this.#eventHandlers)
- i(this.#options);
- }
- #updateTextInputValue() {
- this.#htmlInputList.textContent = "";
- this.#htmlInputList.appendChild(this.#htmlInput);
- for (let i in this.#options) {
- if (this.#options[i].checked) {
- let li = document.createElement("li");
- let closeBt = document.createElement("a");
- closeBt.href = "#";
- closeBt.textContent = "x";
- closeBt.addEventListener("click", e => {
- this.#options[i].checked = false;
- this.#options[i].indeterminate = false;
- this.#rebuildDropdownContent();
- this.#updateTextInputValue();
- this.#onUpdate();
- e.preventDefault();
- });
- li.textContent = this.#options[i].value;
- li.className = "checked";
- li.appendChild(closeBt);
- if (this.#options[i].indeterminate)
- li.classList.add("indeterminate");
- this.#htmlInputList.insertBefore(li, this.#htmlInput);
- }
- }
- }
- #rebuildDropdownContent() {
- this.#htmlDropdown.textContent = "";
- for (let i in this.#options) {
- let wrapper = document.createElement("li");
- let lbl = document.createElement("label");
- let chk = document.createElement("input");
- let span = document.createElement("span");
- span.textContent = this.#options[i].value;
- chk.type = "checkbox";
- chk.checked = !!this.#options[i].checked;
- chk.indeterminate = !!this.#options[i].indeterminate;
- chk.index = i;
- lbl.appendChild(chk);
- lbl.appendChild(span);
- wrapper.appendChild(lbl);
- this.#htmlDropdown.appendChild(wrapper);
- this.#options[i].htmlListItem = wrapper;
- chk.addEventListener("change", e => {
- let state = this.#options[e.currentTarget.index];
- if (!state.checked) {
- e.currentTarget.checked = true;
- e.currentTarget.indeterminate = false;
- } else if (!state.indeterminate) {
- e.currentTarget.checked = true;
- e.currentTarget.indeterminate = true;
- } else {
- e.currentTarget.checked = false;
- e.currentTarget.indeterminate = false;
- }
- state.checked = e.currentTarget.checked;
- state.indeterminate = e.currentTarget.indeterminate;
- e.stopImmediatePropagation();
- this.#updateTextInputValue();
- this.#onUpdate();
- });
- }
- }
- render() {
- this.#htmlSelectElement.style.display = "none";
- if (!this.#htmlInput) {
- this.#htmlInput = document.createElement("input");
- this.#htmlInput.className = "multiselect-input";
- this.#htmlInput.type = "text";
- this.#htmlInput.addEventListener("input", e => {
- let input = e.currentTarget.value.toLocaleLowerCase();
- for (let i of this.#options) {
- if (i.value.toLocaleLowerCase().indexOf(input) >= 0) {
- i.htmlListItem.classList.remove("hidden");
- } else {
- i.htmlListItem.classList.add("hidden");
- }
- }
- });
- this.#htmlInputList && this.#htmlInputList.appendChild(this.#htmlInput);
- }
- if (!this.#htmlInputList) {
- this.#htmlInputList = document.createElement("ul");
- this.#htmlInputList.className = "multiselect-inputlist";
- this.#htmlRootElement && this.#htmlRootElement.appendChild(this.#htmlInputList);
- this.#htmlInputList.appendChild(this.#htmlInput);
- }
- if (!this.#htmlDropdown) {
- this.#htmlDropdown = document.createElement("ul");
- this.#htmlDropdown.className = "multiselect-dropdown";
- this.#htmlDropdown.classList.add("hidden");
- this.#htmlRootElement && this.#htmlRootElement.appendChild(this.#htmlDropdown);
- }
- if (!this.#htmlWrapper) {
- this.#htmlWrapper = document.createElement("div");
- this.#htmlWrapper.className = "multiselect-wrapper";
- this.#htmlWrapper.appendChild(this.#htmlInputList);
- this.#htmlWrapper.appendChild(this.#htmlDropdown);
- this.#htmlRootElement.appendChild(this.#htmlWrapper);
- this.#htmlRootElement.addEventListener("mousedown", e => {
- this.#ignoreMouseOut = setTimeout(() => { this.#ignoreMouseOut = false; }, 500);
- });
- this.#htmlWrapper.addEventListener("focusin", e => {
- this.#htmlDropdown.classList.remove("hidden");
- });
- this.#htmlWrapper.addEventListener("focusout", e => {
- this.#ignoreMouseOut === false && this.#htmlDropdown.classList.add("hidden");
- });
- document.body.addEventListener("click", e => {
- this.#ignoreMouseOut === false && this.#htmlDropdown.classList.add("hidden");
- });
- }
- this.#rebuildDropdownContent();
- this.#updateTextInputValue();
- }
- }
- _makeMultiSelect = htmlElement => {
- let select = new MultiSelect(htmlElement);
- select.render();
- return select;
- };
- if (items instanceof HTMLElement)
- return _makeMultiSelect(items);
- else if (items.length)
- return Array.from(items).map(i => window.makeMultiselect(i));
- });
|