mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-08-10 23:31:21 +02:00
justfile: standardise test recipes to lint-php/lint-css/lint-js/test + add fix recipe
- Removed ambiguous aliases: phpstan, cs-check, syntax - Split lint-biome into lint-css and lint-js with correct paths - Added lint meta-recipe and fix recipe (biome --unsafe + php-cs-fixer) - Fixed FormBootstrap dead null check, CSS shorthand override bug - Updated phpstan baseline, suppressed noDescendingSpecificity/noInnerDeclarations - Applied ~74 biome auto-fixes across CSS/JS
This commit is contained in:
@@ -4,43 +4,45 @@
|
||||
* Provides: dialog openers, clipboard copy, password dialog.
|
||||
*/
|
||||
(() => {
|
||||
var createBtn = document.getElementById('open-create-dialog');
|
||||
if (createBtn) {
|
||||
createBtn.addEventListener('click', () => {
|
||||
document.getElementById('create-dialog').showModal();
|
||||
});
|
||||
}
|
||||
var createBtn = document.getElementById("open-create-dialog");
|
||||
if (createBtn) {
|
||||
createBtn.addEventListener("click", () => {
|
||||
document.getElementById("create-dialog").showModal();
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
var _pendingDeleteLinkId = null;
|
||||
|
||||
function openDeleteLinkDialog(id) {
|
||||
_pendingDeleteLinkId = id;
|
||||
document.getElementById('delete-link-dialog').showModal();
|
||||
function _openDeleteLinkDialog(id) {
|
||||
_pendingDeleteLinkId = id;
|
||||
document.getElementById("delete-link-dialog").showModal();
|
||||
}
|
||||
|
||||
function _executeDeleteLink() {
|
||||
var form = document.getElementById('delete-link-form-' + _pendingDeleteLinkId);
|
||||
if (form) form.submit();
|
||||
var form = document.getElementById(
|
||||
`delete-link-form-${_pendingDeleteLinkId}`,
|
||||
);
|
||||
if (form) form.submit();
|
||||
}
|
||||
|
||||
function copyUrl(id) {
|
||||
var input = document.getElementById('url-' + id);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
var btn = event.target.closest('button');
|
||||
var orig = btn.textContent;
|
||||
btn.textContent = '✓ Copié';
|
||||
setTimeout(() => {
|
||||
btn.textContent = orig;
|
||||
}, 1200);
|
||||
});
|
||||
function _copyUrl(id) {
|
||||
var input = document.getElementById(`url-${id}`);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
var btn = event.target.closest("button");
|
||||
var orig = btn.textContent;
|
||||
btn.textContent = "✓ Copié";
|
||||
setTimeout(() => {
|
||||
btn.textContent = orig;
|
||||
}, 1200);
|
||||
});
|
||||
}
|
||||
|
||||
function openPasswordDialog(id, hasPassword) {
|
||||
document.getElementById('password-link-id').value = id;
|
||||
var info = document.getElementById('password-current-info');
|
||||
info.textContent = hasPassword
|
||||
? 'Un mot de passe est actuellement configuré. Entrez-en un nouveau ou laissez vide pour le supprimer.'
|
||||
: 'Aucun mot de passe configuré.';
|
||||
document.getElementById('password-dialog').showModal();
|
||||
function _openPasswordDialog(id, hasPassword) {
|
||||
document.getElementById("password-link-id").value = id;
|
||||
var info = document.getElementById("password-current-info");
|
||||
info.textContent = hasPassword
|
||||
? "Un mot de passe est actuellement configuré. Entrez-en un nouveau ou laissez vide pour le supprimer."
|
||||
: "Aucun mot de passe configuré.";
|
||||
document.getElementById("password-dialog").showModal();
|
||||
}
|
||||
|
||||
@@ -7,99 +7,105 @@
|
||||
* <meta name="acces-new-link-slug" content="...">
|
||||
*/
|
||||
(() => {
|
||||
var baseUrlMeta = document.querySelector('meta[name="acces-base-url"]');
|
||||
var passwordMeta = document.querySelector('meta[name="acces-new-link-password"]');
|
||||
var slugMeta = document.querySelector('meta[name="acces-new-link-slug"]');
|
||||
var baseUrlMeta = document.querySelector('meta[name="acces-base-url"]');
|
||||
var passwordMeta = document.querySelector(
|
||||
'meta[name="acces-new-link-password"]',
|
||||
);
|
||||
var slugMeta = document.querySelector('meta[name="acces-new-link-slug"]');
|
||||
|
||||
// Show result dialog after redirect (new link created)
|
||||
if (passwordMeta && slugMeta && passwordMeta.content && slugMeta.content) {
|
||||
document.getElementById('create-result-password').value = passwordMeta.content;
|
||||
document.getElementById('create-result-url').value =
|
||||
(baseUrlMeta ? baseUrlMeta.content : '') + '/partage/' + slugMeta.content;
|
||||
document.getElementById('create-result-dialog').showModal();
|
||||
}
|
||||
// Show result dialog after redirect (new link created)
|
||||
if (passwordMeta && slugMeta && passwordMeta.content && slugMeta.content) {
|
||||
document.getElementById("create-result-password").value =
|
||||
passwordMeta.content;
|
||||
document.getElementById("create-result-url").value =
|
||||
`${baseUrlMeta ? baseUrlMeta.content : ""}/partage/${slugMeta.content}`;
|
||||
document.getElementById("create-result-dialog").showModal();
|
||||
}
|
||||
|
||||
// Create dialog opener
|
||||
var createBtn = document.getElementById('open-create-dialog');
|
||||
if (createBtn) {
|
||||
createBtn.addEventListener('click', () => {
|
||||
document.getElementById('create-dialog').showModal();
|
||||
});
|
||||
}
|
||||
// Create dialog opener
|
||||
var createBtn = document.getElementById("open-create-dialog");
|
||||
if (createBtn) {
|
||||
createBtn.addEventListener("click", () => {
|
||||
document.getElementById("create-dialog").showModal();
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
function copyUrl(id) {
|
||||
var input = document.getElementById('url-' + id);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
var btn = event.target.closest('button');
|
||||
if (btn) {
|
||||
var orig = btn.getAttribute('title') || '';
|
||||
btn.setAttribute('title', '✓ Copié');
|
||||
setTimeout(() => {
|
||||
btn.setAttribute('title', orig);
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
function _copyUrl(id) {
|
||||
var input = document.getElementById(`url-${id}`);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
var btn = event.target.closest("button");
|
||||
if (btn) {
|
||||
const orig = btn.getAttribute("title") || "";
|
||||
btn.setAttribute("title", "✓ Copié");
|
||||
setTimeout(() => {
|
||||
btn.setAttribute("title", orig);
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function copyUrlFrom(el) {
|
||||
navigator.clipboard.writeText(el.value).then(() => {
|
||||
var btn = el.nextElementSibling;
|
||||
if (btn) {
|
||||
var orig = btn.textContent;
|
||||
btn.textContent = '✓ Copié';
|
||||
setTimeout(() => {
|
||||
btn.textContent = orig;
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
function _copyUrlFrom(el) {
|
||||
navigator.clipboard.writeText(el.value).then(() => {
|
||||
const btn = el.nextElementSibling;
|
||||
if (btn) {
|
||||
const orig = btn.textContent;
|
||||
btn.textContent = "✓ Copié";
|
||||
setTimeout(() => {
|
||||
btn.textContent = orig;
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function copyTextToClipboard(text) {
|
||||
navigator.clipboard.writeText(text)
|
||||
.then(() => {
|
||||
var btn = event && event.target ? event.target.closest('button') : null;
|
||||
if (btn) {
|
||||
var orig = btn.getAttribute('title') || '';
|
||||
btn.setAttribute('title', '✓ Copié');
|
||||
setTimeout(() => {
|
||||
btn.setAttribute('title', orig);
|
||||
}, 1200);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
function _copyTextToClipboard(text) {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.then(() => {
|
||||
const btn = event?.target ? event.target.closest("button") : null;
|
||||
if (btn) {
|
||||
const orig = btn.getAttribute("title") || "";
|
||||
btn.setAttribute("title", "✓ Copié");
|
||||
setTimeout(() => {
|
||||
btn.setAttribute("title", orig);
|
||||
}, 1200);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function openEditDialog(id, name, hasPassword, expiresVal) {
|
||||
document.getElementById('edit-link-id').value = id;
|
||||
document.getElementById('edit-name').value = name || '';
|
||||
document.getElementById('edit-expires').value = expiresVal || '';
|
||||
document.getElementById('edit-dialog').showModal();
|
||||
function _openEditDialog(id, name, _hasPassword, expiresVal) {
|
||||
document.getElementById("edit-link-id").value = id;
|
||||
document.getElementById("edit-name").value = name || "";
|
||||
document.getElementById("edit-expires").value = expiresVal || "";
|
||||
document.getElementById("edit-dialog").showModal();
|
||||
}
|
||||
|
||||
function openApproveDialog(requestId) {
|
||||
document.getElementById('approve-request-id').value = requestId;
|
||||
document.getElementById('approve-dialog').showModal();
|
||||
function _openApproveDialog(requestId) {
|
||||
document.getElementById("approve-request-id").value = requestId;
|
||||
document.getElementById("approve-dialog").showModal();
|
||||
}
|
||||
|
||||
function openRejectDialog(requestId) {
|
||||
document.getElementById('reject-request-id').value = requestId;
|
||||
document.getElementById('reject-dialog').showModal();
|
||||
function _openRejectDialog(requestId) {
|
||||
document.getElementById("reject-request-id").value = requestId;
|
||||
document.getElementById("reject-dialog").showModal();
|
||||
}
|
||||
|
||||
var _pendingArchiveLinkId = null;
|
||||
|
||||
function openArchiveLinkDialog(id) {
|
||||
_pendingArchiveLinkId = id;
|
||||
document.getElementById('archive-link-dialog').showModal();
|
||||
function _openArchiveLinkDialog(id) {
|
||||
_pendingArchiveLinkId = id;
|
||||
document.getElementById("archive-link-dialog").showModal();
|
||||
}
|
||||
|
||||
function _executeArchiveLink() {
|
||||
var form = document.getElementById('archive-link-form-' + _pendingArchiveLinkId);
|
||||
if (form) form.submit();
|
||||
var form = document.getElementById(
|
||||
`archive-link-form-${_pendingArchiveLinkId}`,
|
||||
);
|
||||
if (form) form.submit();
|
||||
}
|
||||
|
||||
function openDeleteArchivedLinkDialog(id) {
|
||||
document.getElementById('delete-archived-link-id').value = id;
|
||||
document.getElementById('delete-archived-link-dialog').showModal();
|
||||
function _openDeleteArchivedLinkDialog(id) {
|
||||
document.getElementById("delete-archived-link-id").value = id;
|
||||
document.getElementById("delete-archived-link-dialog").showModal();
|
||||
}
|
||||
|
||||
@@ -5,67 +5,72 @@
|
||||
* All functions are attached to `window` for onclick handlers in PHP templates.
|
||||
*/
|
||||
(() => {
|
||||
function cleanupToggleAll(src, group) {
|
||||
const selector = group === 'filepond'
|
||||
? 'input[name="filepond_dirs[]"]'
|
||||
: 'input[name="trash_files[]"]';
|
||||
document.querySelectorAll(selector).forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
cleanupUpdateBulk();
|
||||
}
|
||||
function cleanupToggleAll(src, group) {
|
||||
const selector =
|
||||
group === "filepond"
|
||||
? 'input[name="filepond_dirs[]"]'
|
||||
: 'input[name="trash_files[]"]';
|
||||
document.querySelectorAll(selector).forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
cleanupUpdateBulk();
|
||||
}
|
||||
|
||||
function cleanupUpdateBulk() {
|
||||
const bar = document.getElementById('cleanup-bulk-actions');
|
||||
const countEl = document.getElementById('cleanup-selected-count');
|
||||
if (!bar || !countEl) return;
|
||||
function cleanupUpdateBulk() {
|
||||
const bar = document.getElementById("cleanup-bulk-actions");
|
||||
const countEl = document.getElementById("cleanup-selected-count");
|
||||
if (!bar || !countEl) return;
|
||||
|
||||
const n = document.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked'
|
||||
).length;
|
||||
countEl.textContent = n;
|
||||
bar.style.display = n > 0 ? 'flex' : 'none';
|
||||
}
|
||||
const n = document.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked',
|
||||
).length;
|
||||
countEl.textContent = n;
|
||||
bar.style.display = n > 0 ? "flex" : "none";
|
||||
}
|
||||
|
||||
function cleanupBulkDelete() {
|
||||
const form = document.getElementById('cleanup-bulk-form');
|
||||
const container = document.getElementById('cleanup-bulk-checkboxes');
|
||||
if (!form || !container) return;
|
||||
function cleanupBulkDelete() {
|
||||
const form = document.getElementById("cleanup-bulk-form");
|
||||
const container = document.getElementById("cleanup-bulk-checkboxes");
|
||||
if (!form || !container) return;
|
||||
|
||||
// Populate hidden inputs from checked checkboxes
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked'
|
||||
).forEach((cb) => {
|
||||
const inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = cb.name; // "filepond_dirs[]" or "trash_files[]"
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
// Populate hidden inputs from checked checkboxes
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked',
|
||||
)
|
||||
.forEach((cb) => {
|
||||
const inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = cb.name; // "filepond_dirs[]" or "trash_files[]"
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
|
||||
// Submit via HTMX
|
||||
htmx.trigger(form, 'submit');
|
||||
}
|
||||
// Submit via HTMX
|
||||
htmx.trigger(form, "submit");
|
||||
}
|
||||
|
||||
function reattachListeners() {
|
||||
document.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"], input[name="trash_files[]"]'
|
||||
).forEach((cb) => {
|
||||
cb.addEventListener('change', cleanupUpdateBulk);
|
||||
});
|
||||
cleanupUpdateBulk();
|
||||
}
|
||||
function reattachListeners() {
|
||||
document
|
||||
.querySelectorAll(
|
||||
'input[name="filepond_dirs[]"], input[name="trash_files[]"]',
|
||||
)
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener("change", cleanupUpdateBulk);
|
||||
});
|
||||
cleanupUpdateBulk();
|
||||
}
|
||||
|
||||
document.addEventListener('htmx:afterSwap', (evt) => {
|
||||
// Only reattach if the swap target is our cleanup wrapper
|
||||
if (evt.detail.target.id === 'tmp-cleanup-stats-wrapper') {
|
||||
reattachListeners();
|
||||
}
|
||||
});
|
||||
document.addEventListener("htmx:afterSwap", (evt) => {
|
||||
// Only reattach if the swap target is our cleanup wrapper
|
||||
if (evt.detail.target.id === "tmp-cleanup-stats-wrapper") {
|
||||
reattachListeners();
|
||||
}
|
||||
});
|
||||
|
||||
// Export to global scope for onclick handlers in HTML
|
||||
window.cleanupToggleAll = cleanupToggleAll;
|
||||
window.cleanupUpdateBulk = cleanupUpdateBulk;
|
||||
window.cleanupBulkDelete = cleanupBulkDelete;
|
||||
// Export to global scope for onclick handlers in HTML
|
||||
window.cleanupToggleAll = cleanupToggleAll;
|
||||
window.cleanupUpdateBulk = cleanupUpdateBulk;
|
||||
window.cleanupBulkDelete = cleanupBulkDelete;
|
||||
})();
|
||||
|
||||
@@ -5,87 +5,88 @@
|
||||
* Expects templates with ids `entry-template-f-{key}` and `group-template-f-{key}`.
|
||||
*/
|
||||
(() => {
|
||||
var form = document.querySelector('form[data-apropos-key]');
|
||||
if (!form) return;
|
||||
var form = document.querySelector("form[data-apropos-key]");
|
||||
if (!form) return;
|
||||
|
||||
var key = form.dataset.aproposKey;
|
||||
var groupCount = parseInt(form.dataset.aproposGroupCount, 10) || 0;
|
||||
var entryTpl = document.getElementById('entry-template-f-' + key).innerHTML;
|
||||
var groupTpl = document.getElementById('group-template-f-' + key).innerHTML;
|
||||
var key = form.dataset.aproposKey;
|
||||
var groupCount = parseInt(form.dataset.aproposGroupCount, 10) || 0;
|
||||
var entryTpl = document.getElementById(`entry-template-f-${key}`).innerHTML;
|
||||
var groupTpl = document.getElementById(`group-template-f-${key}`).innerHTML;
|
||||
|
||||
function reindexGroups() {
|
||||
var fieldsets = form.querySelectorAll('fieldset.apropos-group');
|
||||
groupCount = fieldsets.length;
|
||||
fieldsets.forEach((fs, i) => {
|
||||
var newIdx = i;
|
||||
var legend = fs.querySelector('legend');
|
||||
if (legend) legend.textContent = 'Contact ' + (newIdx + 1);
|
||||
function reindexGroups() {
|
||||
var fieldsets = form.querySelectorAll("fieldset.apropos-group");
|
||||
groupCount = fieldsets.length;
|
||||
fieldsets.forEach((fs, i) => {
|
||||
var newIdx = i;
|
||||
var legend = fs.querySelector("legend");
|
||||
if (legend) legend.textContent = `Contact ${newIdx + 1}`;
|
||||
|
||||
fs.querySelectorAll('input').forEach((inp) => {
|
||||
if (inp.name) {
|
||||
inp.name = inp.name.replace(/groups\[\d+\]/, 'groups[' + newIdx + ']');
|
||||
}
|
||||
if (inp.id) {
|
||||
inp.id = inp.id.replace(
|
||||
/(group_f_contacts_|entry_f_contacts_)\d+/,
|
||||
'$1' + newIdx
|
||||
);
|
||||
}
|
||||
});
|
||||
fs.querySelectorAll("input").forEach((inp) => {
|
||||
if (inp.name) {
|
||||
inp.name = inp.name.replace(/groups\[\d+\]/, `groups[${newIdx}]`);
|
||||
}
|
||||
if (inp.id) {
|
||||
inp.id = inp.id.replace(
|
||||
/(group_f_contacts_|entry_f_contacts_)\d+/,
|
||||
`$1${newIdx}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
fs.querySelectorAll('label[for]').forEach((lbl) => {
|
||||
lbl.setAttribute(
|
||||
'for',
|
||||
lbl.getAttribute('for').replace(
|
||||
/(group_f_contacts_|entry_f_contacts_)\d+/,
|
||||
'$1' + newIdx
|
||||
)
|
||||
);
|
||||
});
|
||||
fs.querySelectorAll("label[for]").forEach((lbl) => {
|
||||
lbl.setAttribute(
|
||||
"for",
|
||||
lbl
|
||||
.getAttribute("for")
|
||||
.replace(/(group_f_contacts_|entry_f_contacts_)\d+/, `$1${newIdx}`),
|
||||
);
|
||||
});
|
||||
|
||||
var addBtn = fs.querySelector('.add-entry-btn-f');
|
||||
if (addBtn) addBtn.dataset.group = newIdx;
|
||||
});
|
||||
}
|
||||
var addBtn = fs.querySelector(".add-entry-btn-f");
|
||||
if (addBtn) addBtn.dataset.group = newIdx;
|
||||
});
|
||||
}
|
||||
|
||||
function bindAddEntry(btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var gi = parseInt(this.dataset.group);
|
||||
var fieldset = this.closest('fieldset');
|
||||
var entryCount = fieldset.querySelectorAll('.apropos-entry').length;
|
||||
var html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
|
||||
this.insertAdjacentHTML('beforebegin', html);
|
||||
});
|
||||
}
|
||||
function bindAddEntry(btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
var gi = parseInt(this.dataset.group, 10);
|
||||
var fieldset = this.closest("fieldset");
|
||||
var entryCount = fieldset.querySelectorAll(".apropos-entry").length;
|
||||
var html = entryTpl
|
||||
.replaceAll("{{gi}}", gi)
|
||||
.replaceAll("{{ei}}", entryCount);
|
||||
this.insertAdjacentHTML("beforebegin", html);
|
||||
});
|
||||
}
|
||||
|
||||
function bindDeleteGroup(btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var fieldset = this.closest('fieldset');
|
||||
if (fieldset) {
|
||||
fieldset.remove();
|
||||
reindexGroups();
|
||||
}
|
||||
});
|
||||
}
|
||||
function bindDeleteGroup(btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
var fieldset = this.closest("fieldset");
|
||||
if (fieldset) {
|
||||
fieldset.remove();
|
||||
reindexGroups();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Bind existing buttons
|
||||
form.querySelectorAll('.add-entry-btn-f').forEach(bindAddEntry);
|
||||
form.querySelectorAll('.delete-group-btn-f').forEach(bindDeleteGroup);
|
||||
// Bind existing buttons
|
||||
form.querySelectorAll(".add-entry-btn-f").forEach(bindAddEntry);
|
||||
form.querySelectorAll(".delete-group-btn-f").forEach(bindDeleteGroup);
|
||||
|
||||
form.querySelector('.add-group-btn-f').addEventListener('click', function () {
|
||||
groupCount++;
|
||||
var html = groupTpl.replaceAll('{{gi}}', groupCount);
|
||||
this.insertAdjacentHTML('beforebegin', html);
|
||||
form.querySelector(".add-group-btn-f").addEventListener("click", function () {
|
||||
groupCount++;
|
||||
var html = groupTpl.replaceAll("{{gi}}", groupCount);
|
||||
this.insertAdjacentHTML("beforebegin", html);
|
||||
|
||||
var newGroup = this.previousElementSibling;
|
||||
if (newGroup && newGroup.classList.contains('apropos-group')) {
|
||||
var addBtn = newGroup.querySelector('.add-entry-btn-f');
|
||||
if (addBtn) {
|
||||
addBtn.dataset.group = groupCount;
|
||||
bindAddEntry(addBtn);
|
||||
}
|
||||
var delBtn = newGroup.querySelector('.delete-group-btn-f');
|
||||
if (delBtn) bindDeleteGroup(delBtn);
|
||||
}
|
||||
});
|
||||
var newGroup = this.previousElementSibling;
|
||||
if (newGroup?.classList.contains("apropos-group")) {
|
||||
var addBtn = newGroup.querySelector(".add-entry-btn-f");
|
||||
if (addBtn) {
|
||||
addBtn.dataset.group = groupCount;
|
||||
bindAddEntry(addBtn);
|
||||
}
|
||||
var delBtn = newGroup.querySelector(".delete-group-btn-f");
|
||||
if (delBtn) bindDeleteGroup(delBtn);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -7,111 +7,126 @@
|
||||
*/
|
||||
var _languesPendingForm = null;
|
||||
|
||||
function languesConfirmDelete(btn, name) {
|
||||
_languesPendingForm = btn.closest('form');
|
||||
document.getElementById('langues-delete-name').textContent = name;
|
||||
document.getElementById('langues-delete-dialog').showModal();
|
||||
function _languesConfirmDelete(btn, name) {
|
||||
_languesPendingForm = btn.closest("form");
|
||||
document.getElementById("langues-delete-name").textContent = name;
|
||||
document.getElementById("langues-delete-dialog").showModal();
|
||||
}
|
||||
|
||||
function languesSubmitPending() {
|
||||
if (_languesPendingForm) _languesPendingForm.submit();
|
||||
function _languesSubmitPending() {
|
||||
if (_languesPendingForm) _languesPendingForm.submit();
|
||||
}
|
||||
|
||||
function languesToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_langs[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
languesUpdateBulk();
|
||||
function _languesToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_langs[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
languesUpdateBulk();
|
||||
}
|
||||
|
||||
function languesUpdateBulk() {
|
||||
var n = document.querySelectorAll('input[name="selected_langs[]"]:checked').length;
|
||||
document.getElementById('langues-selected-count').textContent = n;
|
||||
var bar = document.getElementById('langues-bulk-actions');
|
||||
var wrap = document.getElementById('langues-table-wrap');
|
||||
var visible = n > 1;
|
||||
bar.style.display = visible ? 'flex' : 'none';
|
||||
if (visible) {
|
||||
requestAnimationFrame(() => {
|
||||
wrap.style.setProperty('--sticky-top', bar.offsetHeight + 'px');
|
||||
});
|
||||
} else {
|
||||
wrap.style.setProperty('--sticky-top', '0px');
|
||||
}
|
||||
var n = document.querySelectorAll(
|
||||
'input[name="selected_langs[]"]:checked',
|
||||
).length;
|
||||
document.getElementById("langues-selected-count").textContent = n;
|
||||
var bar = document.getElementById("langues-bulk-actions");
|
||||
var wrap = document.getElementById("langues-table-wrap");
|
||||
var visible = n > 1;
|
||||
bar.style.display = visible ? "flex" : "none";
|
||||
if (visible) {
|
||||
requestAnimationFrame(() => {
|
||||
wrap.style.setProperty("--sticky-top", `${bar.offsetHeight}px`);
|
||||
});
|
||||
} else {
|
||||
wrap.style.setProperty("--sticky-top", "0px");
|
||||
}
|
||||
}
|
||||
|
||||
function languesCancelSelection() {
|
||||
document.querySelectorAll('input[name="selected_langs[]"]').forEach((cb) => {
|
||||
cb.checked = false;
|
||||
});
|
||||
languesUpdateBulk();
|
||||
function _languesCancelSelection() {
|
||||
document.querySelectorAll('input[name="selected_langs[]"]').forEach((cb) => {
|
||||
cb.checked = false;
|
||||
});
|
||||
languesUpdateBulk();
|
||||
}
|
||||
|
||||
function languesConfirmBulkDelete() {
|
||||
var checked = document.querySelectorAll('input[name="selected_langs[]"]:checked');
|
||||
if (checked.length < 1) return;
|
||||
document.getElementById('langues-bulk-delete-count').textContent = checked.length;
|
||||
document.getElementById('langues-bulk-delete-dialog').showModal();
|
||||
function _languesConfirmBulkDelete() {
|
||||
var checked = document.querySelectorAll(
|
||||
'input[name="selected_langs[]"]:checked',
|
||||
);
|
||||
if (checked.length < 1) return;
|
||||
document.getElementById("langues-bulk-delete-count").textContent =
|
||||
checked.length;
|
||||
document.getElementById("langues-bulk-delete-dialog").showModal();
|
||||
}
|
||||
|
||||
function languesExecBulkDelete() {
|
||||
var container = document.getElementById('langues-bulk-checkboxes');
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll('input[name="selected_langs[]"]:checked').forEach((cb) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_langs[]';
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById('langues-bulk-form').querySelector('input[name="action"]').value =
|
||||
'delete_bulk';
|
||||
document.getElementById('langues-bulk-delete-dialog').close();
|
||||
document.getElementById('langues-bulk-form').submit();
|
||||
function _languesExecBulkDelete() {
|
||||
var container = document.getElementById("langues-bulk-checkboxes");
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll('input[name="selected_langs[]"]:checked')
|
||||
.forEach((cb) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_langs[]";
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document
|
||||
.getElementById("langues-bulk-form")
|
||||
.querySelector('input[name="action"]').value = "delete_bulk";
|
||||
document.getElementById("langues-bulk-delete-dialog").close();
|
||||
document.getElementById("langues-bulk-form").submit();
|
||||
}
|
||||
|
||||
function languesConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll('input[name="selected_langs[]"]:checked');
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById('langues-bulk-merge-count').textContent = checked.length;
|
||||
var sel = document.getElementById('langues-bulk-merge-target-select');
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest('tr');
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector('td:nth-child(2)').textContent.trim() +
|
||||
'</option>';
|
||||
});
|
||||
document.getElementById('langues-bulk-merge-dialog').showModal();
|
||||
function _languesConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll(
|
||||
'input[name="selected_langs[]"]:checked',
|
||||
);
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById("langues-bulk-merge-count").textContent =
|
||||
checked.length;
|
||||
var sel = document.getElementById("langues-bulk-merge-target-select");
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest("tr");
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector("td:nth-child(2)").textContent.trim() +
|
||||
"</option>";
|
||||
});
|
||||
document.getElementById("langues-bulk-merge-dialog").showModal();
|
||||
}
|
||||
|
||||
function languesExecBulkMerge() {
|
||||
var targetId = document.getElementById('langues-bulk-merge-target-select').value;
|
||||
if (!targetId) return;
|
||||
document.getElementById('langues-bulk-target').value = targetId;
|
||||
var container = document.getElementById('langues-bulk-checkboxes');
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll('input[name="selected_langs[]"]:checked').forEach((cb) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_langs[]';
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById('langues-bulk-merge-dialog').close();
|
||||
document.getElementById('langues-bulk-form').submit();
|
||||
function _languesExecBulkMerge() {
|
||||
var targetId = document.getElementById(
|
||||
"langues-bulk-merge-target-select",
|
||||
).value;
|
||||
if (!targetId) return;
|
||||
document.getElementById("langues-bulk-target").value = targetId;
|
||||
var container = document.getElementById("langues-bulk-checkboxes");
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll('input[name="selected_langs[]"]:checked')
|
||||
.forEach((cb) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_langs[]";
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById("langues-bulk-merge-dialog").close();
|
||||
document.getElementById("langues-bulk-form").submit();
|
||||
}
|
||||
|
||||
document.addEventListener('htmx:afterSwap', (evt) => {
|
||||
if (evt.target.id === 'langues-table-wrap') {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_langs[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener('change', languesUpdateBulk);
|
||||
});
|
||||
languesUpdateBulk();
|
||||
}
|
||||
document.addEventListener("htmx:afterSwap", (evt) => {
|
||||
if (evt.target.id === "langues-table-wrap") {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_langs[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener("change", languesUpdateBulk);
|
||||
});
|
||||
languesUpdateBulk();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,111 +7,124 @@
|
||||
*/
|
||||
var _motsclesPendingForm = null;
|
||||
|
||||
function motsclesConfirmDelete(btn, name) {
|
||||
_motsclesPendingForm = btn.closest('form');
|
||||
document.getElementById('motscles-delete-name').textContent = name;
|
||||
document.getElementById('motscles-delete-dialog').showModal();
|
||||
function _motsclesConfirmDelete(btn, name) {
|
||||
_motsclesPendingForm = btn.closest("form");
|
||||
document.getElementById("motscles-delete-name").textContent = name;
|
||||
document.getElementById("motscles-delete-dialog").showModal();
|
||||
}
|
||||
|
||||
function motsclesSubmitPending() {
|
||||
if (_motsclesPendingForm) _motsclesPendingForm.submit();
|
||||
function _motsclesSubmitPending() {
|
||||
if (_motsclesPendingForm) _motsclesPendingForm.submit();
|
||||
}
|
||||
|
||||
function motsclesToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
function _motsclesToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
}
|
||||
|
||||
function motsclesUpdateBulk() {
|
||||
var n = document.querySelectorAll('input[name="selected_tags[]"]:checked').length;
|
||||
document.getElementById('motscles-selected-count').textContent = n;
|
||||
var bar = document.getElementById('motscles-bulk-actions');
|
||||
var wrap = document.getElementById('motscles-table-wrap');
|
||||
var visible = n > 1;
|
||||
bar.style.display = visible ? 'flex' : 'none';
|
||||
if (visible) {
|
||||
requestAnimationFrame(() => {
|
||||
wrap.style.setProperty('--sticky-top', bar.offsetHeight + 'px');
|
||||
});
|
||||
} else {
|
||||
wrap.style.setProperty('--sticky-top', '0px');
|
||||
}
|
||||
var n = document.querySelectorAll(
|
||||
'input[name="selected_tags[]"]:checked',
|
||||
).length;
|
||||
document.getElementById("motscles-selected-count").textContent = n;
|
||||
var bar = document.getElementById("motscles-bulk-actions");
|
||||
var wrap = document.getElementById("motscles-table-wrap");
|
||||
var visible = n > 1;
|
||||
bar.style.display = visible ? "flex" : "none";
|
||||
if (visible) {
|
||||
requestAnimationFrame(() => {
|
||||
wrap.style.setProperty("--sticky-top", `${bar.offsetHeight}px`);
|
||||
});
|
||||
} else {
|
||||
wrap.style.setProperty("--sticky-top", "0px");
|
||||
}
|
||||
}
|
||||
|
||||
function motsclesConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll('input[name="selected_tags[]"]:checked');
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById('motscles-bulk-merge-count').textContent = checked.length;
|
||||
var sel = document.getElementById('motscles-bulk-merge-target-select');
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest('tr');
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector('td:nth-child(2)').textContent.trim() +
|
||||
'</option>';
|
||||
});
|
||||
document.getElementById('motscles-bulk-merge-dialog').showModal();
|
||||
function _motsclesConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll(
|
||||
'input[name="selected_tags[]"]:checked',
|
||||
);
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById("motscles-bulk-merge-count").textContent =
|
||||
checked.length;
|
||||
var sel = document.getElementById("motscles-bulk-merge-target-select");
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest("tr");
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector("td:nth-child(2)").textContent.trim() +
|
||||
"</option>";
|
||||
});
|
||||
document.getElementById("motscles-bulk-merge-dialog").showModal();
|
||||
}
|
||||
|
||||
function motsclesExecBulkMerge() {
|
||||
var targetId = document.getElementById('motscles-bulk-merge-target-select').value;
|
||||
if (!targetId) return;
|
||||
document.getElementById('motscles-bulk-target').value = targetId;
|
||||
var container = document.getElementById('motscles-bulk-checkboxes');
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll('input[name="selected_tags[]"]:checked').forEach((cb) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_tags[]';
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById('motscles-bulk-merge-dialog').close();
|
||||
document.getElementById('motscles-bulk-form').submit();
|
||||
function _motsclesExecBulkMerge() {
|
||||
var targetId = document.getElementById(
|
||||
"motscles-bulk-merge-target-select",
|
||||
).value;
|
||||
if (!targetId) return;
|
||||
document.getElementById("motscles-bulk-target").value = targetId;
|
||||
var container = document.getElementById("motscles-bulk-checkboxes");
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll('input[name="selected_tags[]"]:checked')
|
||||
.forEach((cb) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_tags[]";
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById("motscles-bulk-merge-dialog").close();
|
||||
document.getElementById("motscles-bulk-form").submit();
|
||||
}
|
||||
|
||||
function motsclesCancelSelection() {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = false;
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
function _motsclesCancelSelection() {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = false;
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
}
|
||||
|
||||
function motsclesConfirmBulkDelete() {
|
||||
var checked = document.querySelectorAll('input[name="selected_tags[]"]:checked');
|
||||
if (checked.length < 1) return;
|
||||
document.getElementById('motscles-bulk-delete-count').textContent = checked.length;
|
||||
document.getElementById('motscles-bulk-delete-dialog').showModal();
|
||||
function _motsclesConfirmBulkDelete() {
|
||||
var checked = document.querySelectorAll(
|
||||
'input[name="selected_tags[]"]:checked',
|
||||
);
|
||||
if (checked.length < 1) return;
|
||||
document.getElementById("motscles-bulk-delete-count").textContent =
|
||||
checked.length;
|
||||
document.getElementById("motscles-bulk-delete-dialog").showModal();
|
||||
}
|
||||
|
||||
function motsclesExecBulkDelete() {
|
||||
var container = document.getElementById('motscles-bulk-checkboxes');
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll('input[name="selected_tags[]"]:checked').forEach((cb) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_tags[]';
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById('motscles-bulk-form').querySelector('input[name="action"]').value =
|
||||
'delete_bulk';
|
||||
document.getElementById('motscles-bulk-delete-dialog').close();
|
||||
document.getElementById('motscles-bulk-form').submit();
|
||||
function _motsclesExecBulkDelete() {
|
||||
var container = document.getElementById("motscles-bulk-checkboxes");
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll('input[name="selected_tags[]"]:checked')
|
||||
.forEach((cb) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_tags[]";
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document
|
||||
.getElementById("motscles-bulk-form")
|
||||
.querySelector('input[name="action"]').value = "delete_bulk";
|
||||
document.getElementById("motscles-bulk-delete-dialog").close();
|
||||
document.getElementById("motscles-bulk-form").submit();
|
||||
}
|
||||
|
||||
document.addEventListener('htmx:afterSwap', (evt) => {
|
||||
if (evt.target.id === 'motscles-table-wrap') {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_tags[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener('change', motsclesUpdateBulk);
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
}
|
||||
document.addEventListener("htmx:afterSwap", (evt) => {
|
||||
if (evt.target.id === "motscles-table-wrap") {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.addEventListener("change", motsclesUpdateBulk);
|
||||
});
|
||||
motsclesUpdateBulk();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
*
|
||||
* Provides: openApproveDialog, openRejectDialog.
|
||||
*/
|
||||
function openApproveDialog(requestId) {
|
||||
document.getElementById('approve-request-id').value = requestId;
|
||||
document.getElementById('approve-dialog').showModal();
|
||||
function _openApproveDialog(requestId) {
|
||||
document.getElementById("approve-request-id").value = requestId;
|
||||
document.getElementById("approve-dialog").showModal();
|
||||
}
|
||||
|
||||
function openRejectDialog(requestId) {
|
||||
document.getElementById('reject-request-id').value = requestId;
|
||||
document.getElementById('reject-dialog').showModal();
|
||||
function _openRejectDialog(requestId) {
|
||||
document.getElementById("reject-request-id").value = requestId;
|
||||
document.getElementById("reject-dialog").showModal();
|
||||
}
|
||||
|
||||
@@ -5,113 +5,118 @@
|
||||
* confirmExport, confirmExportFiles, confirmDelete.
|
||||
*/
|
||||
(() => {
|
||||
function toggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_theses[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
updateBulk();
|
||||
}
|
||||
function toggleAll(src) {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_theses[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
updateBulk();
|
||||
}
|
||||
|
||||
function updateBulk() {
|
||||
var b = document.getElementById('bulk-actions');
|
||||
var c = document.getElementById('selected-count');
|
||||
if (!b || !c) return; // only on thesis index page
|
||||
var n = document.querySelectorAll('input[name="selected_theses[]"]:checked').length;
|
||||
c.textContent = n;
|
||||
b.style.display = n > 0 ? 'flex' : 'none';
|
||||
document.getElementById('admin-table-wrap').style.setProperty(
|
||||
'--sticky-top',
|
||||
n > 0 ? b.offsetHeight + 'px' : '0px'
|
||||
);
|
||||
}
|
||||
function updateBulk() {
|
||||
var b = document.getElementById("bulk-actions");
|
||||
var c = document.getElementById("selected-count");
|
||||
if (!b || !c) return; // only on thesis index page
|
||||
var n = document.querySelectorAll(
|
||||
'input[name="selected_theses[]"]:checked',
|
||||
).length;
|
||||
c.textContent = n;
|
||||
b.style.display = n > 0 ? "flex" : "none";
|
||||
document
|
||||
.getElementById("admin-table-wrap")
|
||||
.style.setProperty("--sticky-top", n > 0 ? `${b.offsetHeight}px` : "0px");
|
||||
}
|
||||
|
||||
function getSelectedIds() {
|
||||
return Array.from(
|
||||
document.querySelectorAll('input[name="selected_theses[]"]:checked')
|
||||
).map((cb) => cb.value);
|
||||
}
|
||||
function getSelectedIds() {
|
||||
return Array.from(
|
||||
document.querySelectorAll('input[name="selected_theses[]"]:checked'),
|
||||
).map((cb) => cb.value);
|
||||
}
|
||||
|
||||
function confirmBulk(act) {
|
||||
var noSel = document.getElementById('no-selection-dialog');
|
||||
if (!noSel) return; // only on thesis index page
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
noSel.showModal();
|
||||
return;
|
||||
}
|
||||
var n = ids.length;
|
||||
document.getElementById('bulk-action-input').value = act;
|
||||
if (act === 'delete') {
|
||||
document.getElementById('bulk-delete-count').textContent = n;
|
||||
document.getElementById('bulk-delete-dialog').showModal();
|
||||
} else {
|
||||
document.getElementById('bulk-confirm-word').textContent =
|
||||
act === 'publish' ? 'Publier' : 'Dépublier';
|
||||
document.getElementById('bulk-confirm-count').textContent = n;
|
||||
document.getElementById('bulk-confirm-dialog').showModal();
|
||||
}
|
||||
}
|
||||
function confirmBulk(act) {
|
||||
var noSel = document.getElementById("no-selection-dialog");
|
||||
if (!noSel) return; // only on thesis index page
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
noSel.showModal();
|
||||
return;
|
||||
}
|
||||
var n = ids.length;
|
||||
document.getElementById("bulk-action-input").value = act;
|
||||
if (act === "delete") {
|
||||
document.getElementById("bulk-delete-count").textContent = n;
|
||||
document.getElementById("bulk-delete-dialog").showModal();
|
||||
} else {
|
||||
document.getElementById("bulk-confirm-word").textContent =
|
||||
act === "publish" ? "Publier" : "Dépublier";
|
||||
document.getElementById("bulk-confirm-count").textContent = n;
|
||||
document.getElementById("bulk-confirm-dialog").showModal();
|
||||
}
|
||||
}
|
||||
|
||||
function execBulk() {
|
||||
var a = document.getElementById('bulk-action-input').value;
|
||||
var f = document.getElementById('bulk-form');
|
||||
f.action = a === 'delete' ? 'actions/delete.php' : 'actions/publish.php';
|
||||
var c = document.getElementById('bulk-checkboxes');
|
||||
c.innerHTML = '';
|
||||
getSelectedIds().forEach((id) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_theses[]';
|
||||
inp.value = id;
|
||||
c.appendChild(inp);
|
||||
});
|
||||
f.submit();
|
||||
}
|
||||
function execBulk() {
|
||||
var a = document.getElementById("bulk-action-input").value;
|
||||
var f = document.getElementById("bulk-form");
|
||||
f.action = a === "delete" ? "actions/delete.php" : "actions/publish.php";
|
||||
var c = document.getElementById("bulk-checkboxes");
|
||||
c.innerHTML = "";
|
||||
getSelectedIds().forEach((id) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_theses[]";
|
||||
inp.value = id;
|
||||
c.appendChild(inp);
|
||||
});
|
||||
f.submit();
|
||||
}
|
||||
|
||||
function confirmExport() {
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
document.getElementById('no-selection-dialog').showModal();
|
||||
return;
|
||||
}
|
||||
window.location.href = '/admin/actions/export.php?csv=1&ids=' + ids.join(',');
|
||||
}
|
||||
function confirmExport() {
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
document.getElementById("no-selection-dialog").showModal();
|
||||
return;
|
||||
}
|
||||
window.location.href = `/admin/actions/export.php?csv=1&ids=${ids.join(",")}`;
|
||||
}
|
||||
|
||||
function confirmExportFiles() {
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
document.getElementById('no-selection-dialog').showModal();
|
||||
return;
|
||||
}
|
||||
window.location.href = '/admin/actions/export.php?files=1&ids=' + ids.join(',');
|
||||
}
|
||||
function confirmExportFiles() {
|
||||
var ids = getSelectedIds();
|
||||
if (!ids.length) {
|
||||
document.getElementById("no-selection-dialog").showModal();
|
||||
return;
|
||||
}
|
||||
window.location.href = `/admin/actions/export.php?files=1&ids=${ids.join(",")}`;
|
||||
}
|
||||
|
||||
function confirmDelete(id, title) {
|
||||
var dialog = document.getElementById('delete-thesis-dialog');
|
||||
if (!dialog) return; // only on thesis index page
|
||||
document.getElementById('delete-thesis-title').textContent = title;
|
||||
dialog.showModal();
|
||||
document.getElementById('delete-dialog-confirm').onclick = () => {
|
||||
document.getElementById('delete-form-' + id).submit();
|
||||
};
|
||||
}
|
||||
function confirmDelete(id, title) {
|
||||
var dialog = document.getElementById("delete-thesis-dialog");
|
||||
if (!dialog) return; // only on thesis index page
|
||||
document.getElementById("delete-thesis-title").textContent = title;
|
||||
dialog.showModal();
|
||||
document.getElementById("delete-dialog-confirm").onclick = () => {
|
||||
document.getElementById(`delete-form-${id}`).submit();
|
||||
};
|
||||
}
|
||||
|
||||
function reattachListeners() {
|
||||
document.querySelectorAll('input[name="selected_theses[]"]').forEach((cb) => {
|
||||
cb.addEventListener('change', updateBulk);
|
||||
});
|
||||
updateBulk();
|
||||
}
|
||||
function reattachListeners() {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_theses[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener("change", updateBulk);
|
||||
});
|
||||
updateBulk();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', reattachListeners);
|
||||
document.addEventListener('htmx:afterSwap', reattachListeners);
|
||||
document.addEventListener("DOMContentLoaded", reattachListeners);
|
||||
document.addEventListener("htmx:afterSwap", reattachListeners);
|
||||
|
||||
// Export to global scope for onclick handlers in HTML
|
||||
window.toggleAll = toggleAll;
|
||||
window.updateBulk = updateBulk;
|
||||
window.confirmBulk = confirmBulk;
|
||||
window.execBulk = execBulk;
|
||||
window.confirmExport = confirmExport;
|
||||
window.confirmExportFiles = confirmExportFiles;
|
||||
window.confirmDelete = confirmDelete;
|
||||
// Export to global scope for onclick handlers in HTML
|
||||
window.toggleAll = toggleAll;
|
||||
window.updateBulk = updateBulk;
|
||||
window.confirmBulk = confirmBulk;
|
||||
window.execBulk = execBulk;
|
||||
window.confirmExport = confirmExport;
|
||||
window.confirmExportFiles = confirmExportFiles;
|
||||
window.confirmDelete = confirmDelete;
|
||||
})();
|
||||
|
||||
@@ -10,71 +10,76 @@
|
||||
*/
|
||||
var _pendingTagForm = null;
|
||||
|
||||
function tagsToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
tagsUpdateBulk();
|
||||
function _tagsToggleAll(src) {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.checked = src.checked;
|
||||
});
|
||||
tagsUpdateBulk();
|
||||
}
|
||||
|
||||
function tagsUpdateBulk() {
|
||||
var n = document.querySelectorAll('input[name="selected_tags[]"]:checked').length;
|
||||
document.getElementById('tags-selected-count').textContent = n;
|
||||
document.getElementById('tags-bulk-actions').style.display = n > 1 ? 'flex' : 'none';
|
||||
var n = document.querySelectorAll(
|
||||
'input[name="selected_tags[]"]:checked',
|
||||
).length;
|
||||
document.getElementById("tags-selected-count").textContent = n;
|
||||
document.getElementById("tags-bulk-actions").style.display =
|
||||
n > 1 ? "flex" : "none";
|
||||
}
|
||||
|
||||
function tagsConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll('input[name="selected_tags[]"]:checked');
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById('bulk-merge-count').textContent = checked.length;
|
||||
var sel = document.getElementById('bulk-merge-target-select');
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest('tr');
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector('.tag-name-cell').textContent.trim() +
|
||||
'</option>';
|
||||
});
|
||||
document.getElementById('bulk-merge-dialog').showModal();
|
||||
function _tagsConfirmBulkMerge() {
|
||||
var checked = document.querySelectorAll(
|
||||
'input[name="selected_tags[]"]:checked',
|
||||
);
|
||||
if (checked.length < 2) return;
|
||||
document.getElementById("bulk-merge-count").textContent = checked.length;
|
||||
var sel = document.getElementById("bulk-merge-target-select");
|
||||
sel.innerHTML = '<option value="">— Choisir la destination —</option>';
|
||||
checked.forEach((cb) => {
|
||||
var tr = cb.closest("tr");
|
||||
sel.innerHTML +=
|
||||
'<option value="' +
|
||||
cb.value +
|
||||
'">' +
|
||||
tr.querySelector(".tag-name-cell").textContent.trim() +
|
||||
"</option>";
|
||||
});
|
||||
document.getElementById("bulk-merge-dialog").showModal();
|
||||
}
|
||||
|
||||
function tagsExecBulkMerge() {
|
||||
var targetId = document.getElementById('bulk-merge-target-select').value;
|
||||
if (!targetId) return;
|
||||
document.getElementById('tags-bulk-target').value = targetId;
|
||||
var container = document.getElementById('tags-bulk-checkboxes');
|
||||
container.innerHTML = '';
|
||||
document.querySelectorAll('input[name="selected_tags[]"]:checked').forEach((cb) => {
|
||||
var inp = document.createElement('input');
|
||||
inp.type = 'hidden';
|
||||
inp.name = 'selected_tags[]';
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById('bulk-merge-dialog').close();
|
||||
document.getElementById('tags-bulk-form').submit();
|
||||
function _tagsExecBulkMerge() {
|
||||
var targetId = document.getElementById("bulk-merge-target-select").value;
|
||||
if (!targetId) return;
|
||||
document.getElementById("tags-bulk-target").value = targetId;
|
||||
var container = document.getElementById("tags-bulk-checkboxes");
|
||||
container.innerHTML = "";
|
||||
document
|
||||
.querySelectorAll('input[name="selected_tags[]"]:checked')
|
||||
.forEach((cb) => {
|
||||
var inp = document.createElement("input");
|
||||
inp.type = "hidden";
|
||||
inp.name = "selected_tags[]";
|
||||
inp.value = cb.value;
|
||||
container.appendChild(inp);
|
||||
});
|
||||
document.getElementById("bulk-merge-dialog").close();
|
||||
document.getElementById("tags-bulk-form").submit();
|
||||
}
|
||||
|
||||
function tagsConfirmDelete(btn, name) {
|
||||
_pendingTagForm = btn.closest('form');
|
||||
document.getElementById('delete-tag-name').textContent = name;
|
||||
document.getElementById('delete-tag-dialog').showModal();
|
||||
function _tagsConfirmDelete(btn, name) {
|
||||
_pendingTagForm = btn.closest("form");
|
||||
document.getElementById("delete-tag-name").textContent = name;
|
||||
document.getElementById("delete-tag-dialog").showModal();
|
||||
}
|
||||
|
||||
function _submitPendingTagForm() {
|
||||
if (_pendingTagForm) _pendingTagForm.submit();
|
||||
if (_pendingTagForm) _pendingTagForm.submit();
|
||||
}
|
||||
|
||||
document.addEventListener('htmx:afterSwap', (evt) => {
|
||||
if (evt.target.id === 'tags-table-wrap') {
|
||||
document
|
||||
.querySelectorAll('input[name="selected_tags[]"]')
|
||||
.forEach((cb) => {
|
||||
cb.addEventListener('change', tagsUpdateBulk);
|
||||
});
|
||||
tagsUpdateBulk();
|
||||
}
|
||||
document.addEventListener("htmx:afterSwap", (evt) => {
|
||||
if (evt.target.id === "tags-table-wrap") {
|
||||
document.querySelectorAll('input[name="selected_tags[]"]').forEach((cb) => {
|
||||
cb.addEventListener("change", tagsUpdateBulk);
|
||||
});
|
||||
tagsUpdateBulk();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,108 +10,109 @@
|
||||
* Guarded: only runs once.
|
||||
*/
|
||||
(() => {
|
||||
if (window.__adminTocBuilt) return;
|
||||
window.__adminTocBuilt = true;
|
||||
if (window.__adminTocBuilt) return;
|
||||
window.__adminTocBuilt = true;
|
||||
|
||||
function build() {
|
||||
var main = document.getElementById('main-content');
|
||||
var toc = document.getElementById('admin-toc');
|
||||
var list = document.getElementById('admin-toc-list');
|
||||
if (!main || !toc || !list) return;
|
||||
function build() {
|
||||
var main = document.getElementById("main-content");
|
||||
var toc = document.getElementById("admin-toc");
|
||||
var list = document.getElementById("admin-toc-list");
|
||||
if (!main || !toc || !list) return;
|
||||
|
||||
// Guard against double population
|
||||
if (list.children.length > 0) return;
|
||||
// Guard against double population
|
||||
if (list.children.length > 0) return;
|
||||
|
||||
var sections = main.querySelectorAll('section[aria-labelledby]');
|
||||
if (sections.length < 2) {
|
||||
toc.hidden = true;
|
||||
return;
|
||||
}
|
||||
var sections = main.querySelectorAll("section[aria-labelledby]");
|
||||
if (sections.length < 2) {
|
||||
toc.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
sections.forEach((sec) => {
|
||||
var headingId = sec.getAttribute('aria-labelledby');
|
||||
var heading = document.getElementById(headingId);
|
||||
if (!heading) return;
|
||||
if (!sec.id) sec.id = headingId;
|
||||
var items = [];
|
||||
sections.forEach((sec) => {
|
||||
var headingId = sec.getAttribute("aria-labelledby");
|
||||
var heading = document.getElementById(headingId);
|
||||
if (!heading) return;
|
||||
if (!sec.id) sec.id = headingId;
|
||||
|
||||
var a = document.createElement('a');
|
||||
a.href = '#' + sec.id;
|
||||
a.textContent = heading.textContent.trim();
|
||||
var a = document.createElement("a");
|
||||
a.href = `#${sec.id}`;
|
||||
a.textContent = heading.textContent.trim();
|
||||
|
||||
var li = document.createElement('li');
|
||||
li.appendChild(a);
|
||||
list.appendChild(li);
|
||||
items.push({ section: sec, link: a });
|
||||
});
|
||||
var li = document.createElement("li");
|
||||
li.appendChild(a);
|
||||
list.appendChild(li);
|
||||
items.push({ section: sec, link: a });
|
||||
});
|
||||
|
||||
// Generate a spread of thresholds for smooth IntersectionObserver firing.
|
||||
function buildThresholds() {
|
||||
var t = [];
|
||||
for (var i = 0; i <= 20; i++) t.push(i / 20);
|
||||
return t;
|
||||
}
|
||||
// Generate a spread of thresholds for smooth IntersectionObserver firing.
|
||||
function buildThresholds() {
|
||||
var t = [];
|
||||
for (var i = 0; i <= 20; i++) t.push(i / 20);
|
||||
return t;
|
||||
}
|
||||
|
||||
var observer = new IntersectionObserver(
|
||||
() => {
|
||||
// Active section = whose top is closest to the midpoint of the
|
||||
// viewport from above. At page bottom, the last section wins
|
||||
// even if its heading can't reach 50%.
|
||||
var line = window.innerHeight * 0.5;
|
||||
var best = null;
|
||||
var bestDist = Infinity;
|
||||
var observer = new IntersectionObserver(
|
||||
() => {
|
||||
// Active section = whose top is closest to the midpoint of the
|
||||
// viewport from above. At page bottom, the last section wins
|
||||
// even if its heading can't reach 50%.
|
||||
var line = window.innerHeight * 0.5;
|
||||
var best = null;
|
||||
var bestDist = Infinity;
|
||||
|
||||
// Pass 1: sections whose top is above/at the line
|
||||
items.forEach((item) => {
|
||||
var top = item.section.getBoundingClientRect().top;
|
||||
if (top <= line && (line - top) < bestDist) {
|
||||
bestDist = line - top;
|
||||
best = item;
|
||||
}
|
||||
});
|
||||
// Pass 1: sections whose top is above/at the line
|
||||
items.forEach((item) => {
|
||||
var top = item.section.getBoundingClientRect().top;
|
||||
if (top <= line && line - top < bestDist) {
|
||||
bestDist = line - top;
|
||||
best = item;
|
||||
}
|
||||
});
|
||||
|
||||
// Pass 2: no section above the line — pick closest from below
|
||||
if (!best) {
|
||||
items.forEach((item) => {
|
||||
var top = item.section.getBoundingClientRect().top;
|
||||
var dist = top - line;
|
||||
if (dist >= 0 && dist < bestDist) {
|
||||
bestDist = dist;
|
||||
best = item;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Pass 2: no section above the line — pick closest from below
|
||||
if (!best) {
|
||||
items.forEach((item) => {
|
||||
var top = item.section.getBoundingClientRect().top;
|
||||
var dist = top - line;
|
||||
if (dist >= 0 && dist < bestDist) {
|
||||
bestDist = dist;
|
||||
best = item;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Pass 3: at page bottom, if the last section is visible but
|
||||
// its heading never crossed 50%, promote it anyway.
|
||||
if (best) {
|
||||
var lastItem = items[items.length - 1];
|
||||
if (lastItem !== best) {
|
||||
var lastTop = lastItem.section.getBoundingClientRect().top;
|
||||
var atBottom = (window.innerHeight + window.scrollY + 5)
|
||||
>= document.documentElement.scrollHeight;
|
||||
if (atBottom && lastTop > line && lastTop < window.innerHeight) {
|
||||
best = lastItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pass 3: at page bottom, if the last section is visible but
|
||||
// its heading never crossed 50%, promote it anyway.
|
||||
if (best) {
|
||||
var lastItem = items[items.length - 1];
|
||||
if (lastItem !== best) {
|
||||
var lastTop = lastItem.section.getBoundingClientRect().top;
|
||||
var atBottom =
|
||||
window.innerHeight + window.scrollY + 5 >=
|
||||
document.documentElement.scrollHeight;
|
||||
if (atBottom && lastTop > line && lastTop < window.innerHeight) {
|
||||
best = lastItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!best && items.length > 0) best = items[0];
|
||||
items.forEach((item) => {
|
||||
item.link.classList.toggle('toc-active', item === best);
|
||||
});
|
||||
},
|
||||
{ threshold: buildThresholds() }
|
||||
);
|
||||
if (!best && items.length > 0) best = items[0];
|
||||
items.forEach((item) => {
|
||||
item.link.classList.toggle("toc-active", item === best);
|
||||
});
|
||||
},
|
||||
{ threshold: buildThresholds() },
|
||||
);
|
||||
|
||||
items.forEach((item) => {
|
||||
observer.observe(item.section);
|
||||
});
|
||||
}
|
||||
items.forEach((item) => {
|
||||
observer.observe(item.section);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', build);
|
||||
} else {
|
||||
build();
|
||||
}
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", build);
|
||||
} else {
|
||||
build();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -78,5 +78,3 @@ document.body.addEventListener("htmx:beforeRequest", (e) => {
|
||||
status.className = "autosave-status autosave-status--saving";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
* Name: queue_order[<queueType>] for the pipe-separated order.
|
||||
*/
|
||||
function syncOrderInput(queueType, pond) {
|
||||
if (!pond || !pond.element) return;
|
||||
if (!pond?.element) return;
|
||||
var form = pond.element.closest("form");
|
||||
if (!form) return;
|
||||
|
||||
@@ -724,7 +724,9 @@
|
||||
|
||||
// Find the label for the TFE input (its parent group's <label>)
|
||||
var fieldGroup = tfeInput.closest(".admin-files-fieldgroup");
|
||||
var label = fieldGroup ? fieldGroup.querySelector("label[for='tfe-files-input']") : null;
|
||||
var label = fieldGroup
|
||||
? fieldGroup.querySelector("label[for='tfe-files-input']")
|
||||
: null;
|
||||
|
||||
if (checkedAny) {
|
||||
tfeInput.removeAttribute("required");
|
||||
@@ -992,12 +994,12 @@
|
||||
? data.error
|
||||
: typeof data === "string"
|
||||
? data
|
||||
: "Erreur " + status;
|
||||
: `Erreur ${status}`;
|
||||
if (bodyEl)
|
||||
bodyEl.innerHTML = '<p class="file-browser-error">Erreur : ' + msg + '</p>';
|
||||
bodyEl.innerHTML = `<p class="file-browser-error">Erreur : ${msg}</p>`;
|
||||
return;
|
||||
}
|
||||
console.log("[pt-relink] success | new_id=" + data.id);
|
||||
console.log(`[pt-relink] success | new_id=${data.id}`);
|
||||
|
||||
var input = document.querySelector(
|
||||
'.tfe-file-picker[data-queue-type="tfe"]',
|
||||
@@ -1008,8 +1010,7 @@
|
||||
var block = document.getElementById("format-fichiers-block");
|
||||
if (block && window.htmx) {
|
||||
var url = "/admin/fragments/fichiers.php";
|
||||
if (thesisId)
|
||||
url += "?_thesis_id=" + encodeURIComponent(thesisId);
|
||||
if (thesisId) url += `?_thesis_id=${encodeURIComponent(thesisId)}`;
|
||||
htmx.ajax("GET", url, {
|
||||
target: "#format-fichiers-block",
|
||||
swap: "outerHTML",
|
||||
@@ -1050,8 +1051,7 @@
|
||||
.catch((err) => {
|
||||
console.error("[pt-relink] fetch error", err);
|
||||
if (bodyEl)
|
||||
bodyEl.innerHTML =
|
||||
'<p class="file-browser-error">Erreur réseau.</p>';
|
||||
bodyEl.innerHTML = '<p class="file-browser-error">Erreur réseau.</p>';
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* receives a single integer (total minutes).
|
||||
*/
|
||||
(() => {
|
||||
var form = document.querySelector('form.admin-form');
|
||||
if (!form) return;
|
||||
var form = document.querySelector("form.admin-form");
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener('submit', function() {
|
||||
var h = parseInt(document.getElementById('duration_h')?.value, 10) || 0;
|
||||
var m = parseInt(document.getElementById('duration_m')?.value, 10) || 0;
|
||||
var total = h * 60 + m;
|
||||
form.addEventListener("submit", () => {
|
||||
var h = parseInt(document.getElementById("duration_h")?.value, 10) || 0;
|
||||
var m = parseInt(document.getElementById("duration_m")?.value, 10) || 0;
|
||||
var total = h * 60 + m;
|
||||
|
||||
var hidden = document.getElementById('duration_minutes_hidden');
|
||||
if (!hidden) {
|
||||
hidden = document.createElement('input');
|
||||
hidden.type = 'hidden';
|
||||
hidden.name = 'duration_minutes';
|
||||
hidden.id = 'duration_minutes_hidden';
|
||||
form.appendChild(hidden);
|
||||
}
|
||||
hidden.value = total > 0 ? String(total) : '';
|
||||
});
|
||||
var hidden = document.getElementById("duration_minutes_hidden");
|
||||
if (!hidden) {
|
||||
hidden = document.createElement("input");
|
||||
hidden.type = "hidden";
|
||||
hidden.name = "duration_minutes";
|
||||
hidden.id = "duration_minutes_hidden";
|
||||
form.appendChild(hidden);
|
||||
}
|
||||
hidden.value = total > 0 ? String(total) : "";
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -5,62 +5,68 @@
|
||||
* Reads `data-admin-mode` (0/1) from the jury <fieldset>.
|
||||
*/
|
||||
(() => {
|
||||
// ── Dynamic row add/remove ──────────────────────────────────────────────
|
||||
window.addJuryRow = (listId, inputName, roleLabel) => {
|
||||
var list = document.getElementById(listId);
|
||||
if (!list) return;
|
||||
var n = list.querySelectorAll('.admin-jury-entry').length + 1;
|
||||
var div = document.createElement('div');
|
||||
div.className = 'admin-jury-entry';
|
||||
div.innerHTML =
|
||||
'<input type="text" name="' +
|
||||
inputName +
|
||||
'" placeholder="Nom" autocomplete="off" aria-label="' +
|
||||
roleLabel +
|
||||
' ' +
|
||||
n +
|
||||
' \u2014 nom">' +
|
||||
'<button type="button" class="btn btn--sm btn--ghost admin-btn-remove" onclick="removeJuryRow(this)" aria-label="Supprimer">' +
|
||||
'<span aria-hidden="true">\u2715</span></button>';
|
||||
list.appendChild(div);
|
||||
};
|
||||
// ── Dynamic row add/remove ──────────────────────────────────────────────
|
||||
window.addJuryRow = (listId, inputName, roleLabel) => {
|
||||
var list = document.getElementById(listId);
|
||||
if (!list) return;
|
||||
var n = list.querySelectorAll(".admin-jury-entry").length + 1;
|
||||
var div = document.createElement("div");
|
||||
div.className = "admin-jury-entry";
|
||||
div.innerHTML =
|
||||
'<input type="text" name="' +
|
||||
inputName +
|
||||
'" placeholder="Nom" autocomplete="off" aria-label="' +
|
||||
roleLabel +
|
||||
" " +
|
||||
n +
|
||||
' \u2014 nom">' +
|
||||
'<button type="button" class="btn btn--sm btn--ghost admin-btn-remove" onclick="removeJuryRow(this)" aria-label="Supprimer">' +
|
||||
'<span aria-hidden="true">\u2715</span></button>';
|
||||
list.appendChild(div);
|
||||
};
|
||||
|
||||
window.removeJuryRow = (btn) => {
|
||||
var entry = btn.closest('.admin-jury-entry');
|
||||
if (entry) entry.remove();
|
||||
};
|
||||
window.removeJuryRow = (btn) => {
|
||||
var entry = btn.closest(".admin-jury-entry");
|
||||
if (entry) entry.remove();
|
||||
};
|
||||
|
||||
// ── ULB toggle ─────────────────────────────────────────────────────────
|
||||
var juryFieldset = document.querySelector('fieldset[data-admin-mode]');
|
||||
var adminMode = juryFieldset ? juryFieldset.getAttribute('data-admin-mode') === '1' : false;
|
||||
// ── ULB toggle ─────────────────────────────────────────────────────────
|
||||
var juryFieldset = document.querySelector("fieldset[data-admin-mode]");
|
||||
var adminMode = juryFieldset
|
||||
? juryFieldset.getAttribute("data-admin-mode") === "1"
|
||||
: false;
|
||||
|
||||
try {
|
||||
var finalitySelect = document.querySelector('select[name="finality"]');
|
||||
var ulbRow = document.getElementById('jury-promoteur-ulb-row');
|
||||
if (!finalitySelect || !ulbRow) return;
|
||||
var ulbAsterisk = document.getElementById('jury-ulb-asterisk');
|
||||
try {
|
||||
var finalitySelect = document.querySelector('select[name="finality"]');
|
||||
var ulbRow = document.getElementById("jury-promoteur-ulb-row");
|
||||
if (!finalitySelect || !ulbRow) return;
|
||||
var ulbAsterisk = document.getElementById("jury-ulb-asterisk");
|
||||
|
||||
function isApprofondiSelected() {
|
||||
var opt = finalitySelect.options[finalitySelect.selectedIndex];
|
||||
if (!opt) return false;
|
||||
return (opt.textContent || opt.text || '').toLowerCase().includes('approfondi');
|
||||
}
|
||||
function isApprofondiSelected() {
|
||||
var opt = finalitySelect.options[finalitySelect.selectedIndex];
|
||||
if (!opt) return false;
|
||||
return (opt.textContent || opt.text || "")
|
||||
.toLowerCase()
|
||||
.includes("approfondi");
|
||||
}
|
||||
|
||||
function toggleUlb() {
|
||||
var show = isApprofondiSelected();
|
||||
ulbRow.style.display = show ? '' : 'none';
|
||||
if (ulbAsterisk) ulbAsterisk.style.display = show ? '' : 'none';
|
||||
var inputs = ulbRow.querySelectorAll('input[name="jury_promoteur_ulb_name[]"]');
|
||||
inputs.forEach((inp, idx) => {
|
||||
inp.required = adminMode ? false : show && idx === 0;
|
||||
inp.disabled = !show;
|
||||
if (!show) inp.value = '';
|
||||
});
|
||||
}
|
||||
function toggleUlb() {
|
||||
var show = isApprofondiSelected();
|
||||
ulbRow.style.display = show ? "" : "none";
|
||||
if (ulbAsterisk) ulbAsterisk.style.display = show ? "" : "none";
|
||||
var inputs = ulbRow.querySelectorAll(
|
||||
'input[name="jury_promoteur_ulb_name[]"]',
|
||||
);
|
||||
inputs.forEach((inp, idx) => {
|
||||
inp.required = adminMode ? false : show && idx === 0;
|
||||
inp.disabled = !show;
|
||||
if (!show) inp.value = "";
|
||||
});
|
||||
}
|
||||
|
||||
finalitySelect.addEventListener('change', toggleUlb);
|
||||
toggleUlb();
|
||||
} catch (e) {
|
||||
console.error('jury ULB toggle:', e);
|
||||
}
|
||||
finalitySelect.addEventListener("change", toggleUlb);
|
||||
toggleUlb();
|
||||
} catch (e) {
|
||||
console.error("jury ULB toggle:", e);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -5,28 +5,28 @@
|
||||
* Reads the container id from data-search-container-id on the pill-search div.
|
||||
*/
|
||||
(() => {
|
||||
var pillDiv = document.querySelector('[data-search-container-id]');
|
||||
if (!pillDiv) return;
|
||||
var containerId = pillDiv.getAttribute('data-search-container-id');
|
||||
var container = document.getElementById(containerId);
|
||||
if (!container) return;
|
||||
var pills = container.querySelector('.tag-search-pills');
|
||||
if (!pills) return;
|
||||
var pillDiv = document.querySelector("[data-search-container-id]");
|
||||
if (!pillDiv) return;
|
||||
var containerId = pillDiv.getAttribute("data-search-container-id");
|
||||
var container = document.getElementById(containerId);
|
||||
if (!container) return;
|
||||
var pills = container.querySelector(".tag-search-pills");
|
||||
if (!pills) return;
|
||||
|
||||
function check() {
|
||||
var asteriskEl = document.getElementById('languages-required-asterisk');
|
||||
if (!asteriskEl) return;
|
||||
var n = pills.querySelectorAll('.tag-pill').length;
|
||||
var checkboxes = document.querySelectorAll(
|
||||
'#languages-fieldset input[type="checkbox"]:checked'
|
||||
);
|
||||
asteriskEl.innerHTML =
|
||||
n === 0 && checkboxes.length === 0
|
||||
? ' <span class="asterisk">*</span>'
|
||||
: '';
|
||||
}
|
||||
function check() {
|
||||
var asteriskEl = document.getElementById("languages-required-asterisk");
|
||||
if (!asteriskEl) return;
|
||||
var n = pills.querySelectorAll(".tag-pill").length;
|
||||
var checkboxes = document.querySelectorAll(
|
||||
'#languages-fieldset input[type="checkbox"]:checked',
|
||||
);
|
||||
asteriskEl.innerHTML =
|
||||
n === 0 && checkboxes.length === 0
|
||||
? ' <span class="asterisk">*</span>'
|
||||
: "";
|
||||
}
|
||||
|
||||
var observer = new MutationObserver(check);
|
||||
observer.observe(pills, { childList: true });
|
||||
check();
|
||||
var observer = new MutationObserver(check);
|
||||
observer.observe(pills, { childList: true });
|
||||
check();
|
||||
})();
|
||||
|
||||
@@ -8,32 +8,35 @@
|
||||
* Loaded on all admin pages via footer.php.
|
||||
*/
|
||||
(() => {
|
||||
// Toast accessibility — auto-focus warning toasts
|
||||
document.body.addEventListener('htmx:afterSettle', (e) => {
|
||||
if (e.target && e.target.id === 'toast-region') {
|
||||
var warn = e.target.querySelector('.toast--warning');
|
||||
if (warn) {
|
||||
warn.setAttribute('tabindex', '-1');
|
||||
warn.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Toast accessibility — auto-focus warning toasts
|
||||
document.body.addEventListener("htmx:afterSettle", (e) => {
|
||||
if (e.target && e.target.id === "toast-region") {
|
||||
var warn = e.target.querySelector(".toast--warning");
|
||||
if (warn) {
|
||||
warn.setAttribute("tabindex", "-1");
|
||||
warn.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Markdown cheatsheet: remove stale dialogs before a new one arrives
|
||||
document.body.addEventListener('htmx:beforeRequest', (e) => {
|
||||
if (
|
||||
e.detail.requestConfig &&
|
||||
e.detail.requestConfig.path === '/admin/markdown-cheatsheet-fragment.php'
|
||||
) {
|
||||
var old = document.getElementById('md-cheatsheet-dialog');
|
||||
if (old) old.remove();
|
||||
}
|
||||
});
|
||||
// Markdown cheatsheet: remove stale dialogs before a new one arrives
|
||||
document.body.addEventListener("htmx:beforeRequest", (e) => {
|
||||
if (
|
||||
e.detail.requestConfig &&
|
||||
e.detail.requestConfig.path === "/admin/markdown-cheatsheet-fragment.php"
|
||||
) {
|
||||
var old = document.getElementById("md-cheatsheet-dialog");
|
||||
if (old) old.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Markdown cheatsheet: close on backdrop (dialog element) click
|
||||
document.body.addEventListener('click', (e) => {
|
||||
if (e.target.tagName === 'DIALOG' && e.target.id === 'md-cheatsheet-dialog') {
|
||||
e.target.close();
|
||||
}
|
||||
});
|
||||
// Markdown cheatsheet: close on backdrop (dialog element) click
|
||||
document.body.addEventListener("click", (e) => {
|
||||
if (
|
||||
e.target.tagName === "DIALOG" &&
|
||||
e.target.id === "md-cheatsheet-dialog"
|
||||
) {
|
||||
e.target.close();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -5,85 +5,79 @@
|
||||
* On desktop, all panels close when crossing the breakpoint.
|
||||
*/
|
||||
(() => {
|
||||
var INDEX_SEL = '#repertoire-index';
|
||||
var ACCORDION_SEL = '.rep-accordion';
|
||||
var TOGGLE_SEL = '.rep-accordion__toggle';
|
||||
var PANEL_SEL = '.rep-accordion__panel';
|
||||
var INDEX_SEL = "#repertoire-index";
|
||||
var ACCORDION_SEL = ".rep-accordion";
|
||||
var TOGGLE_SEL = ".rep-accordion__toggle";
|
||||
var PANEL_SEL = ".rep-accordion__panel";
|
||||
|
||||
function isMobile() {
|
||||
return window.matchMedia('(max-width: 1025px)').matches;
|
||||
}
|
||||
function isMobile() {
|
||||
return window.matchMedia("(max-width: 1025px)").matches;
|
||||
}
|
||||
|
||||
function initAccordions(root) {
|
||||
if (!isMobile()) return;
|
||||
var toggles = root.querySelectorAll(TOGGLE_SEL);
|
||||
toggles.forEach((btn) => {
|
||||
// Skip students column — always visible, not an accordion
|
||||
if (btn.closest('[data-col="students"]')) return;
|
||||
if (btn._accordionBound) return;
|
||||
btn._accordionBound = true;
|
||||
btn.addEventListener('click', () => {
|
||||
var section = btn.closest(ACCORDION_SEL);
|
||||
var panel = section.querySelector(PANEL_SEL);
|
||||
var isOpen = btn.getAttribute('aria-expanded') === 'true';
|
||||
function initAccordions(root) {
|
||||
if (!isMobile()) return;
|
||||
var toggles = root.querySelectorAll(TOGGLE_SEL);
|
||||
toggles.forEach((btn) => {
|
||||
// Skip students column — always visible, not an accordion
|
||||
if (btn.closest('[data-col="students"]')) return;
|
||||
if (btn._accordionBound) return;
|
||||
btn._accordionBound = true;
|
||||
btn.addEventListener("click", () => {
|
||||
var section = btn.closest(ACCORDION_SEL);
|
||||
var panel = section.querySelector(PANEL_SEL);
|
||||
var isOpen = btn.getAttribute("aria-expanded") === "true";
|
||||
|
||||
// Close all others (except students column)
|
||||
root.querySelectorAll(ACCORDION_SEL).forEach((s) => {
|
||||
if (s.dataset.col === 'students') return;
|
||||
var p = s.querySelector(PANEL_SEL);
|
||||
var t = s.querySelector(TOGGLE_SEL);
|
||||
if (s !== section) {
|
||||
t.setAttribute('aria-expanded', 'false');
|
||||
p.classList.remove('is-open');
|
||||
}
|
||||
});
|
||||
// Close all others (except students column)
|
||||
root.querySelectorAll(ACCORDION_SEL).forEach((s) => {
|
||||
if (s.dataset.col === "students") return;
|
||||
var p = s.querySelector(PANEL_SEL);
|
||||
var t = s.querySelector(TOGGLE_SEL);
|
||||
if (s !== section) {
|
||||
t.setAttribute("aria-expanded", "false");
|
||||
p.classList.remove("is-open");
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle this one
|
||||
var nowOpen = !isOpen;
|
||||
btn.setAttribute('aria-expanded', nowOpen ? 'true' : 'false');
|
||||
if (nowOpen) {
|
||||
panel.classList.add('is-open');
|
||||
} else {
|
||||
panel.classList.remove('is-open');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// Toggle this one
|
||||
var nowOpen = !isOpen;
|
||||
btn.setAttribute("aria-expanded", nowOpen ? "true" : "false");
|
||||
if (nowOpen) {
|
||||
panel.classList.add("is-open");
|
||||
} else {
|
||||
panel.classList.remove("is-open");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Initial bind
|
||||
initAccordions(document);
|
||||
// Initial bind
|
||||
initAccordions(document);
|
||||
|
||||
// Re-bind after HTMX swaps (use live DOM since e.detail.target may be detached)
|
||||
document.body.addEventListener('htmx:afterSwap', (e) => {
|
||||
if (
|
||||
e.detail.target &&
|
||||
e.detail.target.matches &&
|
||||
e.detail.target.matches(INDEX_SEL)
|
||||
) {
|
||||
var liveIndex = document.querySelector(INDEX_SEL);
|
||||
if (liveIndex) initAccordions(liveIndex);
|
||||
}
|
||||
});
|
||||
// Re-bind after HTMX swaps (use live DOM since e.detail.target may be detached)
|
||||
document.body.addEventListener("htmx:afterSwap", (e) => {
|
||||
if (e.detail.target?.matches?.(INDEX_SEL)) {
|
||||
var liveIndex = document.querySelector(INDEX_SEL);
|
||||
if (liveIndex) initAccordions(liveIndex);
|
||||
}
|
||||
});
|
||||
|
||||
// Re-bind on resize crossing the breakpoint
|
||||
var wasMobile = isMobile();
|
||||
window.addEventListener('resize', () => {
|
||||
var nowMobile = isMobile();
|
||||
if (nowMobile !== wasMobile) {
|
||||
wasMobile = nowMobile;
|
||||
if (!nowMobile) {
|
||||
// Switching to desktop — close all panels
|
||||
document
|
||||
.querySelectorAll(INDEX_SEL + ' ' + TOGGLE_SEL)
|
||||
.forEach((btn) => {
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
document
|
||||
.querySelectorAll(INDEX_SEL + ' ' + PANEL_SEL)
|
||||
.forEach((p) => {
|
||||
p.classList.remove('is-open');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// Re-bind on resize crossing the breakpoint
|
||||
var wasMobile = isMobile();
|
||||
window.addEventListener("resize", () => {
|
||||
var nowMobile = isMobile();
|
||||
if (nowMobile !== wasMobile) {
|
||||
wasMobile = nowMobile;
|
||||
if (!nowMobile) {
|
||||
// Switching to desktop — close all panels
|
||||
document
|
||||
.querySelectorAll(`${INDEX_SEL} ${TOGGLE_SEL}`)
|
||||
.forEach((btn) => {
|
||||
btn.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
document.querySelectorAll(`${INDEX_SEL} ${PANEL_SEL}`).forEach((p) => {
|
||||
p.classList.remove("is-open");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -8,63 +8,55 @@
|
||||
* DOM replacement.
|
||||
*/
|
||||
(() => {
|
||||
var INDEX_SEL = '#repertoire-index';
|
||||
var scrollSnapshots = {};
|
||||
var INDEX_SEL = "#repertoire-index";
|
||||
var scrollSnapshots = {};
|
||||
|
||||
function snapshot() {
|
||||
var index = document.querySelector(INDEX_SEL);
|
||||
if (!index) return;
|
||||
scrollSnapshots = {};
|
||||
index.querySelectorAll('.repertoire-col[data-col] > ul').forEach((ul) => {
|
||||
var col = ul.closest('.repertoire-col');
|
||||
if (!col) return;
|
||||
var key = col.getAttribute('data-col');
|
||||
scrollSnapshots[key] = ul.scrollTop;
|
||||
});
|
||||
}
|
||||
function snapshot() {
|
||||
var index = document.querySelector(INDEX_SEL);
|
||||
if (!index) return;
|
||||
scrollSnapshots = {};
|
||||
index.querySelectorAll(".repertoire-col[data-col] > ul").forEach((ul) => {
|
||||
var col = ul.closest(".repertoire-col");
|
||||
if (!col) return;
|
||||
var key = col.getAttribute("data-col");
|
||||
scrollSnapshots[key] = ul.scrollTop;
|
||||
});
|
||||
}
|
||||
|
||||
function restore() {
|
||||
var index = document.querySelector(INDEX_SEL);
|
||||
if (!index) return;
|
||||
index.querySelectorAll('.repertoire-col[data-col] > ul').forEach((ul) => {
|
||||
var col = ul.closest('.repertoire-col');
|
||||
if (!col) return;
|
||||
var key = col.getAttribute('data-col');
|
||||
if (scrollSnapshots[key] !== undefined) {
|
||||
ul.scrollTop = scrollSnapshots[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
function restore() {
|
||||
var index = document.querySelector(INDEX_SEL);
|
||||
if (!index) return;
|
||||
index.querySelectorAll(".repertoire-col[data-col] > ul").forEach((ul) => {
|
||||
var col = ul.closest(".repertoire-col");
|
||||
if (!col) return;
|
||||
var key = col.getAttribute("data-col");
|
||||
if (scrollSnapshots[key] !== undefined) {
|
||||
ul.scrollTop = scrollSnapshots[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Capture scroll positions before the outgoing element is replaced
|
||||
document.body.addEventListener('htmx:beforeSwap', (e) => {
|
||||
if (
|
||||
e.detail.target &&
|
||||
e.detail.target.matches &&
|
||||
e.detail.target.matches(INDEX_SEL)
|
||||
) {
|
||||
snapshot();
|
||||
}
|
||||
});
|
||||
// Capture scroll positions before the outgoing element is replaced
|
||||
document.body.addEventListener("htmx:beforeSwap", (e) => {
|
||||
if (e.detail.target?.matches?.(INDEX_SEL)) {
|
||||
snapshot();
|
||||
}
|
||||
});
|
||||
|
||||
// Restore after the new content is in the DOM
|
||||
document.body.addEventListener('htmx:afterSwap', (e) => {
|
||||
if (
|
||||
e.detail.target &&
|
||||
e.detail.target.matches &&
|
||||
e.detail.target.matches(INDEX_SEL)
|
||||
) {
|
||||
// Use requestAnimationFrame to ensure layout has settled
|
||||
requestAnimationFrame(() => {
|
||||
restore();
|
||||
});
|
||||
}
|
||||
});
|
||||
// Restore after the new content is in the DOM
|
||||
document.body.addEventListener("htmx:afterSwap", (e) => {
|
||||
if (e.detail.target?.matches?.(INDEX_SEL)) {
|
||||
// Use requestAnimationFrame to ensure layout has settled
|
||||
requestAnimationFrame(() => {
|
||||
restore();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Also restore on history navigation (browser back/forward)
|
||||
document.body.addEventListener('htmx:historyRestore', () => {
|
||||
requestAnimationFrame(() => {
|
||||
restore();
|
||||
});
|
||||
});
|
||||
// Also restore on history navigation (browser back/forward)
|
||||
document.body.addEventListener("htmx:historyRestore", () => {
|
||||
requestAnimationFrame(() => {
|
||||
restore();
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -5,53 +5,53 @@
|
||||
* with `data-student-name` attribute.
|
||||
*/
|
||||
(() => {
|
||||
var popover = document.getElementById('student-popover');
|
||||
var currentAnchor = null;
|
||||
var popover = document.getElementById("student-popover");
|
||||
var currentAnchor = null;
|
||||
|
||||
function position(anchor) {
|
||||
var r = anchor.getBoundingClientRect();
|
||||
var left = r.right + window.scrollX + 12;
|
||||
var top = r.top + window.scrollY;
|
||||
if (left + 300 > window.innerWidth + window.scrollX) {
|
||||
left = r.left + window.scrollX - 312;
|
||||
}
|
||||
popover.style.left = left + 'px';
|
||||
popover.style.top = top + 'px';
|
||||
}
|
||||
function position(anchor) {
|
||||
var r = anchor.getBoundingClientRect();
|
||||
var left = r.right + window.scrollX + 12;
|
||||
var top = r.top + window.scrollY;
|
||||
if (left + 300 > window.innerWidth + window.scrollX) {
|
||||
left = r.left + window.scrollX - 312;
|
||||
}
|
||||
popover.style.left = `${left}px`;
|
||||
popover.style.top = `${top}px`;
|
||||
}
|
||||
|
||||
document.body.addEventListener(
|
||||
'mouseenter',
|
||||
(e) => {
|
||||
var a = e.target.closest('[data-student-name]');
|
||||
if (!a) return;
|
||||
currentAnchor = a;
|
||||
},
|
||||
true
|
||||
);
|
||||
document.body.addEventListener(
|
||||
"mouseenter",
|
||||
(e) => {
|
||||
var a = e.target.closest("[data-student-name]");
|
||||
if (!a) return;
|
||||
currentAnchor = a;
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
document.body.addEventListener('htmx:afterSwap', (e) => {
|
||||
if (e.detail.target !== popover) return;
|
||||
if (currentAnchor) position(currentAnchor);
|
||||
popover.hidden = false;
|
||||
});
|
||||
document.body.addEventListener("htmx:afterSwap", (e) => {
|
||||
if (e.detail.target !== popover) return;
|
||||
if (currentAnchor) position(currentAnchor);
|
||||
popover.hidden = false;
|
||||
});
|
||||
|
||||
document.body.addEventListener(
|
||||
'mouseleave',
|
||||
(e) => {
|
||||
if (
|
||||
!e.target.closest('[data-student-name]') &&
|
||||
!e.target.closest('#student-popover')
|
||||
)
|
||||
return;
|
||||
setTimeout(() => {
|
||||
if (
|
||||
!document.querySelector('[data-student-name]:hover') &&
|
||||
!document.querySelector('#student-popover:hover')
|
||||
) {
|
||||
popover.hidden = true;
|
||||
}
|
||||
}, 120);
|
||||
},
|
||||
true
|
||||
);
|
||||
document.body.addEventListener(
|
||||
"mouseleave",
|
||||
(e) => {
|
||||
if (
|
||||
!e.target.closest("[data-student-name]") &&
|
||||
!e.target.closest("#student-popover")
|
||||
)
|
||||
return;
|
||||
setTimeout(() => {
|
||||
if (
|
||||
!document.querySelector("[data-student-name]:hover") &&
|
||||
!document.querySelector("#student-popover:hover")
|
||||
) {
|
||||
popover.hidden = true;
|
||||
}
|
||||
}, 120);
|
||||
},
|
||||
true,
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -4,42 +4,45 @@
|
||||
* Operates on #sidebar-links-form and #sidebar-link-tpl.
|
||||
*/
|
||||
(() => {
|
||||
var form = document.getElementById('sidebar-links-form');
|
||||
var tpl = document.getElementById('sidebar-link-tpl');
|
||||
if (!form || !tpl) return;
|
||||
var tplHtml = tpl.innerHTML;
|
||||
var form = document.getElementById("sidebar-links-form");
|
||||
var tpl = document.getElementById("sidebar-link-tpl");
|
||||
if (!form || !tpl) return;
|
||||
var tplHtml = tpl.innerHTML;
|
||||
|
||||
function reindexLinks() {
|
||||
var rows = form.querySelectorAll('.sidebar-link-row');
|
||||
rows.forEach((row, i) => {
|
||||
row.querySelectorAll('input').forEach((inp) => {
|
||||
if (inp.name) {
|
||||
inp.name = inp.name.replace(/links\[\d+\]/, 'links[' + i + ']');
|
||||
}
|
||||
if (inp.id) {
|
||||
inp.id = inp.id.replace(/sl_\d+/, 'sl_' + i);
|
||||
}
|
||||
});
|
||||
row.querySelectorAll('label[for]').forEach((lbl) => {
|
||||
lbl.setAttribute('for', lbl.getAttribute('for').replace(/sl_\d+/, 'sl_' + i));
|
||||
});
|
||||
});
|
||||
}
|
||||
function reindexLinks() {
|
||||
var rows = form.querySelectorAll(".sidebar-link-row");
|
||||
rows.forEach((row, i) => {
|
||||
row.querySelectorAll("input").forEach((inp) => {
|
||||
if (inp.name) {
|
||||
inp.name = inp.name.replace(/links\[\d+\]/, `links[${i}]`);
|
||||
}
|
||||
if (inp.id) {
|
||||
inp.id = inp.id.replace(/sl_\d+/, `sl_${i}`);
|
||||
}
|
||||
});
|
||||
row.querySelectorAll("label[for]").forEach((lbl) => {
|
||||
lbl.setAttribute(
|
||||
"for",
|
||||
lbl.getAttribute("for").replace(/sl_\d+/, `sl_${i}`),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Event delegation for remove buttons
|
||||
form.addEventListener('click', (e) => {
|
||||
if (!e.target.closest('.remove-sidebar-link-btn')) return;
|
||||
e.preventDefault();
|
||||
e.target.closest('.sidebar-link-row').remove();
|
||||
reindexLinks();
|
||||
});
|
||||
// Event delegation for remove buttons
|
||||
form.addEventListener("click", (e) => {
|
||||
if (!e.target.closest(".remove-sidebar-link-btn")) return;
|
||||
e.preventDefault();
|
||||
e.target.closest(".sidebar-link-row").remove();
|
||||
reindexLinks();
|
||||
});
|
||||
|
||||
// Add button
|
||||
var addBtn = document.getElementById('add-sidebar-link-btn');
|
||||
addBtn.addEventListener('click', function () {
|
||||
var rows = form.querySelectorAll('.sidebar-link-row');
|
||||
var idx = rows.length;
|
||||
var html = tplHtml.split('{{li}}').join(idx);
|
||||
this.insertAdjacentHTML('beforebegin', html);
|
||||
});
|
||||
// Add button
|
||||
var addBtn = document.getElementById("add-sidebar-link-btn");
|
||||
addBtn.addEventListener("click", function () {
|
||||
var rows = form.querySelectorAll(".sidebar-link-row");
|
||||
var idx = rows.length;
|
||||
var html = tplHtml.split("{{li}}").join(idx);
|
||||
this.insertAdjacentHTML("beforebegin", html);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* error. Reads the field id from data-smtp-error-field on the SMTP form.
|
||||
*/
|
||||
(() => {
|
||||
var form = document.querySelector('form[data-smtp-error-field]');
|
||||
if (!form) return;
|
||||
var fieldId = form.getAttribute('data-smtp-error-field');
|
||||
var el = fieldId ? document.getElementById(fieldId) : null;
|
||||
if (!el) return;
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
el.focus();
|
||||
var form = document.querySelector("form[data-smtp-error-field]");
|
||||
if (!form) return;
|
||||
var fieldId = form.getAttribute("data-smtp-error-field");
|
||||
var el = fieldId ? document.getElementById(fieldId) : null;
|
||||
if (!el) return;
|
||||
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
el.focus();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user