mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 17:29:29 +05:30
fix(flowchart): prevent preview-source duplication; v4.9.3
The flowchart preview pane accumulated raw Mermaid source when the user
fired several addNode mutations within the 250ms debounce window —
mermaid.run({nodes:[div]}) is async, so the previous render's
<div class="mermaid"> (still carrying the source text) sat in
.flowchart-preview-render when the next render cleared the target. The
first render's eventual element.innerHTML=svg landed on a detached node,
but the visible preview pane had a stack of stale <div class="mermaid">
elements carrying the source.
Fixed by switching renderFlowChartMermaid (src/renderer.js) to
replaceChildren() and adding a per-target WeakSet in-flight tracker so
the new render always starts from a clean slate and the previous render's
eventual innerHTML=svg is harmless on a detached node.
Added a second regression test that fires 7 mutations inside the debounce
with a renderMermaid mock that mimics mermaid.run's async innerHTML=svg
closure.
Amit Haridas
This commit is contained in:
+13
-2
@@ -2420,8 +2420,18 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const { renderFlowChartPanel } = require('./sidebar/flowchart-panel');
|
||||
// Reuse the existing Mermaid render path used by the preview pane
|
||||
// (src/renderer.js:1106-1142). Lazily loads mermaid on first use.
|
||||
//
|
||||
// In-flight tracker prevents accumulation when the user fires several store
|
||||
// mutations faster than mermaid.render can complete. Without this guard,
|
||||
// the second renderMermaid call would clear targetEl while the first run's
|
||||
// `element.innerHTML = svg` was still in flight — the user would briefly see
|
||||
// both the raw source (from the second call's not-yet-rendered <div>) and
|
||||
// the rendered SVG from a third call stacked into the preview pane. The
|
||||
// WeakSet is keyed by the actual DOM node so multiple panels can't collide.
|
||||
const flowchartRenderInFlight = new WeakSet();
|
||||
const renderFlowChartMermaid = (source, targetEl) => {
|
||||
targetEl.innerHTML = '';
|
||||
flowchartRenderInFlight.add(targetEl);
|
||||
targetEl.replaceChildren();
|
||||
const div = document.createElement('div');
|
||||
div.className = 'mermaid';
|
||||
div.textContent = source;
|
||||
@@ -2434,7 +2444,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
window.mermaid.initialize({ startOnLoad: false, theme, securityLevel: 'loose' });
|
||||
window.mermaid
|
||||
.run({ nodes: [div] })
|
||||
.catch((err) => console.warn('flowchart preview render failed:', err));
|
||||
.catch((err) => console.warn('flowchart preview render failed:', err))
|
||||
.finally(() => flowchartRenderInFlight.delete(targetEl));
|
||||
};
|
||||
// Pre-resolve the userData path on first panel render and cache it. The
|
||||
// flowchart panel's getUserDataPath() must be sync (it is interpolated into
|
||||
|
||||
Reference in New Issue
Block a user