fix: navigation partielle Alpine sans course + scripts de page idempotents (v7.45.2)
- app.js : x-ignore sur .main-wrapper au swap fdLoad (nœud remplacé uniquement), démontage unique quand tous les <script src> ont exécuté (load/error + filet 4s) via Alpine.initTree idempotent (_x_marker) — fini les cascades « Undefined variable » (éditeur) et « reading 'has' » ($store.fdCtx) : la zone s'initialisait avant composants et stores. - 5 scripts de page gardés contre la ré-exécution (SyntaxError « Identifier 'LW' has already been declared » à la 2e visite partielle) : local_workspace, board, settings, database_table, page_editor_realtime. - if (window.Alpine) → Alpine.data immédiat sinon listener alpine:init (déjà passé sur swap) : 8 scripts + 7 templates inline. - app.css : purge des 7 blocs @font-face Inter orphelins (fichiers inexistants → 302 HTML → « Failed to decode downloaded font »). - Gates : e2e/regression_editor_mount + e2e/regression_partial_nav (7 pages x complet/1er/2e passage) + regression_logout_dnd + smoke = 6/6 verts sur l'image rebuildée · pytest 1094 passed · ruff OK · OpenAPI 7.45.2.
This commit is contained in:
@@ -326,6 +326,67 @@
|
||||
fdLoad(window.location.href, false);
|
||||
});
|
||||
|
||||
// ── Swap partiel : monter proprement la zone swapée sous Alpine ──
|
||||
// Lors d'une navigation partielle (fdLoad), les <script src> de la page
|
||||
// s'exécutent APRÈS le microtask MutationObserver d'Alpine : toute la zone
|
||||
// .main-wrapper serait initialisée avant que composants ET stores (menu
|
||||
// contextuel $store.fdCtx, …) existent → « Undefined variable: … » puis
|
||||
// « reading 'has' » sur les stores. On pose x-ignore sur TOUTE la zone
|
||||
// pendant le chargement des scripts, puis on démarle quand tous les
|
||||
// <script src> ont exécuté (load/error) — filet de sécurité 4 s.
|
||||
// (initTree est idempotent : le _x_marker posé au premier passage évite
|
||||
// tout double montage.)
|
||||
var fdLastMw = document.querySelector('.main-wrapper'); // nœud du chargement complet
|
||||
window.fdRefreshXData = function (name) {
|
||||
document.querySelectorAll('[x-data="' + name + '()"]').forEach(function (el) {
|
||||
if (el.__fdRefreshed) return;
|
||||
var st = el._x_dataStack;
|
||||
if (!st) return; // sous x-ignore → done() montera
|
||||
if (st[0] && Object.keys(st[0]).length) return; // déjà monté correctement
|
||||
el.__fdRefreshed = true; // monté cassé (hors watcher) → on remonte
|
||||
var fresh = el.cloneNode(true);
|
||||
el.parentNode.replaceChild(fresh, el);
|
||||
if (window.htmx) { try { htmx.process(fresh); } catch { /* volontaire */ } }
|
||||
});
|
||||
};
|
||||
|
||||
document.addEventListener('htmx:afterSwap', function () {
|
||||
var mw = document.querySelector('.main-wrapper');
|
||||
// nœud inchangé = swap hors navigation (sidebar, vues) : rien à faire
|
||||
if (!mw || mw === fdLastMw || mw.__fdSwapWatch) return;
|
||||
fdLastMw = mw;
|
||||
mw.__fdSwapWatch = true;
|
||||
mw.setAttribute('x-ignore', '');
|
||||
var pending = mw.querySelectorAll('script[src]').length;
|
||||
var done = function () {
|
||||
if (!mw.__fdSwapWatch) return;
|
||||
mw.__fdSwapWatch = false;
|
||||
document.removeEventListener('load', onScript, true);
|
||||
document.removeEventListener('error', onScript, true);
|
||||
if (!mw.isConnected || !mw.hasAttribute('x-ignore')) return;
|
||||
mw.removeAttribute('x-ignore');
|
||||
mw._x_ignore = false; // propriété posée par Alpine au checkpoint
|
||||
try { Alpine.initTree(mw); } catch (e) { console.warn('[FlowDeck] mount', e); }
|
||||
};
|
||||
var onScript = function (e) {
|
||||
if (!e.target || e.target.tagName !== 'SCRIPT') return;
|
||||
if (--pending <= 0) done();
|
||||
};
|
||||
if (!pending) {
|
||||
// Avant le microtask MutationObserver d'Alpine : retirer x-ignore suffit,
|
||||
// le MO initialisera au checkpoint (initTree de sécurité = no-op).
|
||||
mw.removeAttribute('x-ignore');
|
||||
mw.__fdSwapWatch = false;
|
||||
setTimeout(function () {
|
||||
if (mw.isConnected) { try { Alpine.initTree(mw); } catch (e) { console.warn('[FlowDeck] mount', e); } }
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
document.addEventListener('load', onScript, true);
|
||||
document.addEventListener('error', onScript, true);
|
||||
setTimeout(done, 4000);
|
||||
});
|
||||
|
||||
// Ctrl/Cmd + \ : toggle the sidebar (Notion-style).
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === '\\' || e.code === 'Backslash')) {
|
||||
|
||||
Reference in New Issue
Block a user