fix: side peek des bases repasse en vanilla JS + largeur 1100px standard (v7.49.0)
- Panneau peek: les bindings Alpine (x-data absent du conteneur) rendaient loovverture et le redimensionnement inoperants -> cblage direct sur le document. - Helper unique window.fdWirePeekResize (app.js): pointer capture, 300px-90vw, clic=fermer, largeur persiste fd_peek_width partagee entre les 4 peeks. - database-table-container margin:0 (tableau colle a gauche, marge Library). - .lib-container remonte dans app.css (trash etait pleine largeur), .db-index 1100px. - ObsiGate verifie sans code: creation .xlsx OK (openpyxl, #186).
This commit is contained in:
+71
-3
@@ -252,6 +252,12 @@
|
||||
// managed by Alpine or HTMX keep their default behaviour.
|
||||
function shouldIntercept(a, evt) {
|
||||
if (!a || !a.getAttribute || !isPlainLeftClick(evt)) return false;
|
||||
// Un handler plus profond a déjà traité le clic et appelé preventDefault
|
||||
// (onglets de vue, lien interne…). Sans ce test, le navigateur AND ce
|
||||
// navigateur SPA traitent le même clic : le composant rend son état, puis
|
||||
// `fdLoad` remplace la zone `.main-wrapper` par la réponse serveur — le
|
||||
// composant perd son DOM et la page finit vide.
|
||||
if (evt.defaultPrevented) return false;
|
||||
if (a.hasAttribute('data-no-nav')) return false;
|
||||
var target = (a.getAttribute('target') || '').toLowerCase();
|
||||
if (target && target !== '_self') return false;
|
||||
@@ -278,14 +284,30 @@
|
||||
}
|
||||
|
||||
var loading = false;
|
||||
var LOAD_WATCHDOG_MS = 15000;
|
||||
|
||||
function fdLoad(url, push) {
|
||||
if (!window.htmx) { window.location.href = url; return; }
|
||||
if (loading) return;
|
||||
// Une navigation est déjà en vol : on l'ABANDONNE au profit d'un chargement
|
||||
// complet. Avant, ce clic etait simplement ignore (aucune URL, aucun
|
||||
// changement) — et si la promesse htmx ne se resolvait jamais, `loading`
|
||||
// restait a `true` indefiniment : plus aucune navigation ne repartait, la
|
||||
// page restait figee (ou a moitie peinte) jusqu'au hard refresh.
|
||||
if (loading) { window.location.href = url; return; }
|
||||
loading = true;
|
||||
var settled = false;
|
||||
function done() {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
loading = false;
|
||||
clearTimeout(watchdog);
|
||||
}
|
||||
// Filet de securite : `loading` ne doit jamais pouvoir rester bloque.
|
||||
var watchdog = setTimeout(function () {
|
||||
if (settled) return;
|
||||
done();
|
||||
window.location.href = url;
|
||||
}, LOAD_WATCHDOG_MS);
|
||||
var p;
|
||||
try {
|
||||
p = window.htmx.ajax('GET', url, {
|
||||
@@ -361,7 +383,8 @@
|
||||
mw.style.opacity = '0';
|
||||
mw.style.pointerEvents = 'none';
|
||||
mw.setAttribute('x-ignore', '');
|
||||
var pending = mw.querySelectorAll('script[src]').length;
|
||||
var scripts = Array.prototype.slice.call(mw.querySelectorAll('script[src]'));
|
||||
var pending = scripts.length;
|
||||
var reveal = function () {
|
||||
if (!mw.isConnected) return;
|
||||
mw.style.opacity = '';
|
||||
@@ -380,7 +403,14 @@
|
||||
reveal();
|
||||
};
|
||||
var onScript = function (e) {
|
||||
if (!e.target || e.target.tagName !== 'SCRIPT') return;
|
||||
var node = e.target;
|
||||
// `load`/`error` en capture sur `document` voit TOUS les <script> de la
|
||||
// page, pas seulement ceux de la zone swappée : compter les uns et les
|
||||
// autres décomptait trop vite et montait l'arbre Alpine avant que les
|
||||
// scripts de la page n'aient tourné (page à moitié montée, composants
|
||||
// affiché à l'état brut). On ne compte donc que les noeuds attendus.
|
||||
if (!node || node.tagName !== 'SCRIPT') return;
|
||||
if (scripts.indexOf(node) === -1) return;
|
||||
if (--pending <= 0) done();
|
||||
};
|
||||
if (!pending) {
|
||||
@@ -481,3 +511,41 @@ function openCardDetail(id) {
|
||||
document.getElementById('card-modal-title').textContent = 'Issue #' + id;
|
||||
}
|
||||
|
||||
|
||||
// ── Side peek : poignée de redimensionnement partagée (v7.49.1) ──
|
||||
// Une seule implémentation pour les peeks de Library, du workspace local,
|
||||
// de My Tasks et des bases de données (le code copié trois fois dérivait :
|
||||
// celui de My Tasks ne capturait pas le pointeur et ne persistait rien).
|
||||
// La largeur choisie est commune à tous les peeks (localStorage fd_peek_width),
|
||||
// comme l'utilisateur ne voit qu'un seul panneau à la fois.
|
||||
window.fdWirePeekResize = function(panel, handle, onClose) {
|
||||
if (!panel || !handle) return;
|
||||
var startX, startWidth, dragging = false;
|
||||
handle.addEventListener('pointerdown', function(e) {
|
||||
e.preventDefault();
|
||||
try { handle.setPointerCapture(e.pointerId); } catch { /* pointeur fantôme */ }
|
||||
startX = e.clientX;
|
||||
startWidth = panel.offsetWidth;
|
||||
dragging = true;
|
||||
document.body.style.userSelect = 'none';
|
||||
});
|
||||
handle.addEventListener('pointermove', function(e) {
|
||||
if (!dragging) return;
|
||||
var w = Math.max(300, Math.min(window.innerWidth * 0.9, startWidth + (startX - e.clientX)));
|
||||
panel.style.width = w + 'px';
|
||||
});
|
||||
function stop(e) {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
document.body.style.userSelect = '';
|
||||
try { handle.releasePointerCapture(e.pointerId); } catch { /* déjà relâché */ }
|
||||
if (e && Math.abs(e.clientX - startX) < 3 && typeof onClose === 'function') onClose();
|
||||
try { localStorage.setItem('fd_peek_width', panel.style.width); } catch { /* navigation privée */ }
|
||||
}
|
||||
handle.addEventListener('pointerup', stop);
|
||||
handle.addEventListener('pointercancel', function() { dragging = false; document.body.style.userSelect = ''; });
|
||||
try {
|
||||
var saved = localStorage.getItem('fd_peek_width');
|
||||
if (saved) panel.style.width = saved;
|
||||
} catch { /* navigation privée */ }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user