fix(alpine): resolve console errors on editor and agent panel
Initialize coverOpen/coverLoading in editorState, render import file info with x-if instead of x-show (null deref), split x-if/x-for on the agent mention menu, guard m.steps.length and use unique keys for the icon picker. Also reduce htmx swap responses to .main-wrapper so shell scripts (agent panel, base inline) are not re-executed on partial navigation.
This commit is contained in:
@@ -284,7 +284,7 @@
|
||||
</div>
|
||||
<div x-show="iconOpen" style="margin-top:12px;" x-transition>
|
||||
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:center;">
|
||||
<template x-for="ic in ['📄','📝','📋','📊','🗂️','📁','📂','🗒️','🗓️','📌','🔖','⭐','🚀','💡','🎯','🔑','📚','🧪','🌍','💰','📝','🧩','🎨','🔧','⚙️','🗃️','📦','🏷️','📍','🏠','👤']" :key="ic">
|
||||
<template x-for="(ic, ici) in ['📄','📝','📋','📊','🗂️','📁','📂','🗒️','🗓️','📌','🔖','⭐','🚀','💡','🎯','🔑','📚','🧪','🌍','💰','📝','🧩','🎨','🔧','⚙️','🗃️','📦','🏷️','📍','🏠','👤']" :key="ici">
|
||||
<button type="button" class="sd-icon-btn" @click="setIcon(ic)" :class="{ active: iconValue === ic }" style="width:36px;height:36px;border-radius:6px;border:1px solid var(--border);background:var(--bg-secondary);font-size:18px;display:flex;align-items:center;justify-content:center;cursor:pointer;" x-text="ic"></button>
|
||||
</template>
|
||||
<input type="text" class="sd-input" x-model="iconValue" placeholder="Custom emoji" style="max-width:80px;" @keydown.enter.prevent="setIcon(iconValue);iconOpen=false;">
|
||||
@@ -815,10 +815,12 @@
|
||||
<div style="border-top:1px solid var(--border);padding-top:16px;">
|
||||
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:8px;color:var(--text);">{{ fd_icon('file',14) }} File (.md, .txt, .zip)</label>
|
||||
<input type="file" accept=".md,.markdown,.txt,.zip" @change="handleImportFile($event)" style="width:100%;padding:12px;background:var(--bg-primary);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;box-sizing:border-box;">
|
||||
<div x-show="importFile" style="margin-top:8px;display:flex;align-items:center;gap:12px;color:var(--text-dim);font-size:13px;">
|
||||
<template x-if="importFile">
|
||||
<div style="margin-top:8px;display:flex;align-items:center;gap:12px;color:var(--text-dim);font-size:13px;">
|
||||
<span x-text="importFile.name"></span>
|
||||
<span x-text="Math.round(importFile.size/1024)+' KB'"></span>
|
||||
</div>
|
||||
</template>
|
||||
<div style="display:flex;gap:8px;margin-top:10px;">
|
||||
<button class="sd-btn-primary" @click="doImport()" :disabled="!importText.trim() && !importFile">{{ fd_icon('download',14) }} Import file</button>
|
||||
</div>
|
||||
|
||||
@@ -901,6 +901,8 @@ window.__fdEditorScriptsLoaded = true;
|
||||
undoStack:[],redoStack:[],_histCap:100,_histLock:false,
|
||||
// ── Cover & icon (v5.10+) ──
|
||||
coverUrl:'',
|
||||
coverOpen:false,
|
||||
coverLoading:false,
|
||||
iconOpen:false,
|
||||
iconValue:'',
|
||||
// ── Import ──
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
<div class="fd-steps" x-show="m.steps && m.steps.length" x-cloak>
|
||||
<button class="fd-steps-head" type="button" @click="toggleSteps(m)">
|
||||
<span class="fd-steps-chev" :class="{down: m.stepsOpen}">▶</span>
|
||||
<span class="fd-steps-count" x-text="m.steps.length === 1 ? '1 étape' : m.steps.length + ' étapes'"></span>
|
||||
<span class="fd-steps-count" x-text="!m.steps ? '' : (m.steps.length === 1 ? '1 étape' : m.steps.length + ' étapes')"></span>
|
||||
<span class="fd-steps-elem" x-text="m.generating ? 'en cours…' : (m.stepsOpen ? 'réduire' : 'voir le déroulé')"></span>
|
||||
</button>
|
||||
<div class="fd-steps-body" x-show="m.stepsOpen" x-cloak>
|
||||
@@ -373,7 +373,8 @@
|
||||
<template x-if="!mentionLoad && !hasMentionItems">
|
||||
<div class="fd-mention-empty">Aucun élément. Tapez un nom de document, page ou base.</div>
|
||||
</template>
|
||||
<template x-if="!mentionLoad" x-for="it in mentionItems" :key="it.token || it.key">
|
||||
<template x-if="!mentionLoad">
|
||||
<template x-for="it in mentionItems" :key="it.token || it.key">
|
||||
<div>
|
||||
<div class="fd-mention-sep" x-show="it._sep" x-text="it._sep"></div>
|
||||
<div class="fd-mention-item" x-show="!it._sep" :class="{focus: it._i===mentionFocus}"
|
||||
@@ -386,6 +387,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fd-ap-chips" x-show="contextChips.length" x-cloak>
|
||||
|
||||
@@ -366,6 +366,22 @@
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
// htmx parses the WHOLE response and executes every <script> it contains,
|
||||
// including shell scripts (agent panel, base inline scripts) that live
|
||||
// outside .main-wrapper. Re-running those corrupts Alpine state (x-for
|
||||
// teardown errors). Before the swap, reduce the response to the
|
||||
// .main-wrapper fragment so only page scripts are executed.
|
||||
document.body.addEventListener('htmx:beforeSwap', function(evt) {
|
||||
var d = evt.detail;
|
||||
if (!d || !d.target || !d.target.classList || !d.target.classList.contains('main-wrapper')) return;
|
||||
if (!d.serverResponse || typeof d.serverResponse !== 'string') return;
|
||||
try {
|
||||
var doc = new DOMParser().parseFromString(d.serverResponse, 'text/html');
|
||||
var mw = doc.querySelector('.main-wrapper');
|
||||
if (mw) d.serverResponse = mw.outerHTML;
|
||||
} catch (e) { /* keep original response on parse failure */ }
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
||||
syncAfterSwap(evt.detail && evt.detail.xhr);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user