Import current PCAT application

This commit is contained in:
ZeroIchiro
2026-09-15 10:47:36 +00:00
commit 1b532b937f
18 changed files with 1059 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
(() => {
const root = document.querySelector('[data-admin-app]');
if (!root) return;
const csrf = root.dataset.csrf;
const rows = root.querySelector('[data-author-rows]');
const template = root.querySelector('[data-author-template]');
const searchUrl = root.dataset.authorSearch;
function addAuthorRow(id = '', name = '', margin = '') {
const row = template.content.firstElementChild.cloneNode(true);
row.querySelector('[data-author-id]').value = id;
row.querySelector('[data-author-name]').value = name;
row.querySelector('[data-margin]').value = margin;
rows.appendChild(row);
bindSearch(row);
}
function bindSearch(row) {
const input = row.querySelector('[data-author-name]');
const id = row.querySelector('[data-author-id]');
const list = row.querySelector('[data-suggestions]');
let timer;
input.addEventListener('input', () => {
id.value = '';
clearTimeout(timer);
const term = input.value.trim();
if (term.length < 2) { list.replaceChildren(); return; }
timer = setTimeout(async () => {
const response = await fetch(`${searchUrl}?q=${encodeURIComponent(term)}`, {
credentials: 'same-origin',
headers: { 'X-CSRF-Token': csrf }
});
if (!response.ok) return;
const authors = await response.json();
list.replaceChildren(...authors.map(author => {
const item = document.createElement('li');
const button = document.createElement('button');
button.type = 'button'; button.textContent = author.name;
button.addEventListener('click', () => { input.value = author.name; id.value = author.id; list.replaceChildren(); });
item.appendChild(button); return item;
}));
}, 180);
});
}
root.querySelector('[data-add-author]').addEventListener('click', () => addAuthorRow());
root.addEventListener('click', event => {
if (event.target.matches('[data-remove-author]')) event.target.closest('[data-author-row]').remove();
});
document.addEventListener('submit', event => {
const message = event.target.dataset.confirm;
if (message && !window.confirm(message)) event.preventDefault();
});
root.querySelectorAll('[data-author-row]').forEach(bindSearch);
})();
+2
View File
@@ -0,0 +1,2 @@
<!doctype html>
<html><head><meta charset="utf-8"><title>Not found</title></head><body></body></html>