Fix footer freezing after Année filter / Aller à / retour à Toutes

v-if="loading" swaps out <div ref="tableWrap"> for a brand new DOM
node every time loading toggles true -> false. mounted() only attaches
the scroll listener once, to whichever wrap existed at mount time --
enterYearMode(), exitYearMode(), and jumpToYear() all trigger that
swap, silently orphaning the listener on the old (now-detached) node.
After any of those three, scrolling stopped calling checkEdges()/
detectCurrentYear() at all, freezing the footer's year totals.

ensureScrollListener() re-attaches (idempotently, via a dataset flag)
after every such transition. Verified: the wrap element does change
identity across jumpToYear(), and the new element picks up the
listener and fetches totals for the newly-visible year correctly.
This commit is contained in:
2026-09-04 21:39:19 +02:00
parent 53c4e58e72
commit a45d55cb81
@@ -605,6 +605,22 @@
this.checkEdges(); this.checkEdges();
}); });
}, },
// mounted() only runs once, but `v-if="loading"` swaps out the
// <div ref="tableWrap"> for a fresh DOM node every time loading
// toggles true -> false (enterYearMode/exitYearMode/jumpToYear all
// do this) -- the old node's scroll listener goes with it, silently
// leaving the new one with no listener at all (checkEdges() and
// detectCurrentYear(), and so the footer, stop responding to
// scroll). Call this after every such transition, once the new
// wrap exists; the dataset flag makes it a no-op if the element is
// unchanged.
ensureScrollListener() {
const wrap = this.$refs.tableWrap;
if (wrap && !wrap.dataset.figliScrollBound) {
wrap.dataset.figliScrollBound = '1';
wrap.addEventListener('scroll', this.onScroll, { passive: true });
}
},
async loadCurrentYearTotals() { async loadCurrentYearTotals() {
if (!this.currentYear) return; if (!this.currentYear) return;
this.currentYearLoading = true; this.currentYearLoading = true;
@@ -638,6 +654,7 @@
} }
await this.$nextTick(); await this.$nextTick();
if (this.$refs.tableWrap) this.$refs.tableWrap.scrollTop = 0; if (this.$refs.tableWrap) this.$refs.tableWrap.scrollTop = 0;
this.ensureScrollListener();
this.detectCurrentYear(); this.detectCurrentYear();
}, },
// Back to "Toutes" -- resume the normal sliding window, re-centered // Back to "Toutes" -- resume the normal sliding window, re-centered
@@ -648,6 +665,7 @@
await this.$nextTick(); await this.$nextTick();
const wrap = this.$refs.tableWrap; const wrap = this.$refs.tableWrap;
if (wrap) wrap.scrollTop = wrap.scrollHeight; if (wrap) wrap.scrollTop = wrap.scrollHeight;
this.ensureScrollListener();
this.detectCurrentYear(); this.detectCurrentYear();
}, },
// "Aller à" -- a one-shot navigation shortcut, distinct from the // "Aller à" -- a one-shot navigation shortcut, distinct from the
@@ -686,6 +704,7 @@
await this.$nextTick(); await this.$nextTick();
const wrap = this.$refs.tableWrap; const wrap = this.$refs.tableWrap;
if (wrap) wrap.scrollTop = 0; if (wrap) wrap.scrollTop = 0;
this.ensureScrollListener();
this.detectCurrentYear(); this.detectCurrentYear();
this.checkEdges(); this.checkEdges();
}, },
@@ -713,8 +732,8 @@
jQuery(document).on('dialog:afterclose', () => this.reloadWindow()); jQuery(document).on('dialog:afterclose', () => this.reloadWindow());
await this.$nextTick(); await this.$nextTick();
const wrap = this.$refs.tableWrap; const wrap = this.$refs.tableWrap;
this.ensureScrollListener();
if (wrap) { if (wrap) {
wrap.addEventListener('scroll', this.onScroll, { passive: true });
// Start scrolled to the most recent data (the window is centered // Start scrolled to the most recent data (the window is centered
// on "today", so that's the bottom of what's loaded). // on "today", so that's the bottom of what's loaded).
wrap.scrollTop = wrap.scrollHeight; wrap.scrollTop = wrap.scrollHeight;