feat(halls): immediately render hall badge in DOM upon adding/removing without requiring page refresh
This commit is contained in:
+112
-19
@@ -3667,7 +3667,7 @@ window.cancelAnimFrame = (function () {
|
||||
}
|
||||
|
||||
// ── Store in item cache (stale-while-revalidate) ───────────────────────
|
||||
if (html && !options.skipCache) {
|
||||
if (html && !options.noCacheStore) {
|
||||
itemCacheMap.set(_itemCacheKey, { html, slug: responseSlug, ts: Date.now() });
|
||||
if (itemCacheMap.size > ITEM_CACHE_MAX) {
|
||||
// Evict oldest entry
|
||||
@@ -10544,6 +10544,91 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// </image-modal>
|
||||
|
||||
// Halls Management (Admin Only / My Halls for all logged-in users)
|
||||
const escapeHtml = (str) => String(str ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
|
||||
const updateHallBadgeInDom = (hallSlug, hallName, action = 'add', isUserHall = false) => {
|
||||
if (!hallSlug) return;
|
||||
const liveHallBtn = document.getElementById('a_hall');
|
||||
const isModern = document.body.classList.contains('layout-modern') || !document.body.classList.contains('layout-legacy');
|
||||
|
||||
// 1. Update dataset on live #a_hall button
|
||||
if (liveHallBtn) {
|
||||
const datasetKey = isUserHall ? 'userHalls' : 'halls';
|
||||
const existing = (liveHallBtn.dataset[datasetKey] || '').split(',').filter(Boolean);
|
||||
if (action === 'add') {
|
||||
if (!existing.includes(hallSlug)) existing.push(hallSlug);
|
||||
if (isUserHall) liveHallBtn.dataset.currentUserHall = hallSlug;
|
||||
else liveHallBtn.dataset.currentHall = hallSlug;
|
||||
} else if (action === 'remove') {
|
||||
const idx = existing.indexOf(hallSlug);
|
||||
if (idx !== -1) existing.splice(idx, 1);
|
||||
if (isUserHall && liveHallBtn.dataset.currentUserHall === hallSlug) {
|
||||
liveHallBtn.dataset.currentUserHall = existing[0] || '';
|
||||
} else if (!isUserHall && liveHallBtn.dataset.currentHall === hallSlug) {
|
||||
liveHallBtn.dataset.currentHall = existing[0] || '';
|
||||
}
|
||||
}
|
||||
liveHallBtn.dataset[datasetKey] = existing.join(',');
|
||||
}
|
||||
|
||||
// 2. Main item header badge reflects site halls
|
||||
if (isUserHall) return;
|
||||
|
||||
let container = document.getElementById('hall-badge-container');
|
||||
if (!container) {
|
||||
// Check for existing .hall-badge-wrap without wrapper
|
||||
const existingWrap = document.querySelector('.hall-badge-wrap');
|
||||
if (existingWrap) {
|
||||
if (action === 'remove') {
|
||||
existingWrap.remove();
|
||||
return;
|
||||
}
|
||||
existingWrap.outerHTML = `<span class="badge hall-badge-wrap"><a href="/h/${escapeHtml(hallSlug)}" class="hall-badge-primary"><i class="fa-solid fa-layer-group"></i> ${escapeHtml(hallName || hallSlug)}</a></span>`;
|
||||
return;
|
||||
}
|
||||
// Dynamically create container and insert at the appropriate place
|
||||
container = document.createElement('span');
|
||||
container.id = 'hall-badge-container';
|
||||
if (isModern) {
|
||||
const tsLink = document.querySelector('.blahlol .timestamp-link');
|
||||
const tsBadge = tsLink ? tsLink.closest('.badge') : null;
|
||||
if (tsBadge && tsBadge.parentNode) {
|
||||
tsBadge.parentNode.insertBefore(container, tsBadge);
|
||||
} else {
|
||||
const blahlol = document.querySelector('.blahlol');
|
||||
if (blahlol) blahlol.appendChild(container);
|
||||
}
|
||||
} else {
|
||||
const gapRight = document.querySelector('.blahlol .gapRight');
|
||||
if (gapRight && gapRight.parentNode) {
|
||||
gapRight.parentNode.insertBefore(container, gapRight);
|
||||
} else {
|
||||
const blahlol = document.querySelector('.blahlol');
|
||||
if (blahlol) blahlol.appendChild(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action === 'add') {
|
||||
const badgeHtml = `<span class="badge hall-badge-wrap"><a href="/h/${escapeHtml(hallSlug)}" class="hall-badge-primary"><i class="fa-solid fa-layer-group"></i> ${escapeHtml(hallName || hallSlug)}</a></span>`;
|
||||
container.innerHTML = isModern ? ` — ${badgeHtml} — ` : ` — ${badgeHtml}`;
|
||||
} else if (action === 'remove') {
|
||||
const remaining = liveHallBtn ? (liveHallBtn.dataset.halls || '').split(',').filter(Boolean) : [];
|
||||
if (remaining.length > 0) {
|
||||
const nextSlug = remaining[0];
|
||||
const badgeHtml = `<span class="badge hall-badge-wrap"><a href="/h/${escapeHtml(nextSlug)}" class="hall-badge-primary"><i class="fa-solid fa-layer-group"></i> ${escapeHtml(nextSlug)}</a></span>`;
|
||||
container.innerHTML = isModern ? ` — ${badgeHtml} — ` : ` — ${badgeHtml}`;
|
||||
} else {
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', async (e) => {
|
||||
// Add to Hall
|
||||
const hallBtn = e.target.closest('#a_hall');
|
||||
@@ -10709,8 +10794,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
const hallName = (select.selectedOptions && select.selectedOptions[0]) ? select.selectedOptions[0].textContent : hallSlug;
|
||||
updateHallBadgeInDom(hallSlug, hallName, 'add', false);
|
||||
if (window.invalidateItemCache) window.invalidateItemCache(itemid);
|
||||
if (window.flashMessage) window.flashMessage((window.f0ckI18n && window.f0ckI18n.hall_added) || 'Added to hall!');
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true });
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true, skipCache: true });
|
||||
close();
|
||||
} else {
|
||||
throw new Error(data.msg || 'Failed to add to hall');
|
||||
@@ -10771,17 +10859,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (data.success) {
|
||||
myHallsConfirmBtn.disabled = false;
|
||||
myHallsConfirmBtn.textContent = window.f0ckI18n?.hall_add_btn || 'Add';
|
||||
// Patch the live #a_hall button NOW so next modal open pre-selects correctly
|
||||
// (before loadItemAjax finishes re-rendering the DOM)
|
||||
const liveHallBtn = document.getElementById('a_hall');
|
||||
if (liveHallBtn) {
|
||||
liveHallBtn.dataset.currentUserHall = hallSlug;
|
||||
const existing = (liveHallBtn.dataset.userHalls || '').split(',').filter(Boolean);
|
||||
if (!existing.includes(hallSlug)) existing.push(hallSlug);
|
||||
liveHallBtn.dataset.userHalls = existing.join(',');
|
||||
}
|
||||
const hallName = (myHallsSelect && myHallsSelect.selectedOptions && myHallsSelect.selectedOptions[0])
|
||||
? myHallsSelect.selectedOptions[0].textContent.replace(/\s*🔒\s*$/, '')
|
||||
: hallSlug;
|
||||
updateHallBadgeInDom(hallSlug, hallName, 'add', true);
|
||||
if (window.invalidateItemCache) window.invalidateItemCache(itemid);
|
||||
if (window.flashMessage) window.flashMessage((window.f0ckI18n && window.f0ckI18n.hall_added) || 'Added to hall!');
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true });
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true, skipCache: true });
|
||||
close();
|
||||
} else {
|
||||
throw new Error(data.message || data.msg || 'Failed to add');
|
||||
@@ -10814,8 +10898,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
updateHallBadgeInDom(hallSlug, '', 'remove', false);
|
||||
if (window.invalidateItemCache) window.invalidateItemCache(itemid);
|
||||
if (window.flashMessage) window.flashMessage((window.f0ckI18n && window.f0ckI18n.hall_removed) || 'Removed from hall!');
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true });
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true, skipCache: true });
|
||||
close();
|
||||
} else {
|
||||
throw new Error(data.msg || 'Failed to remove from hall');
|
||||
@@ -10845,8 +10931,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (data.success) {
|
||||
myHallsRemoveBtn.disabled = false;
|
||||
myHallsRemoveBtn.textContent = 'Remove';
|
||||
updateHallBadgeInDom(slug, '', 'remove', true);
|
||||
if (window.invalidateItemCache) window.invalidateItemCache(itemid);
|
||||
window.flashMessage((window.f0ckI18n && window.f0ckI18n.hall_removed) || 'Removed from hall!');
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true });
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true, skipCache: true });
|
||||
close();
|
||||
} else {
|
||||
throw new Error(data.message || data.msg || 'Failed to remove');
|
||||
@@ -10869,20 +10957,25 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!confirm('Remove from this hall?')) return;
|
||||
|
||||
const container = document.getElementById('comments-container');
|
||||
const itemid = container ? container.dataset.itemId : null;
|
||||
const itemid = container ? container.dataset.itemId : (document.querySelector('.id-link')?.dataset.itemId || null);
|
||||
const hallSlug = removeBtn.dataset.hall;
|
||||
|
||||
if (!itemid || !hallSlug) return window.flashMessage('Error: Missing itemid or hallSlug', 3000, 'error');
|
||||
|
||||
const token = (window.f0ckSession && window.f0ckSession.csrf_token) || '';
|
||||
const resp = await fetch('/mod/halls/remove', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `id=${itemid}&hall=${encodeURIComponent(hallSlug)}`
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-CSRF-Token': token
|
||||
},
|
||||
body: `id=${itemid}&hall=${encodeURIComponent(hallSlug)}&csrf_token=${encodeURIComponent(token)}`
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
// Refresh item view to remove hall badge
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true });
|
||||
updateHallBadgeInDom(hallSlug, '', 'remove', false);
|
||||
if (window.invalidateItemCache) window.invalidateItemCache(itemid);
|
||||
if (window.loadItemAjax) window.loadItemAjax(window.location.href, true, { keepMedia: true, skipCache: true });
|
||||
} else {
|
||||
window.flashMessage(data.msg || 'Failed to remove from hall', 3000, 'error');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user