fix(editor): refresh the icon preview on outside icon writes
A10: the editor's icon preview is painted by a closure nothing outside can reach, so a favicon fetched from Settings (or an import overwrite) updated the cards and left the open editor showing the old initials. soIconField publishes its painter; saveEntryIcon — the choke point for every icon write — routes through editorAbsorbChange like tag/folder already do. Also whitelists .toast and #busyOverlay in the editor's click-outside: both can sit under the cursor during a long operation, and clicking one counted as clicking away. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,11 @@ async function saveEntryIcon(entryId, dataUri) {
|
|||||||
try { const b = await r.json(); if (b && b.error) msg = b.error; }
|
try { const b = await r.json(); if (b && b.error) msg = b.error; }
|
||||||
catch (_) {}
|
catch (_) {}
|
||||||
toast('Icon NOT saved: ' + msg, 'error');
|
toast('Icon NOT saved: ' + msg, 'error');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// Choke point for every icon write (favicon backfill, upload, remove,
|
||||||
|
// import overwrite) — refresh the editor if it's open on this entry.
|
||||||
|
editorAbsorbChange(entryId, { icon: dataUri || '' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast('Icon save failed: ' + (e && e.message || e), 'error');
|
toast('Icon save failed: ' + (e && e.message || e), 'error');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3508,6 +3508,7 @@ function editorAbsorbChange(id, change) {
|
|||||||
const sel = $('#soFolder');
|
const sel = $('#soFolder');
|
||||||
if (sel) sel.value = change.folder;
|
if (sel) sel.value = change.folder;
|
||||||
}
|
}
|
||||||
|
if (change.icon !== undefined && soIconRepaint) soIconRepaint(change.icon || null);
|
||||||
if (change.tag && !soState.tags.includes(change.tag)) {
|
if (change.tag && !soState.tags.includes(change.tag)) {
|
||||||
soState.tags.push(change.tag);
|
soState.tags.push(change.tag);
|
||||||
soState.original.tags = soState.original.tags
|
soState.original.tags = soState.original.tags
|
||||||
@@ -4271,6 +4272,11 @@ function soEditableField(label, id, value) {
|
|||||||
// came from.
|
// came from.
|
||||||
const ICON_MAX_BYTES = 256 * 1024; // matches server-side cap (256 KB)
|
const ICON_MAX_BYTES = 256 * 1024; // matches server-side cap (256 KB)
|
||||||
|
|
||||||
|
// Repaint hook for the editor's icon preview, published by soIconField so an
|
||||||
|
// icon written from OUTSIDE the editor (favicon backfill, import) can refresh
|
||||||
|
// it. Cleared on close — the preview node dies with the panel.
|
||||||
|
let soIconRepaint = null;
|
||||||
|
|
||||||
function soIconField(entry) {
|
function soIconField(entry) {
|
||||||
const wrap = el('div', { class: 'slideover-field so-icon-field' });
|
const wrap = el('div', { class: 'slideover-field so-icon-field' });
|
||||||
const preview = el('div', { class: 'so-icon-preview' });
|
const preview = el('div', { class: 'so-icon-preview' });
|
||||||
@@ -4289,6 +4295,7 @@ function soIconField(entry) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
paintPreview(entry.icon_b64 || null);
|
paintPreview(entry.icon_b64 || null);
|
||||||
|
soIconRepaint = paintPreview;
|
||||||
|
|
||||||
const actions = el('div', { class: 'so-icon-actions' });
|
const actions = el('div', { class: 'so-icon-actions' });
|
||||||
|
|
||||||
@@ -4953,6 +4960,7 @@ function closeSlideOver() {
|
|||||||
const ae = document.activeElement;
|
const ae = document.activeElement;
|
||||||
if (ae && $('#slideover').contains(ae) && typeof ae.blur === 'function') ae.blur();
|
if (ae && $('#slideover').contains(ae) && typeof ae.blur === 'function') ae.blur();
|
||||||
$('#slideover').classList.remove('is-open');
|
$('#slideover').classList.remove('is-open');
|
||||||
|
soIconRepaint = null;
|
||||||
state.selectedId = null;
|
state.selectedId = null;
|
||||||
renderGrid();
|
renderGrid();
|
||||||
}
|
}
|
||||||
@@ -7332,6 +7340,10 @@ async function init() {
|
|||||||
// themselves what happens to the editor.
|
// themselves what happens to the editor.
|
||||||
if (e.target.closest('.batch-bar')) return;
|
if (e.target.closest('.batch-bar')) return;
|
||||||
if (e.target.closest('.content-header')) return;
|
if (e.target.closest('.content-header')) return;
|
||||||
|
// A toast or the busy spinner can land under the cursor mid-operation;
|
||||||
|
// clicking one must not count as "clicked away from the editor".
|
||||||
|
if (e.target.closest('.toast')) return;
|
||||||
|
if (e.target.closest('#busyOverlay')) return;
|
||||||
if (e.target.closest('.cols-menu')) return;
|
if (e.target.closest('.cols-menu')) return;
|
||||||
if (e.target.closest('.filters-menu')) return;
|
if (e.target.closest('.filters-menu')) return;
|
||||||
if (e.target.closest('.user-menu')) return;
|
if (e.target.closest('.user-menu')) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user