mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-06 02:48:04 +00:00
fix(notes): remove orphaned image nodes when files deleted from controls
When an image file is removed from the Controls panel in the note editor, the corresponding image node in the TipTap editor was not being cleaned up. This left behind orphaned nodes that displayed a broken placeholder icon. - Sync editor.storage.files when files are removed from Controls - Walk the editor document and delete image nodes referencing removed files - Fix stale closure in image node view data event listener to read from live editor.storage.files instead of captured-at-creation reference - Dispatch data events to remaining image nodes to refresh their sources
This commit is contained in:
parent
b1d40f3409
commit
3cad442599
2 changed files with 43 additions and 5 deletions
|
|
@ -149,10 +149,10 @@ export const Image = Node.create<ImageOptions>({
|
|||
img.setAttribute('alt', node.attrs.alt || '');
|
||||
img.setAttribute('title', node.attrs.title || '');
|
||||
|
||||
img.addEventListener('data', (e) => {
|
||||
const files = e?.files || [];
|
||||
if (files && node.attrs.src.startsWith('data://')) {
|
||||
const file = editorFiles.find((f) => f.id === fileId);
|
||||
img.addEventListener('data', () => {
|
||||
const currentFiles = editor.storage?.files || [];
|
||||
if (node.attrs.src.startsWith('data://')) {
|
||||
const file = currentFiles.find((f) => f.id === fileId);
|
||||
if (file) {
|
||||
img.setAttribute('src', safeImageUrl(file.url || ''));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1438,7 +1438,45 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings,
|
|||
bind:show={showPanel}
|
||||
bind:selectedModelId
|
||||
bind:files
|
||||
onUpdate={() => {
|
||||
onUpdate={(updatedFiles) => {
|
||||
if (editor) {
|
||||
editor.storage.files = updatedFiles;
|
||||
|
||||
// Remove orphaned image nodes whose files were deleted
|
||||
const fileIds = new Set(updatedFiles.map((f) => f.id));
|
||||
const { state } = editor;
|
||||
const nodesToRemove = [];
|
||||
|
||||
state.doc.descendants((node, pos) => {
|
||||
if (node.type.name === 'image' && node.attrs.src?.startsWith('data://')) {
|
||||
const refId = node.attrs.src.replace('data://', '');
|
||||
if (!fileIds.has(refId)) {
|
||||
nodesToRemove.push({ from: pos, to: pos + node.nodeSize });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (nodesToRemove.length > 0) {
|
||||
// Delete in reverse order to preserve positions
|
||||
let tr = state.tr;
|
||||
for (let i = nodesToRemove.length - 1; i >= 0; i--) {
|
||||
tr = tr.delete(nodesToRemove[i].from, nodesToRemove[i].to);
|
||||
}
|
||||
editor.view.dispatch(tr);
|
||||
}
|
||||
|
||||
// Refresh remaining image nodes
|
||||
for (const file of updatedFiles) {
|
||||
if (file.type === 'image' || (file?.content_type ?? '').startsWith('image/')) {
|
||||
const img = document.getElementById(`image:${file.id}`);
|
||||
if (img) {
|
||||
img.dispatchEvent(new CustomEvent('data'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
note.data.files = updatedFiles.length > 0 ? updatedFiles : null;
|
||||
changeDebounceHandler();
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue