possible tag deletion fix

This commit is contained in:
2026-01-26 21:49:48 +01:00
parent 734071beab
commit ca86cf7c6e
3 changed files with 86 additions and 34 deletions

View File

@@ -52,7 +52,7 @@
const delbutton = document.createElement("a"); const delbutton = document.createElement("a");
delbutton.innerHTML = " ×"; delbutton.innerHTML = " ×";
delbutton.href = "#"; delbutton.href = "javascript:void(0)";
// Class for delegation // Class for delegation
delbutton.classList.add("admin-deltag"); delbutton.classList.add("admin-deltag");
@@ -70,18 +70,62 @@
if (!ctx) return; if (!ctx) return;
const { postid } = ctx; const { postid } = ctx;
if (!confirm("Do you really want to delete this tag?")) // Use normalized target logic if possible, or assume e.target (wrapped in listener)
return; // In delegation, we passed 'e'. e.target might be text node if not normalized in the handler call?
const tagname = e.target.parentElement.querySelector('a:first-child').innerText; // In listener I normalized 'target', but passed 'e' to deleteEvent.
// So 'e.target' is still the raw event target.
// I should check nodeType here or use closest properly.
const res = await (await fetch("/api/v2/admin/" + postid + "/tags/" + encodeURIComponent(tagname), { let target = e.target;
method: 'DELETE' if (target.nodeType === 3) target = target.parentElement;
})).json();
if (!res.success) const badge = target.closest('.badge');
return alert("uff"); const tagLink = badge.querySelector('a:first-child');
const tagname = tagLink.innerText;
renderTags(res.tags); const modal = document.getElementById('delete-tag-modal');
const nameEl = document.getElementById('delete-tag-name');
const confirmBtn = document.getElementById('delete-tag-confirm');
const cancelBtn = document.getElementById('delete-tag-cancel');
if (modal) {
nameEl.textContent = tagname;
confirmBtn.textContent = 'Delete';
confirmBtn.disabled = false;
modal.style.display = 'flex';
const closeModal = () => {
modal.style.display = 'none';
confirmBtn.onclick = null;
cancelBtn.onclick = null;
};
cancelBtn.onclick = closeModal;
confirmBtn.onclick = async () => {
confirmBtn.textContent = 'Deleting...';
confirmBtn.disabled = true;
try {
const res = await (await fetch("/api/v2/admin/" + postid + "/tags/" + encodeURIComponent(tagname), {
method: 'DELETE'
})).json();
if (!res.success) {
alert(res.msg || "uff");
confirmBtn.textContent = 'Delete';
confirmBtn.disabled = false;
} else {
renderTags(res.tags);
closeModal();
}
} catch (err) {
console.error(err);
alert("Error deleting tag");
confirmBtn.textContent = 'Delete';
confirmBtn.disabled = false;
}
};
}
}; };
const addtagClick = (e) => { const addtagClick = (e) => {
@@ -314,29 +358,24 @@
return false; return false;
}; };
// Event Delegation
// Event Delegation // Event Delegation
document.addEventListener("click", e => { document.addEventListener("click", e => {
if (e.target.matches("a#a_addtag")) { const target = e.target.nodeType === 3 ? e.target.parentElement : e.target;
if (target.matches("a#a_addtag")) {
addtagClick(e); addtagClick(e);
} else if (e.target.matches("a#a_toggle")) { } else if (target.matches("a#a_toggle")) {
toggleEvent(e); toggleEvent(e);
} else if (e.target.closest("svg#a_favo")) { } else if (target.closest("svg#a_favo")) {
toggleFavEvent(e); toggleFavEvent(e);
} else if (e.target.closest("svg#a_delete")) { } else if (target.closest("svg#a_delete")) {
deleteButtonEvent(e); deleteButtonEvent(e);
} else if (e.target.matches("#tags > .badge > a:first-child")) { } else if (target.matches("#tags > .badge > a:first-child")) {
editTagEvent(e); editTagEvent(e);
} else if (e.target.innerText === " \u00d7" && e.target.closest(".badge")) { // check text " x" or similar for delete? } else if (target.matches("#tags > .badge > a:last-child") || target.closest('.admin-deltag')) {
// Original was " ×" which is × (\u00d7). // Match by structure OR class (added in renderTags)
// Logic in deleteEvent expects match. deleteEvent(e);
// Let's rely on class or structure.
// In renderTags I added class 'admin-deltag'.
// Existing tags in HTML might NOT have this class unless rendered by JS?
// But existing tags are just HTML. We should match structure.
// selector: "#tags > .badge > a:last-child"
if (e.target.matches("#tags > .badge > a:last-child")) {
deleteEvent(e);
}
} }
}); });

View File

@@ -518,9 +518,10 @@ window.requestAnimFrame = (function () {
// Intercept clicks // Intercept clicks
document.addEventListener('click', (e) => { document.addEventListener('click', (e) => {
const target = e.target.nodeType === 3 ? e.target.parentElement : e.target;
// Check for thumbnail links on index page // Check for thumbnail links on index page
const thumbnail = e.target.closest('.posts > a'); const thumbnail = target.closest('.posts > a');
if (thumbnail && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) { if (thumbnail && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
e.preventDefault(); e.preventDefault();
// Thumbnails inherit context (e.g. from Tag Index) // Thumbnails inherit context (e.g. from Tag Index)
@@ -528,7 +529,7 @@ window.requestAnimFrame = (function () {
return; return;
} }
const link = e.target.closest('#next, #prev, #random, #nav-random, .id-link, .nav-next, .nav-prev'); const link = target.closest('#next, #prev, #random, #nav-random, .id-link, .nav-next, .nav-prev');
if (link && link.href && link.hostname === window.location.hostname && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) { if (link && link.href && link.hostname === window.location.hostname && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
// Special check for random // Special check for random
if (link.id === 'random' || link.id === 'nav-random') { if (link.id === 'random' || link.id === 'nav-random') {
@@ -579,7 +580,7 @@ window.requestAnimFrame = (function () {
} else { } else {
loadItemAjax(link.href, true); loadItemAjax(link.href, true);
} }
} else if (e.target.closest('#togglebg')) { } else if (target.closest('#togglebg')) {
e.preventDefault(); e.preventDefault();
background = !background; background = !background;
localStorage.setItem('background', background.toString()); localStorage.setItem('background', background.toString());
@@ -604,9 +605,9 @@ window.requestAnimFrame = (function () {
canvas.classList.add('fader-out'); canvas.classList.add('fader-out');
} }
} }
} else if (e.target.closest('.removetag')) { } else if (target.closest('.removetag')) {
e.preventDefault(); e.preventDefault();
const removeBtn = e.target.closest('.removetag'); const removeBtn = target.closest('.removetag');
const tagLink = removeBtn.previousElementSibling; const tagLink = removeBtn.previousElementSibling;
if (tagLink) { if (tagLink) {

View File

@@ -49,6 +49,17 @@
span.insertAdjacentElement("beforeend", a); span.insertAdjacentElement("beforeend", a);
if (document.querySelector('a[href^="/admin"]')) {
const space = document.createTextNode('\u00A0'); //  
span.appendChild(space);
const del = document.createElement("a");
del.className = "removetag";
del.href = "javascript:void(0)";
del.innerHTML = "×";
span.insertAdjacentElement("beforeend", del);
}
document.querySelector("#tags").insertAdjacentElement("afterbegin", span); document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
}); });
}; };
@@ -209,11 +220,12 @@
// Event Delegation // Event Delegation
document.addEventListener("click", e => { document.addEventListener("click", e => {
if (e.target.matches("a#a_addtag")) { const target = e.target.nodeType === 3 ? e.target.parentElement : e.target;
if (target.matches("a#a_addtag")) {
addtagClick(e); addtagClick(e);
} else if (e.target.matches("a#a_toggle")) { } else if (target.matches("a#a_toggle")) {
toggleEvent(e); toggleEvent(e);
} else if (e.target.closest("svg#a_favo")) { } else if (target.closest("svg#a_favo")) {
toggleFavEvent(e); toggleFavEvent(e);
} }
}); });