123 lines
4.1 KiB
JavaScript
Executable File
123 lines
4.1 KiB
JavaScript
Executable File
export const ESCAPE_MAP = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
|
|
export function escapeHtml(str) {
|
|
if (!str) return '';
|
|
return String(str).replace(/[&<>"']/g, m => ESCAPE_MAP[m]);
|
|
}
|
|
|
|
export function showAlert(elementId, msg, type) {
|
|
const el = document.getElementById(elementId);
|
|
if (!el) return;
|
|
el.className = 'form-alert ' + type;
|
|
el.textContent = msg;
|
|
}
|
|
|
|
export function hideAlert(elementId) {
|
|
const el = document.getElementById(elementId);
|
|
if (!el) return;
|
|
el.className = 'form-alert';
|
|
el.textContent = '';
|
|
}
|
|
|
|
/** Форматирует календарную дату по локальным компонентам без UTC-сдвига. */
|
|
export function formatLocalDate(date) {
|
|
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
|
throw new TypeError('Ожидалась корректная дата');
|
|
}
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
export function renderStatusMessage(container, message, className = 'form-alert error') {
|
|
if (!container) return;
|
|
const element = document.createElement('div');
|
|
element.className = className;
|
|
element.textContent = message;
|
|
container.replaceChildren(element);
|
|
}
|
|
|
|
export function renderTableMessage(tbody, columnCount, message) {
|
|
if (!tbody) return;
|
|
const row = document.createElement('tr');
|
|
const cell = document.createElement('td');
|
|
cell.colSpan = columnCount;
|
|
cell.className = 'loading-row';
|
|
cell.textContent = message;
|
|
row.appendChild(cell);
|
|
tbody.replaceChildren(row);
|
|
}
|
|
|
|
export function applyRippleEffect() {
|
|
document.addEventListener('click', function (e) {
|
|
const btn = e.target.closest('.btn-primary, .btn-danger, .btn-danger-subtle, .btn-logout');
|
|
if (!btn) return;
|
|
|
|
const ripple = document.createElement('span');
|
|
ripple.classList.add('ripple');
|
|
btn.classList.add('ripple-host');
|
|
|
|
btn.appendChild(ripple);
|
|
|
|
setTimeout(() => ripple.remove(), 600);
|
|
});
|
|
}
|
|
|
|
export function initMultiSelect(boxId, menuId, textId, checkboxContainerId) {
|
|
const box = document.getElementById(boxId);
|
|
const menu = document.getElementById(menuId);
|
|
const container = document.getElementById(checkboxContainerId);
|
|
if (!box || !menu || !container) return;
|
|
|
|
// Remove old listeners to prevent duplication if re-initialized
|
|
const newBox = box.cloneNode(true);
|
|
box.parentNode.replaceChild(newBox, box);
|
|
|
|
newBox.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
const isOpen = menu.classList.contains('open');
|
|
document.querySelectorAll('.dropdown-menu').forEach(m => m.classList.remove('open'));
|
|
document.querySelectorAll('.select-box').forEach(b => b.classList.remove('active'));
|
|
if (!isOpen) {
|
|
menu.classList.add('open');
|
|
newBox.classList.add('active');
|
|
}
|
|
});
|
|
|
|
menu.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
});
|
|
|
|
container.addEventListener('change', () => {
|
|
updateSelectText(checkboxContainerId, textId);
|
|
});
|
|
}
|
|
|
|
export function updateSelectText(containerId, textId) {
|
|
const container = document.getElementById(containerId);
|
|
const textEl = document.getElementById(textId);
|
|
if (!container || !textEl) return;
|
|
const checked = Array.from(container.querySelectorAll('input:checked'));
|
|
if (checked.length === 0) {
|
|
textEl.textContent = 'Выберите оборудование...';
|
|
} else if (checked.length === 1) {
|
|
textEl.textContent = checked[0].parentElement.textContent.trim();
|
|
} else {
|
|
textEl.textContent = `Выбрано: ${checked.length}`;
|
|
}
|
|
}
|
|
|
|
export function closeAllDropdownsOnOutsideClick() {
|
|
document.addEventListener('click', () => {
|
|
document.querySelectorAll('.dropdown-menu').forEach(m => m.classList.remove('open'));
|
|
document.querySelectorAll('.select-box').forEach(b => b.classList.remove('active'));
|
|
});
|
|
}
|