Replace standalone add and export views with accessible dialogs, refine list interactions, and remove obsolete paths and unused counts. Fix filtered totals and reject oversized imports without truncation, with regression coverage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
159 lines
6.5 KiB
JavaScript
159 lines
6.5 KiB
JavaScript
/** 邀请码管理:弹窗、条件表单、复制与批量选择。仅本页入队。 */
|
|
(function () {
|
|
'use strict';
|
|
|
|
var root = document.querySelector('.aksrt-inv-page');
|
|
if (!root) return;
|
|
var toast = root.querySelector('[data-aksrt-inv-toast]');
|
|
var toastTimer;
|
|
var add = root.querySelector('#aksrt-inv-add');
|
|
var addForm = add.querySelector('form');
|
|
var addSubmit = add.querySelector('[data-aksrt-inv-add-submit]');
|
|
var importing = addForm.elements.import_data;
|
|
|
|
function notify(key) {
|
|
clearTimeout(toastTimer);
|
|
toast.textContent = toast.getAttribute('data-' + key);
|
|
toast.classList.add('is-visible');
|
|
toastTimer = setTimeout(function () { toast.classList.remove('is-visible'); }, 4000);
|
|
}
|
|
|
|
function syncForm(form) {
|
|
form.querySelectorAll('[data-aksrt-inv-dep]').forEach(function (pane) {
|
|
var parts = pane.getAttribute('data-aksrt-inv-dep').split('=');
|
|
var field = form.querySelector('[name="' + parts[0] + '"]:checked') || form.querySelector('[name="' + parts[0] + '"]');
|
|
var value = field && field.type === 'checkbox' ? (field.checked ? field.value : '') : field && field.value;
|
|
var active = !!field && !field.matches(':disabled') && parts[1].split('|').includes(value);
|
|
pane.hidden = !active;
|
|
pane.disabled = !active;
|
|
});
|
|
if (form === addForm && !form.dataset.submitting) {
|
|
addSubmit.textContent = addSubmit.getAttribute(form.elements.add_type.value === 'import' ? 'data-import-label' : 'data-auto-label');
|
|
}
|
|
}
|
|
|
|
root.querySelectorAll('.aksrt-inv-dialog').forEach(function (dialog) {
|
|
var opener;
|
|
var startedOutside = 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;
|
|
}
|
|
root.querySelectorAll('[data-aksrt-dialog-open="' + dialog.id + '"]').forEach(function (button) {
|
|
button.addEventListener('click', function () {
|
|
opener = button;
|
|
syncForm(dialog.querySelector('form'));
|
|
dialog.showModal();
|
|
document.documentElement.classList.add('aksrt-inv-modal-open');
|
|
});
|
|
});
|
|
dialog.querySelectorAll('[data-aksrt-dialog-close]').forEach(function (button) {
|
|
button.addEventListener('click', function () { dialog.close(); });
|
|
});
|
|
dialog.addEventListener('pointerdown', function (event) {
|
|
startedOutside = event.target === dialog && outside(event);
|
|
});
|
|
dialog.addEventListener('click', function (event) {
|
|
if (startedOutside && event.target === dialog && outside(event)) dialog.close();
|
|
startedOutside = false;
|
|
});
|
|
dialog.addEventListener('close', function () {
|
|
document.documentElement.classList.toggle('aksrt-inv-modal-open', !!root.querySelector('dialog[open]'));
|
|
if (opener && opener.isConnected) opener.focus();
|
|
});
|
|
var form = dialog.querySelector('form');
|
|
form.addEventListener('change', function () { syncForm(form); });
|
|
syncForm(form);
|
|
});
|
|
|
|
root.addEventListener('click', async function (event) {
|
|
var button = event.target.closest('[data-clipboard-text]');
|
|
if (!button) return;
|
|
var value = button.getAttribute('data-clipboard-text');
|
|
try {
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
await navigator.clipboard.writeText(value);
|
|
} else {
|
|
var input = document.createElement('textarea');
|
|
input.value = value;
|
|
input.className = 'screen-reader-text';
|
|
root.appendChild(input);
|
|
input.select();
|
|
var copied = false;
|
|
try {
|
|
copied = document.execCommand('copy');
|
|
} finally {
|
|
input.remove();
|
|
button.focus();
|
|
}
|
|
if (!copied) throw new Error('copy');
|
|
}
|
|
notify('copied');
|
|
} catch (error) {
|
|
var range = document.createRange();
|
|
range.selectNodeContents(button);
|
|
var selection = window.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
notify('copy-failed');
|
|
}
|
|
});
|
|
|
|
addForm.addEventListener('submit', function (event) {
|
|
if (addForm.dataset.submitting) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
addForm.dataset.submitting = '1';
|
|
addSubmit.disabled = true;
|
|
addSubmit.textContent = addSubmit.getAttribute('data-busy-label');
|
|
});
|
|
importing.addEventListener('input', function () {
|
|
var count = importing.value.split(/\r\n|\r|\n/).filter(function (line) { return line.trim() !== ''; }).length;
|
|
importing.setCustomValidity(count > 1000 ? importing.getAttribute('data-limit-error') : '');
|
|
});
|
|
root.querySelector('#aksrt-inv-export form').addEventListener('submit', function () {
|
|
root.querySelector('#aksrt-inv-export').close();
|
|
notify('exported');
|
|
});
|
|
|
|
var list = root.querySelector('[data-aksrt-inv-list]');
|
|
var checks = Array.from(list.querySelectorAll('[name="action_id[]"]'));
|
|
var checkAll = list.querySelector('[data-aksrt-inv-check-all]');
|
|
var selection = list.querySelector('[data-aksrt-inv-selection]');
|
|
var bulk = list.querySelector('[data-aksrt-inv-bulk]');
|
|
function syncSelection() {
|
|
var count = checks.filter(function (check) { return check.checked; }).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 = checks.length === 0;
|
|
bulk.disabled = !!list.dataset.submitting || count === 0 || list.elements.bulk_action.value !== 'delete';
|
|
checks.forEach(function (check) { check.closest('tr').classList.toggle('is-selected', check.checked); });
|
|
return count;
|
|
}
|
|
checkAll.addEventListener('change', function () {
|
|
checks.forEach(function (check) { check.checked = checkAll.checked; });
|
|
syncSelection();
|
|
});
|
|
list.addEventListener('change', syncSelection);
|
|
list.addEventListener('submit', function (event) {
|
|
var count = syncSelection();
|
|
if (list.dataset.submitting || bulk.disabled || !window.confirm(list.getAttribute('data-confirm').replace('%d', String(count)))) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
list.dataset.submitting = '1';
|
|
bulk.disabled = true;
|
|
});
|
|
window.addEventListener('pageshow', function () {
|
|
delete addForm.dataset.submitting;
|
|
delete list.dataset.submitting;
|
|
addSubmit.disabled = false;
|
|
syncForm(addForm);
|
|
syncSelection();
|
|
document.documentElement.classList.toggle('aksrt-inv-modal-open', !!root.querySelector('dialog[open]'));
|
|
});
|
|
syncSelection();
|
|
})();
|