const getStoredTheme = () => localStorage.getItem("theme"); const setStoredTheme = theme => localStorage.setItem("theme", theme); const getPreferredTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; $('input[name="themeToggle"]').on("change", function() { const selectedTheme = $(this).val(); setStoredTheme(selectedTheme); setThemeIcon(selectedTheme) applyTheme(selectedTheme); }); // on page load function initThemeChoice() { const theme = getStoredTheme() || "auto"; // If the user is new, they won't have a set theme, so default to auto setThemeIcon(theme); applyTheme(theme); } function setThemeIcon(theme) { const iconOptions = { light: "bi-sun", dark: "bi-moon-stars", auto: "bi-circle-half" } if (!Object.keys(iconOptions).includes(theme)) { throw new Error(`No icon for theme: ${theme}`); } $(".js-themeMenuBtn > i").removeClass(Object.values(iconOptions).join(" ")); $(".js-themeMenuBtn > i").addClass(iconOptions[theme]); } function applyTheme(theme) { $('input[name="themeToggle"]').siblings("label").removeClass("active"); $(`input[name="themeToggle"][value="${theme}"]`).siblings("label").addClass("active"); if (!theme || theme === "auto") { theme = getPreferredTheme(); } $("body").attr("data-bs-theme", theme); } function getCurrentDateTime() { var now = new Date(); var year = now.getFullYear(); var month = String(now.getMonth() + 1).padStart(2, '0'); var day = String(now.getDate()).padStart(2, '0'); var hours = String(now.getHours()).padStart(2, '0'); var minutes = String(now.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day}T${hours}:${minutes}`; } // Sanitise a given string to remove HTML, making it DOM safe. function sanitise(string) { if (typeof string !== "string") { return string; } const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', "/": '/', }; const reg = /[&<>"'/]/ig; return string.replace(reg, (match) => map[match]); } $(document).ready(function() { // Activate all tooltips $('[data-bs-toggle="tooltip"]').tooltip(); // Activate select2s $(".select-2").each(function() { $(this).select2({ theme: "bootstrap", minimumResultsForSearch: 10 }); }); $(".corbz-select").each(function() { $(this).initCorbzSelect(); }); $.notify.addStyle("bootstrap", { html: '" }); $.notify.defaults({ globalPosition: "bottom right", animationType: "fade", className: "success" }); // Activate datepickers // $(".input-group.date").datepicker({format: "yyyy-mm-dd"}); // Load theme initThemeChoice(); }); // region Custom Select Control (($) => { function initCorbzSelect() { const defaultSelectedHtml = " "; const updateSelectedDisplay = ($select, $selected, $dropdown, settings) => { let values = $select.val() || []; let names = []; if (!Array.isArray(values)) { values = [values] }; // Update names based on values $select.find("option").each(function() { if (values.includes($(this).val())) { names.push($(this).text()); } }); const len = values.length; const total = $select.find("option").length; if (len === 0) { $selected.html(defaultSelectedHtml); } else if (len === total && total > 3) {$selected.text("All Selected")} else if (len > 3) { $selected.text(`${values.length} Selected`); } else { names ? $selected.text(names.join(", ")) : $selected.html(defaultSelectedHtml); } if (!settings.multiple) { $dropdown.find(".corbz-select-option").removeClass("active").each(function() { if (names.includes($(this).data("name"))) { $(this).addClass("active"); } }); } $dropdown.find(".corbz-option-checkbox").each(function() { $(this).prop("checked", values.includes($(this).val())); }); } this.each(function() { // The original select element, this will be hidden and replaced // with the custom input 'container' const $select = $(this); // The custom input to replace the original select const $container = $('
'); // Contains text indicating the 'selected' options, acts as a // button to open the dropdown. const $selected = $('
'); $selected.html(defaultSelectedHtml); // The dropdown box when accessing the container const $dropdown = $('
'); // Search input to filter the dropdown results const $search = $(''); const $optionsContainer = $('
'); const settings = { id: $select.prop("id"), multiple: $select.prop("multiple"), required: $select.prop("required"), disabled: $select.prop("disabled"), minResultsForSearch: 5 } // Add custom elements to the DOM $dropdown.prepend($search); $dropdown.append($optionsContainer) $container.append($selected).append($dropdown); $select.hide().after($container); // Show/Hide the dropdown when clicking the custom input $selected.on("click", function(event) { event.stopPropagation(); $(".corbz-select-dropdown").not($dropdown).hide(); $(".corbz-select-container").not($container).removeClass("active"); $dropdown.toggle(); $container.toggleClass("active", $dropdown.is(":visible")); }); // Hide dropdown if clicking outside $(document).on('click', function() { $dropdown.hide(); $container.removeClass("active"); // Reset search filtering $search.val(""); $search.trigger("keyup"); }); // Use or hide search $search.toggle($select.find("option").length > settings.minResultsForSearch); // Prevent closing the dropdown when selecting the search input $search.on("click", function (event) { event.stopPropagation(); }); // Search to filter through options $search.on("keyup", function () { const searchValue = $(this).val().toLowerCase(); $dropdown.find(".corbz-select-option").each(function() { const optionText = $(this).text().toLowerCase(); $(this).toggle(optionText.includes(searchValue)) }) }); const updateSelectedDisplayWrapper = () => { updateSelectedDisplay($select, $selected, $dropdown, settings) } const onOptionSelect = $option => { $dropdown.hide(); $container.removeClass("active"); $select.val($option.data("value")).trigger("change"); updateSelectedDisplayWrapper(); } $select.find("option").each(function() { const $option = $('
'); $option.data("name", $(this).text()); $option.data("value", $(this).val()); if (!settings.multiple) { $option.text($(this).text()); $option.on("click", () => onOptionSelect($option)); } else { const $checkbox = $(``).val($(this).val()); const $label = $("").text($(this).text()); $option.prepend($checkbox).append($label); $option.on("click", function(event) { event.stopPropagation(); // Handle if the user clicked inside the checkbox itself if (!$(event.target).hasClass("corbz-option-checkbox")) { $checkbox.prop("checked", !$checkbox.prop("checked")); } const selectedElems = $dropdown.find(`input[type="checkbox"][name="${settings.id}"]:checked`).map(function() { return $(this).closest(".corbz-select-option"); }); // Get and internally set the selected values const selectedVals = selectedElems.map(function() { return this.data("value"); }); $select.val(selectedVals).trigger("change"); updateSelectedDisplayWrapper(); }); } $optionsContainer.append($option) }); // For no options, display a message if (!$select.find("option").length) { const $noOptions = $('
'); $noOptions.text("No options available"); $dropdown.append($noOptions); } // Initialize display, and detect future changes updateSelectedDisplayWrapper(); $select.on("change", updateSelectedDisplayWrapper); }); } $.fn.initCorbzSelect = initCorbzSelect; })(jQuery);