omni-viewer-core 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/viewers/csv/controller.d.ts +6 -1
- package/dist/viewers/csv/index.js +18 -6
- package/dist/viewers/diagram-controller.d.ts +7 -1
- package/dist/viewers/diagram-controller.js +2 -1
- package/dist/viewers/diagram.d.ts +6 -1
- package/dist/viewers/diagram.js +15 -4
- package/dist/viewers/latex/controller.d.ts +10 -1
- package/dist/viewers/latex/controller.js +2 -1
- package/dist/viewers/latex/index.d.ts +7 -1
- package/dist/viewers/latex/index.js +10 -3
- package/dist/viewers/markdown/controller.d.ts +6 -1
- package/dist/viewers/markdown/controller.js +2 -1
- package/dist/viewers/markdown/index.d.ts +6 -1
- package/dist/viewers/markdown/index.js +18 -5
- package/dist/viewers/mermaid/index.d.ts +4 -3
- package/dist/viewers/pdf/controller.d.ts +11 -1
- package/dist/viewers/pdf/controller.js +8 -1
- package/dist/viewers/pdf/index.js +8 -1
- package/dist/viewers/plantuml/index.d.ts +4 -3
- package/package.json +1 -1
|
@@ -115,7 +115,12 @@ export interface CsvController {
|
|
|
115
115
|
/** Whole document in original order as normalized CSV (save/writeback —
|
|
116
116
|
* ignores search and sort so hidden rows are never dropped). */
|
|
117
117
|
toDocumentCsv(): string;
|
|
118
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Mark the current edit depth as the saved point (clears dirty). Writes are
|
|
120
|
+
* async and the grid stays editable during one, so the caller must confirm
|
|
121
|
+
* that `toDocumentCsv()` still equals what it wrote before calling this —
|
|
122
|
+
* otherwise an edit made mid-write is recorded as being on disk.
|
|
123
|
+
*/
|
|
119
124
|
markSaved(): void;
|
|
120
125
|
/** Decoded source text (raw view). */
|
|
121
126
|
readonly rawText: string;
|
|
@@ -216,13 +216,25 @@ export async function mountCsvViewer(input, container, ctx, options = {}) {
|
|
|
216
216
|
saveAsBtn.title = t('common.noFileSave');
|
|
217
217
|
}
|
|
218
218
|
const dirtyBadge = el('span', 'omni-csv__dirty');
|
|
219
|
+
/**
|
|
220
|
+
* Clear dirty only if the document still equals the bytes that reached the
|
|
221
|
+
* file. The grid stays editable across the async write, so a cell changed
|
|
222
|
+
* mid-write would otherwise be recorded as saved — and a host trusting
|
|
223
|
+
* `isDirty()` would discard it on re-mount. When it differs, dirty is left
|
|
224
|
+
* set: the next save resolves it, and erring toward "unsaved" cannot lose
|
|
225
|
+
* work.
|
|
226
|
+
*/
|
|
227
|
+
function markSavedIfUnchanged(written) {
|
|
228
|
+
if (controller.toDocumentCsv() === written)
|
|
229
|
+
controller.markSaved();
|
|
230
|
+
}
|
|
219
231
|
async function saveDocument(service) {
|
|
220
232
|
try {
|
|
221
233
|
// Save covers the whole document in original order — never the
|
|
222
234
|
// filtered/sorted display result (docs §6).
|
|
223
|
-
const
|
|
224
|
-
await service.write(
|
|
225
|
-
|
|
235
|
+
const written = controller.toDocumentCsv();
|
|
236
|
+
await service.write(new TextEncoder().encode(written));
|
|
237
|
+
markSavedIfUnchanged(written);
|
|
226
238
|
showToast(t('common.savedToOriginal'));
|
|
227
239
|
}
|
|
228
240
|
catch (error) {
|
|
@@ -237,9 +249,9 @@ export async function mountCsvViewer(input, container, ctx, options = {}) {
|
|
|
237
249
|
const name = saveAsFileName(input.fileName, state.delimiter);
|
|
238
250
|
const mime = state.delimiter === '\t' ? 'text/tab-separated-values' : 'text/csv';
|
|
239
251
|
try {
|
|
240
|
-
const
|
|
241
|
-
await service.saveFile(name,
|
|
242
|
-
|
|
252
|
+
const written = controller.toDocumentCsv();
|
|
253
|
+
await service.saveFile(name, new TextEncoder().encode(written), mime);
|
|
254
|
+
markSavedIfUnchanged(written);
|
|
243
255
|
showToast(t('common.saved', { name }));
|
|
244
256
|
}
|
|
245
257
|
catch (error) {
|
|
@@ -19,8 +19,14 @@ export type DiagramAction = {
|
|
|
19
19
|
type: 'undo';
|
|
20
20
|
} | {
|
|
21
21
|
type: 'redo';
|
|
22
|
-
}
|
|
22
|
+
}
|
|
23
|
+
/** `source` is the text that actually reached the file. Writes are async and
|
|
24
|
+
* the editor stays live during one, so the current source at completion is
|
|
25
|
+
* not necessarily what was written (mirrors the latex/markdown controllers).
|
|
26
|
+
* Omitted = "what is in the editor now". */
|
|
27
|
+
| {
|
|
23
28
|
type: 'mark-saved';
|
|
29
|
+
source?: string;
|
|
24
30
|
};
|
|
25
31
|
export interface DiagramViewState {
|
|
26
32
|
mode: DiagramViewMode;
|
|
@@ -38,7 +38,8 @@ export function createDiagramController(text, theme) {
|
|
|
38
38
|
setSource(redo.pop());
|
|
39
39
|
}
|
|
40
40
|
else if (action.type === 'mark-saved') {
|
|
41
|
-
|
|
41
|
+
const savedSource = action.source ?? state.source;
|
|
42
|
+
state = { ...state, savedSource, dirty: state.source !== savedSource };
|
|
42
43
|
}
|
|
43
44
|
emit();
|
|
44
45
|
},
|
|
@@ -8,6 +8,11 @@ export type DiagramViewerContext = HostContext & {
|
|
|
8
8
|
writeback?: FileWritebackService;
|
|
9
9
|
save?: FileSaveService;
|
|
10
10
|
};
|
|
11
|
+
/** Diagram mount handle: `isDirty()` lets a host guard a re-mount against
|
|
12
|
+
* discarding unsaved source edits (DESIGN.md §3-②). */
|
|
13
|
+
export interface DiagramViewerHandle extends ViewerHandle {
|
|
14
|
+
isDirty(): boolean;
|
|
15
|
+
}
|
|
11
16
|
export interface DiagramMountOptions extends MountOptions {
|
|
12
17
|
renderMermaid?(id: string, source: string, theme?: DiagramTheme): Promise<string>;
|
|
13
18
|
renderPlantUml?(source: string, document: Document, theme?: DiagramTheme): SVGElement | string;
|
|
@@ -20,5 +25,5 @@ export interface DiagramMountOptions extends MountOptions {
|
|
|
20
25
|
export declare function mountDiagramViewer(kind: DiagramKind, parsed: {
|
|
21
26
|
source: string;
|
|
22
27
|
warnings: string[];
|
|
23
|
-
}, input: ViewerInput, container: HTMLElement, ctx: DiagramViewerContext, options?: DiagramMountOptions): Promise<
|
|
28
|
+
}, input: ViewerInput, container: HTMLElement, ctx: DiagramViewerContext, options?: DiagramMountOptions): Promise<DiagramViewerHandle>;
|
|
24
29
|
export declare function sanitizeSvg(svg: string, maxBytes?: number, maxNodes?: number): SVGElement;
|
package/dist/viewers/diagram.js
CHANGED
|
@@ -181,13 +181,20 @@ export async function mountDiagramViewer(kind, parsed, input, container, ctx, op
|
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
183
|
const saveSource = async () => {
|
|
184
|
-
|
|
184
|
+
// Snapshot once: the write is async and the editor stays live, so
|
|
185
|
+
// `controller.state.source` after the await may already be a later edit
|
|
186
|
+
// than the bytes that reached the file.
|
|
187
|
+
const saved = controller.state.source;
|
|
188
|
+
const bytes = new TextEncoder().encode(saved);
|
|
185
189
|
if (ctx.writeback) {
|
|
190
|
+
// The caption is the dirty indicator: leave syncState's verdict alone
|
|
191
|
+
// when an edit arrived mid-write and the source is still unsaved.
|
|
186
192
|
try {
|
|
187
193
|
await ctx.writeback.write(bytes);
|
|
188
|
-
controller.dispatch({ type: 'mark-saved' });
|
|
194
|
+
controller.dispatch({ type: 'mark-saved', source: saved });
|
|
189
195
|
setStatus('common.savedToOriginal', 'valid');
|
|
190
|
-
|
|
196
|
+
if (!controller.state.dirty)
|
|
197
|
+
sourceCaption.textContent = t('common.savedToOriginal');
|
|
191
198
|
}
|
|
192
199
|
catch (error) {
|
|
193
200
|
ctx.logger.log('error', `diagram save failed: ${String(error)}`);
|
|
@@ -296,7 +303,11 @@ export async function mountDiagramViewer(kind, parsed, input, container, ctx, op
|
|
|
296
303
|
container.classList.remove(VIEWER_ROOT_CLASS, `omni-viewer--${kind}`);
|
|
297
304
|
else
|
|
298
305
|
root.replaceChildren();
|
|
299
|
-
}
|
|
306
|
+
},
|
|
307
|
+
// The controller, not the textarea: `mark-saved` (a successful writeback)
|
|
308
|
+
// is the only thing that clears it, so a failed save or a Save As copy
|
|
309
|
+
// stays dirty.
|
|
310
|
+
isDirty: () => controller.state.dirty
|
|
300
311
|
};
|
|
301
312
|
}
|
|
302
313
|
let nextId = 1;
|
|
@@ -12,8 +12,17 @@ export type LatexAction = {
|
|
|
12
12
|
type: 'undo';
|
|
13
13
|
} | {
|
|
14
14
|
type: 'redo';
|
|
15
|
-
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `source` is the text that actually reached the file. Writes are async and
|
|
18
|
+
* the editor stays live during one, so the current source at completion is
|
|
19
|
+
* not necessarily what was written — omitting it would mark an edit made
|
|
20
|
+
* mid-write as saved and let a host discard it. Omitted = "what is in the
|
|
21
|
+
* editor now", which is only correct for synchronous saves.
|
|
22
|
+
*/
|
|
23
|
+
| {
|
|
16
24
|
type: 'mark-saved';
|
|
25
|
+
source?: string;
|
|
17
26
|
};
|
|
18
27
|
export interface LatexViewState {
|
|
19
28
|
mode: LatexViewMode;
|
|
@@ -52,7 +52,8 @@ export function createLatexController(text, mode = 'preview') {
|
|
|
52
52
|
setSource(redo.pop());
|
|
53
53
|
}
|
|
54
54
|
else if (action.type === 'mark-saved') {
|
|
55
|
-
|
|
55
|
+
const savedSource = action.source ?? state.source;
|
|
56
|
+
state = { ...state, savedSource, dirty: state.source !== savedSource };
|
|
56
57
|
}
|
|
57
58
|
emit();
|
|
58
59
|
},
|
|
@@ -28,6 +28,12 @@ export interface LatexViewerDeps {
|
|
|
28
28
|
math?: MathRenderer;
|
|
29
29
|
createDOMPurify?(window: Window): DomPurify;
|
|
30
30
|
}
|
|
31
|
+
/** LaTeX mount handle: dirty inspection lets hosts guard a re-mount (file
|
|
32
|
+
* change, refresh) against discarding unsaved edits, without reaching into the
|
|
33
|
+
* viewer's DOM (csv/image/pdf expose the same method). */
|
|
34
|
+
export interface LatexViewerHandle extends ViewerHandle {
|
|
35
|
+
isDirty(): boolean;
|
|
36
|
+
}
|
|
31
37
|
export interface LatexMountOptions extends MountOptions {
|
|
32
38
|
/** Forwarded to the parser (limits, cancellation). */
|
|
33
39
|
parse?: LatexParseOptions;
|
|
@@ -57,7 +63,7 @@ export declare const LATEX_VIEWER_META: {
|
|
|
57
63
|
optionalServices: readonly ["clipboard", "navigation", "writeback", "save"];
|
|
58
64
|
inputOwnership: "borrows";
|
|
59
65
|
};
|
|
60
|
-
export declare function mountLatexViewer(input: ViewerInput, container: HTMLElement, ctx: LatexViewerContext, options?: LatexMountOptions): Promise<
|
|
66
|
+
export declare function mountLatexViewer(input: ViewerInput, container: HTMLElement, ctx: LatexViewerContext, options?: LatexMountOptions): Promise<LatexViewerHandle>;
|
|
61
67
|
/**
|
|
62
68
|
* Commands that produce no glyphs but that math engines do not implement.
|
|
63
69
|
* Collecting the document's own macros (L18) means a text-mode macro can now
|
|
@@ -543,11 +543,15 @@ export async function mountLatexViewer(input, container, ctx, options = {}) {
|
|
|
543
543
|
}
|
|
544
544
|
};
|
|
545
545
|
const saveSource = async () => {
|
|
546
|
-
|
|
546
|
+
// Snapshot once: the write is async and the editor stays live, so
|
|
547
|
+
// `controller.state.source` after the await may already be a later edit
|
|
548
|
+
// than the bytes that reached the file.
|
|
549
|
+
const saved = controller.state.source;
|
|
550
|
+
const bytes = new TextEncoder().encode(saved);
|
|
547
551
|
if (ctx.writeback) {
|
|
548
552
|
try {
|
|
549
553
|
await ctx.writeback.write(bytes);
|
|
550
|
-
controller.dispatch({ type: 'mark-saved' });
|
|
554
|
+
controller.dispatch({ type: 'mark-saved', source: saved });
|
|
551
555
|
setStatus('common.savedToOriginal', 'valid');
|
|
552
556
|
}
|
|
553
557
|
catch (error) {
|
|
@@ -641,7 +645,10 @@ export async function mountLatexViewer(input, container, ctx, options = {}) {
|
|
|
641
645
|
teardown();
|
|
642
646
|
throw new MountAbortedError();
|
|
643
647
|
}
|
|
644
|
-
|
|
648
|
+
// Reads the controller rather than the textarea: the source of truth for
|
|
649
|
+
// "unsaved" is `source !== savedSource`, which undo restores and `mark-saved`
|
|
650
|
+
// clears. A Save As copy never dispatches `mark-saved`, so it stays dirty.
|
|
651
|
+
return { dispose: teardown, isDirty: () => controller.state.dirty };
|
|
645
652
|
}
|
|
646
653
|
function errorText(error, fallback) {
|
|
647
654
|
return error instanceof Error ? error.message : fallback;
|
|
@@ -18,8 +18,13 @@ export type MarkdownAction = {
|
|
|
18
18
|
type: 'undo';
|
|
19
19
|
} | {
|
|
20
20
|
type: 'redo';
|
|
21
|
-
}
|
|
21
|
+
}
|
|
22
|
+
/** `source` is the text that actually reached the file. Writes are async and
|
|
23
|
+
* the editor stays live during one, so the current source at completion is
|
|
24
|
+
* not necessarily what was written. Omitted = "what is in the editor now". */
|
|
25
|
+
| {
|
|
22
26
|
type: 'mark-saved';
|
|
27
|
+
source?: string;
|
|
23
28
|
} | {
|
|
24
29
|
type: 'copy-code';
|
|
25
30
|
code: string;
|
|
@@ -52,7 +52,8 @@ export function createMarkdownController(text, _headings) {
|
|
|
52
52
|
setSource(redo.pop());
|
|
53
53
|
}
|
|
54
54
|
else if (action.type === 'mark-saved') {
|
|
55
|
-
|
|
55
|
+
const savedSource = action.source ?? state.source;
|
|
56
|
+
state = { ...state, savedSource, dirty: state.source !== savedSource };
|
|
56
57
|
}
|
|
57
58
|
emit();
|
|
58
59
|
},
|
|
@@ -56,6 +56,11 @@ export type MarkdownViewerContext = HostContext & {
|
|
|
56
56
|
writeback?: FileWritebackService;
|
|
57
57
|
save?: FileSaveService;
|
|
58
58
|
};
|
|
59
|
+
/** Markdown mount handle: `isDirty()` lets a host guard a re-mount against
|
|
60
|
+
* discarding unsaved source edits (DESIGN.md §3-②). */
|
|
61
|
+
export interface MarkdownViewerHandle extends ViewerHandle {
|
|
62
|
+
isDirty(): boolean;
|
|
63
|
+
}
|
|
59
64
|
export interface MarkdownMountOptions extends MountOptions {
|
|
60
65
|
limits?: ResourceLimits;
|
|
61
66
|
markdownLimits?: MarkdownParseOptions['markdownLimits'];
|
|
@@ -64,4 +69,4 @@ export interface MarkdownMountOptions extends MountOptions {
|
|
|
64
69
|
* wants it configurable should drive this from its own settings. */
|
|
65
70
|
scrollSync?: boolean;
|
|
66
71
|
}
|
|
67
|
-
export declare function mountMarkdownViewer(input: ViewerInput, container: HTMLElement, ctx: MarkdownViewerContext, deps: MarkdownViewerDeps, options?: MarkdownMountOptions): Promise<
|
|
72
|
+
export declare function mountMarkdownViewer(input: ViewerInput, container: HTMLElement, ctx: MarkdownViewerContext, deps: MarkdownViewerDeps, options?: MarkdownMountOptions): Promise<MarkdownViewerHandle>;
|
|
@@ -546,13 +546,20 @@ export async function mountMarkdownViewer(input, container, ctx, deps, options =
|
|
|
546
546
|
}
|
|
547
547
|
};
|
|
548
548
|
const saveSource = async () => {
|
|
549
|
-
|
|
549
|
+
// Snapshot once: the write is async and the editor stays live, so
|
|
550
|
+
// `controller.state.source` after the await may already be a later edit
|
|
551
|
+
// than the bytes that reached the file.
|
|
552
|
+
const saved = controller.state.source;
|
|
553
|
+
const bytes = new TextEncoder().encode(saved);
|
|
550
554
|
if (ctx.writeback) {
|
|
555
|
+
// The caption is the dirty indicator: leave syncState's verdict alone
|
|
556
|
+
// when an edit arrived mid-write and the source is still unsaved.
|
|
551
557
|
try {
|
|
552
558
|
await ctx.writeback.write(bytes);
|
|
553
|
-
controller.dispatch({ type: 'mark-saved' });
|
|
559
|
+
controller.dispatch({ type: 'mark-saved', source: saved });
|
|
554
560
|
setStatus('common.savedToOriginal', 'valid');
|
|
555
|
-
|
|
561
|
+
if (!controller.state.dirty)
|
|
562
|
+
sourceCaption.textContent = t('common.savedToOriginal');
|
|
556
563
|
}
|
|
557
564
|
catch (error) {
|
|
558
565
|
ctx.logger.log('error', `markdown save failed: ${String(error)}`);
|
|
@@ -739,9 +746,15 @@ export async function mountMarkdownViewer(input, container, ctx, deps, options =
|
|
|
739
746
|
releaseAssets();
|
|
740
747
|
throw new MountAbortedError();
|
|
741
748
|
}
|
|
742
|
-
return {
|
|
749
|
+
return {
|
|
750
|
+
dispose() { disposed = true; renderVersion++; if (liveTimer)
|
|
743
751
|
clearTimeout(liveTimer); releaseAssets(); for (const dispose of disposers.splice(0))
|
|
744
|
-
dispose(); shell.remove(); }
|
|
752
|
+
dispose(); shell.remove(); },
|
|
753
|
+
// The controller, not the textarea: `mark-saved` (a successful writeback)
|
|
754
|
+
// is the only thing that clears it, so a failed save or a download copy
|
|
755
|
+
// stays dirty.
|
|
756
|
+
isDirty: () => controller.state.dirty
|
|
757
|
+
};
|
|
745
758
|
}
|
|
746
759
|
/** Flat text for an outline entry. Rendered math contributes twice to
|
|
747
760
|
* `textContent` — KaTeX emits a visual copy alongside a MathML twin — so the
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { diagramViewerCss, type DiagramMountOptions, type DiagramViewerContext } from '../diagram.js';
|
|
2
|
-
import type {
|
|
1
|
+
import { diagramViewerCss, type DiagramMountOptions, type DiagramViewerContext, type DiagramViewerHandle } from '../diagram.js';
|
|
2
|
+
import type { ViewerInput } from '../types.js';
|
|
3
3
|
export { parseMermaid } from '../../parsers/mermaid/index.js';
|
|
4
4
|
export { diagramViewerCss as mermaidViewerCss };
|
|
5
5
|
export type MermaidViewerContext = DiagramViewerContext;
|
|
6
6
|
export type MermaidMountOptions = DiagramMountOptions;
|
|
7
|
+
export type MermaidViewerHandle = DiagramViewerHandle;
|
|
7
8
|
export declare const MERMAID_VIEWER_META: {
|
|
8
9
|
id: string;
|
|
9
10
|
displayNameKey: string;
|
|
@@ -13,4 +14,4 @@ export declare const MERMAID_VIEWER_META: {
|
|
|
13
14
|
optionalServices: readonly ["clipboard", "writeback", "save"];
|
|
14
15
|
inputOwnership: "borrows";
|
|
15
16
|
};
|
|
16
|
-
export declare function mountMermaidViewer(input: ViewerInput, container: HTMLElement, ctx: MermaidViewerContext, options?: MermaidMountOptions): Promise<
|
|
17
|
+
export declare function mountMermaidViewer(input: ViewerInput, container: HTMLElement, ctx: MermaidViewerContext, options?: MermaidMountOptions): Promise<MermaidViewerHandle>;
|
|
@@ -123,8 +123,18 @@ export type PdfAction = {
|
|
|
123
123
|
type: 'undo';
|
|
124
124
|
} | {
|
|
125
125
|
type: 'redo';
|
|
126
|
-
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* `savedState` is the page order and annotations that actually reached the
|
|
129
|
+
* file. Builds and writes are async and the document stays editable during
|
|
130
|
+
* one, so the state at completion is not necessarily what was written —
|
|
131
|
+
* omitting it would mark an edit made mid-save as saved and let a host
|
|
132
|
+
* discard it. Omitted = "the current state", which is only correct for a
|
|
133
|
+
* synchronous save.
|
|
134
|
+
*/
|
|
135
|
+
| {
|
|
127
136
|
type: 'mark-saved';
|
|
137
|
+
savedState?: Pick<PdfViewState, 'pageOrder' | 'annotations'>;
|
|
128
138
|
};
|
|
129
139
|
export interface PdfController {
|
|
130
140
|
readonly state: PdfViewState;
|
|
@@ -217,7 +217,14 @@ export function createPdfController(pageCount, seed, options = {}) {
|
|
|
217
217
|
selectedAnnotationId = action.id;
|
|
218
218
|
break;
|
|
219
219
|
case 'mark-saved':
|
|
220
|
-
|
|
220
|
+
// Same shape as `signature()` so an unchanged document still
|
|
221
|
+
// compares equal (state copies preserve key order).
|
|
222
|
+
savedSignature = action.savedState
|
|
223
|
+
? JSON.stringify({
|
|
224
|
+
pageOrder: action.savedState.pageOrder,
|
|
225
|
+
annotations: action.savedState.annotations
|
|
226
|
+
})
|
|
227
|
+
: signature();
|
|
221
228
|
break;
|
|
222
229
|
}
|
|
223
230
|
if (before && beforeSignature !== signature()) {
|
|
@@ -1757,13 +1757,20 @@ export async function mountPdfViewer(input, container, ctx, deps, options = {})
|
|
|
1757
1757
|
async function save() {
|
|
1758
1758
|
if (!ctx.writeback || saveBtn.disabled)
|
|
1759
1759
|
return;
|
|
1760
|
+
// Pin what is being written before the build starts: only the save/merge
|
|
1761
|
+
// buttons are disabled while an operation runs, so pages and annotations
|
|
1762
|
+
// can still change across the await. Taking the state at completion would
|
|
1763
|
+
// mark those changes as saved and let a host discard them on re-mount.
|
|
1764
|
+
// `stateForSave()` only rasterizes text for output, so the pre-raster
|
|
1765
|
+
// state is what this write represents.
|
|
1766
|
+
const { pageOrder, annotations } = controller.state;
|
|
1760
1767
|
const result = await runOperation('save', async (control) => {
|
|
1761
1768
|
const data = await buildOutput(stateForSave(), control);
|
|
1762
1769
|
await ctx.writeback.write(data);
|
|
1763
1770
|
});
|
|
1764
1771
|
if (result.status === 'succeeded') {
|
|
1765
1772
|
mergedSinceSave = false;
|
|
1766
|
-
controller.dispatch({ type: 'mark-saved' });
|
|
1773
|
+
controller.dispatch({ type: 'mark-saved', savedState: { pageOrder, annotations } });
|
|
1767
1774
|
refreshChrome();
|
|
1768
1775
|
status.textContent = t('common.savedToOriginal');
|
|
1769
1776
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { diagramViewerCss, type DiagramMountOptions, type DiagramViewerContext } from '../diagram.js';
|
|
2
|
-
import type {
|
|
1
|
+
import { diagramViewerCss, type DiagramMountOptions, type DiagramViewerContext, type DiagramViewerHandle } from '../diagram.js';
|
|
2
|
+
import type { ViewerInput } from '../types.js';
|
|
3
3
|
export { parsePlantUml } from '../../parsers/plantuml/index.js';
|
|
4
4
|
export { diagramViewerCss as plantumlViewerCss };
|
|
5
5
|
export type PlantUmlViewerContext = DiagramViewerContext;
|
|
6
6
|
export type PlantUmlMountOptions = DiagramMountOptions;
|
|
7
|
+
export type PlantUmlViewerHandle = DiagramViewerHandle;
|
|
7
8
|
export declare const PLANTUML_VIEWER_META: {
|
|
8
9
|
id: string;
|
|
9
10
|
displayNameKey: string;
|
|
@@ -13,4 +14,4 @@ export declare const PLANTUML_VIEWER_META: {
|
|
|
13
14
|
optionalServices: readonly ["clipboard", "writeback", "save"];
|
|
14
15
|
inputOwnership: "borrows";
|
|
15
16
|
};
|
|
16
|
-
export declare function mountPlantUmlViewer(input: ViewerInput, container: HTMLElement, ctx: PlantUmlViewerContext, options?: PlantUmlMountOptions): Promise<
|
|
17
|
+
export declare function mountPlantUmlViewer(input: ViewerInput, container: HTMLElement, ctx: PlantUmlViewerContext, options?: PlantUmlMountOptions): Promise<PlantUmlViewerHandle>;
|