The markdown/YAML preview editors were never disposed when switching to a
non-editor file: dispose() was only called from inside the same plugin's
render(), so md→PDF/image/YAML overwrote the pane via innerHTML and leaked
the Toast UI instance, its DOM, and document-level resizer drag listeners.
Unsaved edits were also discarded silently on any file switch (including
arrow-key auto-preview), and debounced change handlers could resolve after
an editor was disposed and write the wrong file's dirty/hash state.
preview.js now owns editor lifecycle centrally in renderInline:
- disposeEditors() up front before replacing the pane (fixes the leak for
every md/yaml → anything switch).
- dirty guard: deliberate switches (click/Enter/menu) confirm before
discarding; auto previews (keyboard cursor walking the tree, opts.auto)
leave the dirty editor in place rather than nagging per keystroke;
re-selecting the file already being edited is a no-op.
- a renderSeq token bails late-arriving loads so a slow file can't paint
stale content into the pane after a newer selection.
- clearPreview() exposed and used by rescope (events.js) and popstate
(app.js) so those resets dispose the editor instead of leaking it.
- beforeunload warns when an editor is dirty at page exit.
preview-markdown.js: per-mount AbortController wired into the resizer
document listeners so dispose() detaches them even mid-drag; debounced
change/save/convert handlers guard `currentInstance !== instance` so a
disposed editor's callbacks can't corrupt the active file; expose
isDirty()/currentNode().
preview-yaml.js: track dirty/node state, guard the change handler the same
way, expose dispose()/isDirty()/currentNode().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>