"use strict"; { const getOptionGroupName = (option) => option.parentElement.label; const SelectBox = { cache: {}, init: function (id) { const box = document.getElementById(id); SelectBox.cache[id] = []; const cache = SelectBox.cache[id]; for (const node of box.options) { const group = getOptionGroupName(node); cache.push({ group, value: node.value, text: node.text, displayed: 1, }); } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) if (cache.some((item) => item.group)) { SelectBox.sort(id); } }, redisplay: function (id) { // Repopulate HTML select box from cache const box = document.getElementById(id); const scroll_value_from_top = box.scrollTop; box.innerHTML = ""; let node = box; let currentOptgroup = null; for (const option of SelectBox.cache[id]) { if (option.displayed) { // Create a new optgroup when the group changes if (option.group && option.group !== currentOptgroup) { currentOptgroup = option.group; node = document.createElement("optgroup"); node.setAttribute("label", option.group); box.appendChild(node); } else if (!option.group && currentOptgroup !== null) { // Back to ungrouped options currentOptgroup = null; node = box; } const new_option = new Option( option.text, option.value, false, false, ); // Shows a tooltip when hovering over the option new_option.title = option.text; node.appendChild(new_option); } } box.scrollTop = scroll_value_from_top; }, filter: function (id, text) { // Redisplay the HTML select box, displaying only the choices containing ALL // the words in text. (It's an AND search.) const tokens = text.toLowerCase().split(/\s+/); for (const node of SelectBox.cache[id]) { node.displayed = 1; const node_text = node.text.toLowerCase(); for (const token of tokens) { if (!node_text.includes(token)) { node.displayed = 0; break; // Once the first token isn't found we're done } } } SelectBox.redisplay(id); }, get_hidden_node_count(id) { const cache = SelectBox.cache[id] || []; return cache.filter((node) => node.displayed === 0).length; }, delete_from_cache: function (id, value) { let delete_index = null; const cache = SelectBox.cache[id]; for (const [i, node] of cache.entries()) { if (node.value === value) { delete_index = i; break; } } cache.splice(delete_index, 1); }, add_to_cache: function (id, option) { SelectBox.cache[id].push({ group: option.group, value: option.value, text: option.text, displayed: 1, }); }, cache_contains: function (id, value) { // Check if an item is contained in the cache for (const node of SelectBox.cache[id]) { if (node.value === value) { return true; } } return false; }, move: function (from, to) { const from_box = document.getElementById(from); for (const option of from_box.options) { const option_value = option.value; if ( option.selected && SelectBox.cache_contains(from, option_value) ) { const group = getOptionGroupName(option); SelectBox.add_to_cache(to, { group, value: option_value, text: option.text, displayed: 1, }); SelectBox.delete_from_cache(from, option_value); } } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) if (SelectBox.cache[to].some((item) => item.group)) { SelectBox.sort(to); } SelectBox.redisplay(from); SelectBox.redisplay(to); }, move_all: function (from, to) { const from_box = document.getElementById(from); for (const option of from_box.options) { const option_value = option.value; if (SelectBox.cache_contains(from, option_value)) { const group = getOptionGroupName(option); SelectBox.add_to_cache(to, { group, value: option_value, text: option.text, displayed: 1, }); SelectBox.delete_from_cache(from, option_value); } } // Only sort if there are any groups (to preserve existing behavior for non-grouped selects) if (SelectBox.cache[to].some((item) => item.group)) { SelectBox.sort(to); } SelectBox.redisplay(from); SelectBox.redisplay(to); }, sort: function (id) { SelectBox.cache[id].sort(function (a, b) { a = ((a.group && a.group.toLowerCase()) || "") + a.text.toLowerCase(); b = ((b.group && b.group.toLowerCase()) || "") + b.text.toLowerCase(); if (a > b) { return 1; } if (a < b) { return -1; } return 0; }); }, select_all: function (id) { const box = document.getElementById(id); for (const option of box.options) { option.selected = true; } }, }; window.SelectBox = SelectBox; }