fix: prevent continue-reading card from duplicating chapter label on repeated back-navigation
The previous approach cloned the card DOM node and used removeChild to move it, which meant the source node was gone on re-runs and a stale clone could persist across history restores. Replace with: clear continueGrid, build a fresh <a> element from the source card's attributes/innerHTML on every run, and hide (not remove) the original in #books-grid so it is always available as a clean source. Also scope the data-slug selector to #books-grid to avoid accidental matches against the continue-reading cards themselves.
This commit is contained in:
@@ -205,28 +205,53 @@ const homeTmpl = `
|
||||
var continueGrid = document.getElementById('continue-reading-grid');
|
||||
var availableHeading = document.getElementById('available-heading');
|
||||
|
||||
// Clear any stale cards from a previous render (e.g. HTMX re-executing this
|
||||
// script after a history restore) before re-populating.
|
||||
// Always clear before re-populating so back-navigation never duplicates cards.
|
||||
if (continueGrid) continueGrid.innerHTML = '';
|
||||
|
||||
if (inProgress.length > 0) {
|
||||
if (inProgress.length > 0 && continueGrid) {
|
||||
var moved = 0;
|
||||
inProgress.forEach(function(slug) {
|
||||
var card = document.querySelector('[data-slug="' + slug + '"]');
|
||||
// Find the source card in #books-grid by data-slug.
|
||||
var card = document.querySelector('#books-grid [data-slug="' + slug + '"]');
|
||||
if (!card) return;
|
||||
var clone = card.cloneNode(true);
|
||||
|
||||
var chapterNum = progress[slug];
|
||||
var meta = clone.querySelector('.min-w-0');
|
||||
if (meta && chapterNum) {
|
||||
|
||||
// Build a fresh card element rather than cloning + mutating,
|
||||
// so repeated back-navigations cannot accumulate injected nodes.
|
||||
var a = document.createElement('a');
|
||||
a.href = card.getAttribute('href');
|
||||
a.setAttribute('hx-get', card.getAttribute('hx-get'));
|
||||
a.setAttribute('hx-target', card.getAttribute('hx-target'));
|
||||
a.setAttribute('hx-push-url', card.getAttribute('hx-push-url'));
|
||||
a.setAttribute('hx-swap', card.getAttribute('hx-swap'));
|
||||
a.setAttribute('data-slug', slug);
|
||||
a.className = card.className;
|
||||
// Copy inner HTML then inject the chapter-progress line.
|
||||
a.innerHTML = card.innerHTML;
|
||||
if (chapterNum) {
|
||||
var meta = a.querySelector('.min-w-0');
|
||||
if (meta) {
|
||||
// Remove any previously injected progress line (defensive).
|
||||
var old = meta.querySelector('.chapter-progress-line');
|
||||
if (old) old.parentNode.removeChild(old);
|
||||
|
||||
var chLine = document.createElement('p');
|
||||
chLine.className = 'text-xs text-amber-400 mt-1';
|
||||
chLine.className = 'chapter-progress-line text-xs text-amber-400 mt-1';
|
||||
chLine.textContent = 'Chapter ' + chapterNum;
|
||||
var author = meta.querySelector('p');
|
||||
if (author) author.insertAdjacentElement('afterend', chLine);
|
||||
else { var title = meta.querySelector('h2'); if (title) title.insertAdjacentElement('afterend', chLine); }
|
||||
else {
|
||||
var title = meta.querySelector('h2');
|
||||
if (title) title.insertAdjacentElement('afterend', chLine);
|
||||
}
|
||||
continueGrid.appendChild(clone);
|
||||
card.parentNode.removeChild(card);
|
||||
}
|
||||
}
|
||||
htmx.process(a);
|
||||
continueGrid.appendChild(a);
|
||||
// Hide the original from the all-books grid (don't remove, just hide,
|
||||
// so the DOM node stays available for future re-runs on the same page).
|
||||
card.style.display = 'none';
|
||||
moved++;
|
||||
});
|
||||
if (moved > 0) {
|
||||
|
||||
Reference in New Issue
Block a user