373 lines
12 KiB
JavaScript
373 lines
12 KiB
JavaScript
function toggleMenu() {
|
|
const menu = document.getElementById("menu");
|
|
if (menu.style.display === "block") {
|
|
menu.style.display = "none";
|
|
} else {
|
|
menu.style.display = "block";
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize function, create initial tokens with itens that are already selected by the user
|
|
function init(element) {
|
|
// Create div that wroaps all the elements inside (select, elements selected, search div) to put select inside
|
|
const wrapper = document.createElement("div");
|
|
wrapper.addEventListener("click", clickOnWrapper);
|
|
wrapper.classList.add("multi-select-component");
|
|
wrapper.classList.add("input-field");
|
|
|
|
// Create elements of search
|
|
const search_div = document.createElement("div");
|
|
search_div.classList.add("search-container");
|
|
const input = document.createElement("input");
|
|
input.classList.add("selected-input");
|
|
input.setAttribute("autocomplete", "off");
|
|
input.setAttribute("tabindex", "0");
|
|
input.addEventListener("keyup", inputChange);
|
|
input.addEventListener("keydown", deletePressed);
|
|
input.addEventListener("click", openOptions);
|
|
|
|
const dropdown_icon = document.createElement("a");
|
|
dropdown_icon.setAttribute("href", "#");
|
|
dropdown_icon.classList.add("dropdown-icon");
|
|
|
|
dropdown_icon.addEventListener("click", clickDropdown);
|
|
const autocomplete_list = document.createElement("ul");
|
|
autocomplete_list.classList.add("autocomplete-list");
|
|
search_div.appendChild(input);
|
|
search_div.appendChild(autocomplete_list);
|
|
search_div.appendChild(dropdown_icon);
|
|
|
|
// set the wrapper as child (instead of the element)
|
|
element.parentNode.replaceChild(wrapper, element);
|
|
// set element as child of wrapper
|
|
wrapper.appendChild(element);
|
|
wrapper.appendChild(search_div);
|
|
|
|
addPlaceholder(wrapper);
|
|
|
|
// const select = document.querySelector(".select-field");
|
|
// for (const process of processeList) {
|
|
// const option = document.createElement("option");
|
|
// option.setAttribute("value", process.name);
|
|
// option.innerText = process.name;
|
|
|
|
// select.appendChild(option);
|
|
// }
|
|
}
|
|
|
|
function removePlaceholder(wrapper) {
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
input_search.removeAttribute("placeholder");
|
|
}
|
|
|
|
function addPlaceholder(wrapper) {
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
const tokens = wrapper.querySelectorAll(".selected-wrapper");
|
|
if (!tokens.length && !(document.activeElement === input_search))
|
|
input_search.setAttribute("placeholder", "---------");
|
|
}
|
|
|
|
// Listener of user search
|
|
function inputChange(e) {
|
|
const wrapper = e.target.parentNode.parentNode;
|
|
const select = wrapper.querySelector("select");
|
|
const dropdown = wrapper.querySelector(".dropdown-icon");
|
|
|
|
const input_val = e.target.value;
|
|
|
|
if (input_val) {
|
|
dropdown.classList.add("active");
|
|
populateAutocompleteList(select, input_val.trim());
|
|
} else {
|
|
dropdown.classList.remove("active");
|
|
const event = new Event("click");
|
|
dropdown.dispatchEvent(event);
|
|
}
|
|
}
|
|
|
|
// Listen for clicks on the wrapper, if click happens focus on the input
|
|
function clickOnWrapper(e) {
|
|
const wrapper = e.target;
|
|
if (wrapper.tagName == "DIV") {
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
const dropdown = wrapper.querySelector(".dropdown-icon");
|
|
if (!dropdown.classList.contains("active")) {
|
|
const event = new Event("click");
|
|
dropdown.dispatchEvent(event);
|
|
}
|
|
input_search.focus();
|
|
removePlaceholder(wrapper);
|
|
}
|
|
}
|
|
|
|
function openOptions(e) {
|
|
const input_search = e.target;
|
|
const wrapper = input_search.parentElement.parentElement;
|
|
const dropdown = wrapper.querySelector(".dropdown-icon");
|
|
if (!dropdown.classList.contains("active")) {
|
|
const event = new Event("click");
|
|
dropdown.dispatchEvent(event);
|
|
}
|
|
e.stopPropagation();
|
|
}
|
|
|
|
// Function that create a token inside of a wrapper with the given value
|
|
function createToken(wrapper, value) {
|
|
const search = wrapper.querySelector(".search-container");
|
|
const inputInderline = document.querySelector(".selected-processes");
|
|
// Create token wrapper
|
|
const token = document.createElement("div");
|
|
token.classList.add("selected-wrapper");
|
|
const token_span = document.createElement("span");
|
|
token_span.classList.add("selected-label");
|
|
token_span.innerText = value;
|
|
const close = document.createElement("a");
|
|
close.classList.add("selected-close");
|
|
close.setAttribute("tabindex", "-1");
|
|
close.setAttribute("data-option", value);
|
|
close.setAttribute("data-hits", 0);
|
|
close.setAttribute("href", "#");
|
|
close.innerText = "x";
|
|
close.addEventListener("click", removeToken);
|
|
token.appendChild(token_span);
|
|
token.appendChild(close);
|
|
inputInderline.appendChild(token);
|
|
}
|
|
|
|
// Listen for clicks in the dropdown option
|
|
function clickDropdown(e) {
|
|
const dropdown = e.target;
|
|
const wrapper = dropdown.parentNode.parentNode;
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
const select = wrapper.querySelector("select");
|
|
dropdown.classList.toggle("active");
|
|
|
|
if (dropdown.classList.contains("active")) {
|
|
removePlaceholder(wrapper);
|
|
input_search.focus();
|
|
|
|
if (!input_search.value) {
|
|
populateAutocompleteList(select, "", true);
|
|
} else {
|
|
populateAutocompleteList(select, input_search.value);
|
|
}
|
|
} else {
|
|
clearAutocompleteList(select);
|
|
addPlaceholder(wrapper);
|
|
}
|
|
}
|
|
|
|
// Clears the results of the autocomplete list
|
|
function clearAutocompleteList(select) {
|
|
const wrapper = select.parentNode;
|
|
|
|
const autocomplete_list = wrapper.querySelector(".autocomplete-list");
|
|
autocomplete_list.innerHTML = "";
|
|
}
|
|
|
|
// Populate the autocomplete list following a given query from the user
|
|
function populateAutocompleteList(select, query, dropdown = false) {
|
|
const { autocomplete_options } = getOptions(select);
|
|
|
|
let options_to_show;
|
|
|
|
if (dropdown) options_to_show = autocomplete_options;
|
|
else options_to_show = autocomplete(query, autocomplete_options);
|
|
|
|
const wrapper = select.parentNode;
|
|
const input_search = wrapper.querySelector(".search-container");
|
|
const autocomplete_list = wrapper.querySelector(".autocomplete-list");
|
|
autocomplete_list.innerHTML = "";
|
|
const result_size = options_to_show.length;
|
|
|
|
if (result_size == 1) {
|
|
const li = document.createElement("li");
|
|
li.innerText = options_to_show[0];
|
|
li.setAttribute("data-value", options_to_show[0]);
|
|
li.addEventListener("click", selectOption);
|
|
autocomplete_list.appendChild(li);
|
|
if (query.length == options_to_show[0].length) {
|
|
const event = new Event("click");
|
|
li.dispatchEvent(event);
|
|
}
|
|
} else if (result_size > 1) {
|
|
for (let i = 0; i < result_size; i++) {
|
|
const li = document.createElement("li");
|
|
li.innerText = options_to_show[i];
|
|
li.setAttribute("data-value", options_to_show[i]);
|
|
li.addEventListener("click", selectOption);
|
|
autocomplete_list.appendChild(li);
|
|
}
|
|
} else {
|
|
const li = document.createElement("li");
|
|
li.classList.add("not-cursor");
|
|
li.innerText = "No options found";
|
|
autocomplete_list.appendChild(li);
|
|
}
|
|
}
|
|
|
|
// Listener to autocomplete results when clicked set the selected property in the select option
|
|
function selectOption(e) {
|
|
const wrapper = e.target.parentNode.parentNode.parentNode;
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
const option = wrapper.querySelector(
|
|
`select option[value="${e.target.dataset.value}"]`
|
|
);
|
|
|
|
option.setAttribute("selected", "");
|
|
createToken(wrapper, e.target.dataset.value);
|
|
if (input_search.value) {
|
|
input_search.value = "";
|
|
}
|
|
|
|
// showSelectedProcess(e.target.dataset.value);
|
|
|
|
input_search.focus();
|
|
|
|
e.target.remove();
|
|
const autocomplete_list = wrapper.querySelector(".autocomplete-list");
|
|
|
|
if (!autocomplete_list.children.length) {
|
|
const li = document.createElement("li");
|
|
li.classList.add("not-cursor");
|
|
li.innerText = "No options found";
|
|
autocomplete_list.appendChild(li);
|
|
}
|
|
|
|
const event = new Event("keyup");
|
|
input_search.dispatchEvent(event);
|
|
e.stopPropagation();
|
|
}
|
|
|
|
// function that returns a list with the autcomplete list of matches
|
|
function autocomplete(query, options) {
|
|
// No query passed, just return entire list
|
|
if (!query) {
|
|
return options;
|
|
}
|
|
let options_return = [];
|
|
|
|
for (let i = 0; i < options.length; i++) {
|
|
if (
|
|
query.toLowerCase() === options[i].slice(0, query.length).toLowerCase()
|
|
) {
|
|
options_return.push(options[i]);
|
|
}
|
|
}
|
|
return options_return;
|
|
}
|
|
|
|
// Returns the options that are selected by the user and the ones that are not
|
|
function getOptions(select) {
|
|
// Select all the options available
|
|
const all_options = Array.from(select.querySelectorAll("option")).map(
|
|
(el) => el.value
|
|
);
|
|
|
|
// Get the options that are selected from the user
|
|
const options_selected = Array.from(
|
|
select.querySelectorAll("option:checked")
|
|
).map((el) => el.value);
|
|
|
|
// Create an autocomplete options array with the options that are not selected by the user
|
|
const autocomplete_options = [];
|
|
all_options.forEach((option) => {
|
|
if (!options_selected.includes(option)) {
|
|
autocomplete_options.push(option);
|
|
}
|
|
});
|
|
|
|
autocomplete_options.sort();
|
|
|
|
return {
|
|
options_selected,
|
|
autocomplete_options,
|
|
};
|
|
}
|
|
|
|
// Listener for when the user wants to remove a given token.
|
|
function removeToken(e) {
|
|
// Get the value to remove
|
|
const value_to_remove = e.target.dataset.option;
|
|
const wrapper = e.target.parentNode.parentNode.parentNode;
|
|
const input_search = wrapper.querySelector(".selected-input");
|
|
const dropdown = wrapper.querySelector(".dropdown-icon");
|
|
// Get the options in the select to be unselected
|
|
const option_to_unselect = wrapper.querySelector(
|
|
`select option[value="${value_to_remove}"]`
|
|
);
|
|
option_to_unselect.removeAttribute("selected");
|
|
// Remove token attribute
|
|
e.target.parentNode.remove();
|
|
dropdown.classList.remove("active");
|
|
const process = document.querySelector("#" + e.target.dataset.option);
|
|
process.remove();
|
|
}
|
|
|
|
// Listen for 2 sequence of hits on the delete key, if this happens delete the last token if exist
|
|
function deletePressed(e) {
|
|
const wrapper = e.target.parentNode.parentNode;
|
|
const input_search = e.target;
|
|
const key = e.keyCode || e.charCode;
|
|
const tokens = wrapper.querySelectorAll(".selected-wrapper");
|
|
|
|
if (tokens.length) {
|
|
const last_token_x = tokens[tokens.length - 1].querySelector("a");
|
|
let hits = +last_token_x.dataset.hits;
|
|
|
|
if (key == 8 || key == 46) {
|
|
if (!input_search.value) {
|
|
if (hits > 1) {
|
|
// Trigger delete event
|
|
const event = new Event("click");
|
|
last_token_x.dispatchEvent(event);
|
|
} else {
|
|
last_token_x.dataset.hits = 2;
|
|
}
|
|
}
|
|
} else {
|
|
last_token_x.dataset.hits = 0;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function addOption(target, val, text) {
|
|
const select = document.querySelector(target);
|
|
let opt = document.createElement("option");
|
|
opt.value = val;
|
|
opt.innerHTML = text;
|
|
select.appendChild(opt);
|
|
}
|
|
|
|
// get select that has the options available
|
|
const select = document.querySelectorAll("[data-multi-select-plugin]");
|
|
select.forEach((select) => {
|
|
console.log(select);
|
|
init(select);
|
|
});
|
|
|
|
// Dismiss on outside click
|
|
document.addEventListener("click", () => {
|
|
// get select that has the options available
|
|
const select = document.querySelectorAll("[data-multi-select-plugin]");
|
|
for (let i = 0; i < select.length; i++) {
|
|
if (event) {
|
|
var isClickInside = select[i].parentElement.parentElement.contains(
|
|
event.target
|
|
);
|
|
|
|
if (!isClickInside) {
|
|
const wrapper = select[i].parentElement.parentElement;
|
|
const dropdown = wrapper.querySelector(".dropdown-icon");
|
|
const autocomplete_list = wrapper.querySelector(".autocomplete-list");
|
|
//the click was outside the specifiedElement, do something
|
|
dropdown.classList.remove("active");
|
|
autocomplete_list.innerHTML = "";
|
|
addPlaceholder(wrapper);
|
|
}
|
|
}
|
|
}
|
|
});
|