/** 消息管理:详情、选择与批量操作、发送计数及角色群发确认。仅本页入队。 */ (function () { 'use strict'; var root = document.querySelector('.aksrt-messages-admin'); if (!root) return; var compose = document.getElementById('aksrt-msg-compose'); var detail = document.getElementById('aksrt-msg-detail'); var confirmDialog = document.getElementById('aksrt-msg-confirm'); if (!compose || !detail || !confirmDialog || typeof compose.showModal !== 'function') return; function text(element, key, values) { var value = element.getAttribute('data-i18n-' + key) || ''; return value.replace(/\{(\w+)\}/g, function (match, name) { return values && values[name] !== undefined ? String(values[name]) : match; }); } function syncScroll() { document.documentElement.classList.toggle('aksrt-msg-modal-open', !!root.querySelector('dialog[open]')); } function open(dialog) { if (!dialog.open) dialog.showModal(); syncScroll(); } root.querySelectorAll('.aksrt-msg-dialog').forEach(function (dialog) { var outsideStart = false; function outside(event) { var rect = dialog.getBoundingClientRect(); return event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom; } dialog.querySelectorAll('[data-aksrt-dialog-close]').forEach(function (button) { button.addEventListener('click', function () { dialog.close(); }); }); dialog.addEventListener('pointerdown', function (event) { outsideStart = event.target === dialog && outside(event); }); dialog.addEventListener('click', function (event) { if (outsideStart && event.target === dialog && outside(event)) dialog.close(); outsideStart = false; }); dialog.addEventListener('close', syncScroll); }); var pending = null; var confirmButton = confirmDialog.querySelector('[data-aksrt-msg-confirm]'); function ask(title, message, label, danger, callback) { pending = callback; confirmDialog.querySelector('[data-aksrt-dialog-title]').textContent = title; confirmDialog.querySelector('#aksrt-msg-confirm-text').textContent = message; confirmButton.textContent = label; confirmButton.classList.toggle('aksrt-messages-admin__danger', danger); confirmButton.classList.toggle('button-primary', !danger); open(confirmDialog); confirmDialog.querySelector('[data-aksrt-dialog-close][autofocus]').focus(); } confirmDialog.addEventListener('cancel', function () { pending = null; }); confirmDialog.addEventListener('close', function () { pending = null; }); confirmButton.addEventListener('click', function () { var callback = pending; pending = null; confirmDialog.close(); if (callback) callback(); }); root.querySelectorAll('[data-aksrt-msg-view]').forEach(function (button) { button.addEventListener('click', function () { var template = document.getElementById('aksrt-msg-detail-' + button.getAttribute('data-aksrt-msg-view')); if (!template) return; detail.querySelector('[data-aksrt-msg-detail-body]').replaceChildren(template.content.cloneNode(true)); open(detail); }); }); var list = root.querySelector('[data-aksrt-msg-list]'); var listSubmitting = false; var syncSelection; if (list) { var checks = Array.from(list.querySelectorAll('[data-aksrt-msg-check]')); var checkAll = list.querySelector('[data-aksrt-msg-check-all]'); var selection = list.querySelector('[data-aksrt-msg-selection]'); var bulkButtons = list.querySelectorAll('[data-aksrt-msg-action]:not([data-id])'); function selected() { return checks.filter(function (check) { return check.checked; }); } syncSelection = function () { var count = selected().length; selection.textContent = selection.getAttribute('data-label').replace('%d', String(count)); checkAll.checked = count > 0 && count === checks.length; checkAll.indeterminate = count > 0 && count < checks.length; checkAll.disabled = listSubmitting || checks.length === 0; bulkButtons.forEach(function (button) { button.disabled = listSubmitting || count === 0; }); checks.forEach(function (check) { check.closest('tr').classList.toggle('is-selected', check.checked); }); }; checkAll.addEventListener('change', function () { checks.forEach(function (check) { check.checked = checkAll.checked; }); syncSelection(); }); checks.forEach(function (check) { check.addEventListener('change', syncSelection); }); function mutate(op, id) { if (listSubmitting) return; list.elements.bulk_action.value = op; list.elements.message_id.value = id || ''; list.requestSubmit(); } list.querySelectorAll('[data-aksrt-msg-action]').forEach(function (button) { button.addEventListener('click', function () { if (listSubmitting) return; var op = button.getAttribute('data-aksrt-msg-action'); var id = button.getAttribute('data-id'); var count = id ? 1 : selected().length; if (!count) return; if (op === 'delete') { ask(text(confirmDialog, 'delete-title'), text(confirmDialog, 'delete-text', { count: count }), text(confirmDialog, 'delete-send'), true, function () { mutate(op, id); }); } else { mutate(op, id); } }); }); list.addEventListener('submit', function (event) { if (listSubmitting || !list.elements.bulk_action.value || (!list.elements.message_id.value && !selected().length)) { event.preventDefault(); return; } listSubmitting = true; // 只锁操作按钮,不禁用复选框,否则 ids[] 不会随表单提交。 list.querySelectorAll('button').forEach(function (button) { button.disabled = true; }); syncSelection(); }); syncSelection(); } var form = compose.querySelector('[data-aksrt-msg-compose]'); var send = form.querySelector('[data-aksrt-msg-send]'); var role = form.elements.role; var counters = form.querySelectorAll('[data-count-limit]'); var sending = false; var approved = ''; function clearApproval() { approved = ''; form.elements.confirmed_role.value = ''; form.elements.confirmed_count.value = ''; } function syncCounters() { counters.forEach(function (field) { // 与 PHP mb_strlen 一致按 Unicode 码点计数,emoji 不占两个字。 var count = Array.from(field.value).length; var limit = Number(field.getAttribute('data-count-limit')); var counter = form.querySelector('[data-count-for="' + field.name + '"]'); counter.textContent = count + ' / ' + limit; counter.classList.toggle('is-over', count > limit); field.setCustomValidity(count > limit ? text(form, 'count-error', { count: limit }) : ''); }); } function syncRole() { var option = role.options[role.selectedIndex]; var count = option ? Number(option.getAttribute('data-count')) : 0; form.querySelector('[data-aksrt-msg-role-hint]').textContent = count > 0 && !option.disabled ? text(form, 'role-hint', { count: count }) : ''; } function mode() { return form.querySelector('input[name="recipient_mode"]:checked').value; } function syncMode() { clearApproval(); form.querySelectorAll('[data-aksrt-msg-pane]').forEach(function (pane) { var active = pane.getAttribute('data-aksrt-msg-pane') === mode(); pane.hidden = !active; pane.querySelectorAll('input, select, textarea').forEach(function (field) { field.disabled = !active; }); }); syncRole(); } form.querySelectorAll('input[name="recipient_mode"]').forEach(function (radio) { radio.addEventListener('change', syncMode); }); role.addEventListener('change', function () { clearApproval(); syncRole(); }); form.addEventListener('input', function () { clearApproval(); syncCounters(); }); function snapshot() { return JSON.stringify([role.value, role.options[role.selectedIndex].getAttribute('data-count'), form.elements.title.value, form.elements.content.value, form.elements.target_url.value]); } form.addEventListener('submit', function (event) { syncCounters(); if (sending || !form.reportValidity()) { event.preventDefault(); return; } if (mode() === 'role' && approved !== snapshot()) { event.preventDefault(); var option = role.options[role.selectedIndex]; if (!option || option.disabled || !role.value) return; var count = Number(option.getAttribute('data-count')); var current = snapshot(); ask(text(form, 'role-title'), text(form, 'role-confirm', { role: option.getAttribute('data-label'), count: count }), text(form, 'role-send'), false, function () { if (mode() !== 'role' || current !== snapshot()) return; approved = current; form.elements.confirmed_role.value = role.value; form.elements.confirmed_count.value = String(count); form.requestSubmit(send); }); return; } sending = true; send.disabled = true; }); root.querySelectorAll('[data-aksrt-dialog-open]').forEach(function (button) { button.addEventListener('click', function () { open(compose); var field = mode() === 'role' ? role : form.elements.users; field.focus(); }); }); window.addEventListener('pageshow', function () { sending = false; send.disabled = false; clearApproval(); if (list) { listSubmitting = false; list.elements.bulk_action.value = ''; list.elements.message_id.value = ''; list.querySelectorAll('button[data-id], button[data-aksrt-msg-view]').forEach(function (button) { button.disabled = false; }); syncSelection(); } syncCounters(); }); syncMode(); syncCounters(); if (compose.hasAttribute('data-aksrt-dialog-autoopen')) open(compose); })();