Files
pulse-signage/src/web/public/js/icon-picker.js
T
lzstealth 203d0bfc01
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m49s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s
Release 2.8.0
2026-08-16 17:15:31 +01:00

112 lines
4.9 KiB
JavaScript

(function () {
'use strict';
function initIconPicker(root) {
var select = root.querySelector('select');
var toggle = root.querySelector('[data-icon-picker-toggle]');
var menu = root.querySelector('[data-icon-picker-menu]');
var preview = root.querySelector('[data-icon-picker-preview]');
var label = root.querySelector('[data-icon-picker-label]');
var search = root.querySelector('[data-icon-picker-search]');
var close = root.querySelector('[data-icon-picker-close]');
var grid = root.querySelector('[data-icon-picker-grid]');
var empty = root.querySelector('[data-icon-picker-empty]');
var initialOptions = Array.prototype.slice.call(root.querySelectorAll('[data-icon-picker-option]'));
if (!select || !toggle || !menu || !grid) {
return;
}
function catalogOptions() {
return Array.prototype.slice.call(select.options).map(function (option) {
return { value: option.value, label: option.textContent || option.label || option.value };
});
}
function createOption(option, selectedValue) {
var button = document.createElement('button');
button.type = 'button';
button.className = 'announcement-icon-picker__option';
button.setAttribute('data-icon-picker-option', '');
button.setAttribute('data-icon-key', option.value);
button.setAttribute('data-icon-label', option.label);
button.setAttribute('aria-pressed', option.value === selectedValue ? 'true' : 'false');
button.title = option.label;
button.innerHTML = '<i class="bi bi-' + option.value + '" aria-hidden="true"></i><span class="visually-hidden">' + option.label + '</span>';
return button;
}
function getOptionLimit() {
var firstOption = grid.querySelector('[data-icon-picker-option]');
var gridStyle = window.getComputedStyle(grid);
var gap = parseFloat(gridStyle.columnGap || gridStyle.gap || '0') || 0;
var optionWidth = firstOption ? firstOption.getBoundingClientRect().width : 0;
var columns = optionWidth && grid.clientWidth
? Math.max(1, Math.floor((grid.clientWidth + gap) / (optionWidth + gap)))
: 4;
return columns * 6;
}
function updatePreview() {
var option = select.options[select.selectedIndex];
var value = option ? option.value : '';
if (preview) {
preview.className = 'announcement-icon-picker__toggle-icon bi bi-' + value;
}
if (label) {
label.textContent = option ? option.textContent : 'Select an icon';
}
root.querySelectorAll('[data-icon-picker-option]').forEach(function (optionButton) {
var selected = optionButton.getAttribute('data-icon-key') === value;
optionButton.classList.toggle('is-selected', selected);
optionButton.setAttribute('aria-pressed', selected ? 'true' : 'false');
});
}
function render(query) {
var normalizedQuery = String(query || '').trim().toLowerCase();
var selectedValue = String(select.value || '').trim();
var options = normalizedQuery
? catalogOptions().filter(function (option) { return (option.value + ' ' + option.label).toLowerCase().indexOf(normalizedQuery) !== -1; })
: initialOptions.map(function (option) { return { value: option.getAttribute('data-icon-key') || '', label: option.getAttribute('data-icon-label') || '' }; });
var visibleOptions = options.slice(0, getOptionLimit());
grid.innerHTML = '';
visibleOptions.forEach(function (option) { grid.appendChild(createOption(option, selectedValue)); });
if (empty) empty.hidden = options.length > 0;
updatePreview();
}
function closeMenu() {
menu.hidden = true;
toggle.setAttribute('aria-expanded', 'false');
}
toggle.addEventListener('click', function (event) {
event.preventDefault();
menu.hidden = !menu.hidden;
toggle.setAttribute('aria-expanded', menu.hidden ? 'false' : 'true');
if (!menu.hidden) {
render(search ? search.value : '');
if (search) search.focus();
}
});
if (close) close.addEventListener('click', function (event) { event.preventDefault(); closeMenu(); });
grid.addEventListener('click', function (event) {
var option = event.target.closest ? event.target.closest('[data-icon-picker-option]') : null;
if (!option) return;
select.value = option.getAttribute('data-icon-key') || '';
select.dispatchEvent(new Event('change', { bubbles: true }));
closeMenu();
});
if (search) search.addEventListener('input', function () { render(search.value); });
select.addEventListener('change', updatePreview);
document.addEventListener('click', function (event) {
if (!menu.hidden && !root.contains(event.target)) closeMenu();
});
updatePreview();
}
window.PulseIconPicker = { init: initIconPicker };
document.querySelectorAll('[data-icon-picker]').forEach(initIconPicker);
}());