@file-viewer/renderer-drawing 2.1.2 → 2.1.4
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/diagram.d.ts +3 -2
- package/dist/diagram.js +12 -10
- package/dist/drawing.js +31 -29
- package/package.json +2 -2
package/dist/diagram.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FileViewerDrawingOptions, type FileViewerOptions, type FileViewerThemeMode } from '@file-viewer/core';
|
|
2
2
|
export type DiagramKind = 'mermaid' | 'plantuml';
|
|
3
3
|
export interface DiagramController {
|
|
4
4
|
setZoom: (scale: number) => void;
|
|
@@ -13,6 +13,7 @@ interface RenderDiagramParams {
|
|
|
13
13
|
kind: DiagramKind;
|
|
14
14
|
options?: FileViewerDrawingOptions;
|
|
15
15
|
theme?: FileViewerThemeMode;
|
|
16
|
+
viewerOptions?: FileViewerOptions;
|
|
16
17
|
}
|
|
17
|
-
export declare const renderDiagram: ({ documentRef, text, target, kind, options, theme }: RenderDiagramParams) => Promise<DiagramController>;
|
|
18
|
+
export declare const renderDiagram: ({ documentRef, text, target, kind, options, theme, viewerOptions }: RenderDiagramParams) => Promise<DiagramController>;
|
|
18
19
|
export {};
|
package/dist/diagram.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createFileViewerTranslator } from '@file-viewer/core';
|
|
1
2
|
import Panzoom, {} from '@panzoom/panzoom';
|
|
2
3
|
const getOwnerWindow = (documentRef) => {
|
|
3
4
|
return documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
|
|
@@ -28,11 +29,11 @@ const normalizePlantumlServer = (documentRef, value) => {
|
|
|
28
29
|
return normalized;
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
const sanitizeSvg = (documentRef, svg) => {
|
|
32
|
+
const sanitizeSvg = (documentRef, svg, t) => {
|
|
32
33
|
const parsed = new DOMParser().parseFromString(svg, 'image/svg+xml');
|
|
33
34
|
const parseError = parsed.querySelector('parsererror');
|
|
34
35
|
if (parseError) {
|
|
35
|
-
throw new Error(parseError.textContent || '
|
|
36
|
+
throw new Error(parseError.textContent || t('drawing.error.svgParseFailed'));
|
|
36
37
|
}
|
|
37
38
|
parsed.querySelectorAll('script,iframe,object,embed').forEach(node => node.remove());
|
|
38
39
|
parsed.querySelectorAll('*').forEach(node => {
|
|
@@ -45,7 +46,7 @@ const sanitizeSvg = (documentRef, svg) => {
|
|
|
45
46
|
const svgNode = parsed.documentElement;
|
|
46
47
|
return documentRef.importNode(svgNode, true);
|
|
47
48
|
};
|
|
48
|
-
const renderMermaidSvg = async (documentRef, text, theme) => {
|
|
49
|
+
const renderMermaidSvg = async (documentRef, text, theme, t) => {
|
|
49
50
|
const mermaidModule = await import('mermaid');
|
|
50
51
|
const mermaid = mermaidModule.default;
|
|
51
52
|
const id = `file-viewer-mermaid-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -55,7 +56,7 @@ const renderMermaidSvg = async (documentRef, text, theme) => {
|
|
|
55
56
|
theme: isDarkTheme(documentRef, theme) ? 'dark' : 'default'
|
|
56
57
|
});
|
|
57
58
|
const rendered = await mermaid.render(id, text);
|
|
58
|
-
return sanitizeSvg(documentRef, rendered.svg);
|
|
59
|
+
return sanitizeSvg(documentRef, rendered.svg, t);
|
|
59
60
|
};
|
|
60
61
|
const appendSvgText = (documentRef, parent, text, x, dy, weight = '500') => {
|
|
61
62
|
const line = documentRef.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
|
@@ -121,7 +122,7 @@ const renderPlantumlFallbackSvg = (documentRef, text, message) => {
|
|
|
121
122
|
svg.appendChild(source);
|
|
122
123
|
return svg;
|
|
123
124
|
};
|
|
124
|
-
const renderPlantumlSvg = async (documentRef, text, options) => {
|
|
125
|
+
const renderPlantumlSvg = async (documentRef, text, options, t) => {
|
|
125
126
|
if (!options?.plantumlServerUrl) {
|
|
126
127
|
return renderPlantumlFallbackSvg(documentRef, text, 'Offline mode is active. Configure options.drawing.plantumlServerUrl for server-rendered PlantUML SVG.');
|
|
127
128
|
}
|
|
@@ -135,9 +136,9 @@ const renderPlantumlSvg = async (documentRef, text, options) => {
|
|
|
135
136
|
signal: controller.signal
|
|
136
137
|
});
|
|
137
138
|
if (!response.ok) {
|
|
138
|
-
throw new Error(
|
|
139
|
+
throw new Error(t('drawing.error.plantumlRenderFailed', { status: response.status }));
|
|
139
140
|
}
|
|
140
|
-
return sanitizeSvg(documentRef, await response.text());
|
|
141
|
+
return sanitizeSvg(documentRef, await response.text(), t);
|
|
141
142
|
}
|
|
142
143
|
catch (error) {
|
|
143
144
|
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
@@ -162,14 +163,15 @@ const applySvgDefaults = (svg, kind) => {
|
|
|
162
163
|
svg.setAttribute('height', String(Math.ceil(svg.viewBox.baseVal.height)));
|
|
163
164
|
}
|
|
164
165
|
};
|
|
165
|
-
export const renderDiagram = async ({ documentRef, text, target, kind, options, theme }) => {
|
|
166
|
+
export const renderDiagram = async ({ documentRef, text, target, kind, options, theme, viewerOptions }) => {
|
|
167
|
+
const t = createFileViewerTranslator(viewerOptions);
|
|
166
168
|
const shell = createElement(documentRef, 'div', 'drawing-diagram-shell');
|
|
167
169
|
const panTarget = createElement(documentRef, 'div', 'drawing-diagram-pan');
|
|
168
170
|
shell.appendChild(panTarget);
|
|
169
171
|
target.replaceChildren(shell);
|
|
170
172
|
const svg = kind === 'mermaid'
|
|
171
|
-
? await renderMermaidSvg(documentRef, text, theme)
|
|
172
|
-
: await renderPlantumlSvg(documentRef, text, options);
|
|
173
|
+
? await renderMermaidSvg(documentRef, text, theme, t)
|
|
174
|
+
: await renderPlantumlSvg(documentRef, text, options, t);
|
|
173
175
|
applySvgDefaults(svg, kind);
|
|
174
176
|
panTarget.replaceChildren(svg);
|
|
175
177
|
const panzoom = Panzoom(panTarget, {
|
package/dist/drawing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, readFileViewerText, resolveFileViewerDrawioViewerScriptUrl, waitForFileViewerNextPaint, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
1
|
+
import { createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, readFileViewerText, resolveFileViewerDrawioViewerScriptUrl, waitForFileViewerNextPaint, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
2
2
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
3
3
|
const EXCALIDRAW_OFFICIAL_TIMEOUT = 6000;
|
|
4
4
|
const DRAWIO_OFFICIAL_TIMEOUT = 6000;
|
|
@@ -139,7 +139,7 @@ const deleteDiagramsViewerPromise = (documentRef, scriptUrl) => {
|
|
|
139
139
|
diagramsViewerPromises.delete(documentRef);
|
|
140
140
|
}
|
|
141
141
|
};
|
|
142
|
-
const loadDiagramsViewer = (documentRef, scriptUrl) => {
|
|
142
|
+
const loadDiagramsViewer = (documentRef, scriptUrl, t) => {
|
|
143
143
|
const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
|
|
144
144
|
if (ownerWindow?.GraphViewer) {
|
|
145
145
|
return Promise.resolve();
|
|
@@ -155,14 +155,14 @@ const loadDiagramsViewer = (documentRef, scriptUrl) => {
|
|
|
155
155
|
.find(script => script.src === scriptUrl);
|
|
156
156
|
if (existed) {
|
|
157
157
|
existed.addEventListener('load', () => resolve(), { once: true });
|
|
158
|
-
existed.addEventListener('error', () => reject(new Error('
|
|
158
|
+
existed.addEventListener('error', () => reject(new Error(t('drawing.error.viewerLoadFailed'))), { once: true });
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
const script = documentRef.createElement('script');
|
|
162
162
|
script.src = scriptUrl;
|
|
163
163
|
script.async = true;
|
|
164
164
|
script.onload = () => resolve();
|
|
165
|
-
script.onerror = () => reject(new Error('
|
|
165
|
+
script.onerror = () => reject(new Error(t('drawing.error.viewerLoadFailed')));
|
|
166
166
|
documentRef.head.appendChild(script);
|
|
167
167
|
});
|
|
168
168
|
promiseMap.set(scriptUrl, nextPromise);
|
|
@@ -446,16 +446,16 @@ const renderOfficialExcalidraw = async (payload, elements, target) => {
|
|
|
446
446
|
setTimeout(restoreConsole, 3000);
|
|
447
447
|
}
|
|
448
448
|
};
|
|
449
|
-
const renderExcalidraw = async (documentRef, text, target) => {
|
|
449
|
+
const renderExcalidraw = async (documentRef, text, target, t) => {
|
|
450
450
|
const payload = JSON.parse(text);
|
|
451
451
|
const elements = Array.isArray(payload.elements)
|
|
452
452
|
? payload.elements.filter((element) => !element.isDeleted)
|
|
453
453
|
: [];
|
|
454
454
|
if (!elements.length) {
|
|
455
|
-
throw new Error('
|
|
455
|
+
throw new Error(t('drawing.error.excalidrawEmpty'));
|
|
456
456
|
}
|
|
457
457
|
try {
|
|
458
|
-
await runWithTimeout(renderOfficialExcalidraw(payload, elements, target), EXCALIDRAW_OFFICIAL_TIMEOUT, '
|
|
458
|
+
await runWithTimeout(renderOfficialExcalidraw(payload, elements, target), EXCALIDRAW_OFFICIAL_TIMEOUT, t('drawing.error.excalidrawTimeout'));
|
|
459
459
|
}
|
|
460
460
|
catch (error) {
|
|
461
461
|
console.warn(error);
|
|
@@ -550,17 +550,17 @@ const appendDrawioWrappedText = (documentRef, svg, text, x, y, width, height, fo
|
|
|
550
550
|
});
|
|
551
551
|
svg.appendChild(textNode);
|
|
552
552
|
};
|
|
553
|
-
const renderDrawioFallback = (documentRef, text, target) => {
|
|
553
|
+
const renderDrawioFallback = (documentRef, text, target, t) => {
|
|
554
554
|
const parser = new DOMParser();
|
|
555
555
|
const parsed = parser.parseFromString(text, 'text/xml');
|
|
556
556
|
const parseError = parsed.querySelector('parsererror');
|
|
557
557
|
if (parseError) {
|
|
558
|
-
throw new Error(
|
|
558
|
+
throw new Error(t('drawing.error.drawioParseFailed', { message: parseError.textContent || 'invalid xml' }));
|
|
559
559
|
}
|
|
560
560
|
const firstDiagram = parsed.querySelector('diagram');
|
|
561
561
|
const graphModel = firstDiagram?.querySelector('mxGraphModel') || parsed.querySelector('mxGraphModel');
|
|
562
562
|
if (!graphModel) {
|
|
563
|
-
throw new Error('
|
|
563
|
+
throw new Error(t('drawing.error.drawioNoModel'));
|
|
564
564
|
}
|
|
565
565
|
const cells = Array.from(graphModel.querySelectorAll('mxCell'));
|
|
566
566
|
const vertices = cells
|
|
@@ -574,7 +574,7 @@ const renderDrawioFallback = (documentRef, text, target) => {
|
|
|
574
574
|
}))
|
|
575
575
|
.filter(item => item.id && item.geometry);
|
|
576
576
|
if (!vertices.length) {
|
|
577
|
-
throw new Error('
|
|
577
|
+
throw new Error(t('drawing.error.drawioNoElements'));
|
|
578
578
|
}
|
|
579
579
|
const vertexById = new Map(vertices.map(vertex => [vertex.id, vertex]));
|
|
580
580
|
const allX = vertices.flatMap(vertex => [vertex.geometry.x, vertex.geometry.x + vertex.geometry.width]);
|
|
@@ -716,9 +716,9 @@ const renderDrawioFallback = (documentRef, text, target) => {
|
|
|
716
716
|
}
|
|
717
717
|
appendRenderedSvg(target, svg, 'rough');
|
|
718
718
|
};
|
|
719
|
-
const renderOfficialDrawio = async (documentRef, text, target, scriptUrl) => {
|
|
719
|
+
const renderOfficialDrawio = async (documentRef, text, target, scriptUrl, t) => {
|
|
720
720
|
const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
|
|
721
|
-
await loadDiagramsViewer(documentRef, scriptUrl);
|
|
721
|
+
await loadDiagramsViewer(documentRef, scriptUrl, t);
|
|
722
722
|
await waitForFileViewerNextPaint(ownerWindow);
|
|
723
723
|
const host = createElement(documentRef, 'div', 'mxgraph drawing-mxgraph');
|
|
724
724
|
host.setAttribute('data-mxgraph', JSON.stringify({
|
|
@@ -736,31 +736,32 @@ const renderOfficialDrawio = async (documentRef, text, target, scriptUrl) => {
|
|
|
736
736
|
}));
|
|
737
737
|
target.appendChild(host);
|
|
738
738
|
if (!ownerWindow?.GraphViewer) {
|
|
739
|
-
throw new Error('
|
|
739
|
+
throw new Error(t('drawing.error.viewerInitFailed'));
|
|
740
740
|
}
|
|
741
741
|
ownerWindow.GraphViewer.createViewerForElement(host);
|
|
742
742
|
markRendered(target, 'official');
|
|
743
743
|
};
|
|
744
|
-
const renderDrawio = async (documentRef, text, target, options) => {
|
|
744
|
+
const renderDrawio = async (documentRef, text, target, options, t) => {
|
|
745
745
|
if (options?.preferOfficial === false) {
|
|
746
|
-
renderDrawioFallback(documentRef, text, target);
|
|
746
|
+
renderDrawioFallback(documentRef, text, target, t);
|
|
747
747
|
return;
|
|
748
748
|
}
|
|
749
749
|
const scriptUrl = resolveDrawingViewerScriptUrl(options, documentRef);
|
|
750
750
|
try {
|
|
751
|
-
await runWithTimeout(renderOfficialDrawio(documentRef, text, target, scriptUrl), DRAWIO_OFFICIAL_TIMEOUT, '
|
|
751
|
+
await runWithTimeout(renderOfficialDrawio(documentRef, text, target, scriptUrl, t), DRAWIO_OFFICIAL_TIMEOUT, t('drawing.error.drawioTimeout'));
|
|
752
752
|
}
|
|
753
753
|
catch (error) {
|
|
754
754
|
console.warn(error);
|
|
755
755
|
deleteDiagramsViewerPromise(documentRef, scriptUrl);
|
|
756
756
|
delete target.dataset.drawingRendered;
|
|
757
757
|
target.replaceChildren();
|
|
758
|
-
renderDrawioFallback(documentRef, text, target);
|
|
758
|
+
renderDrawioFallback(documentRef, text, target, t);
|
|
759
759
|
}
|
|
760
760
|
};
|
|
761
761
|
export default async function renderDrawing(buffer, target, type = 'drawio', context) {
|
|
762
762
|
const documentRef = target.ownerDocument || document;
|
|
763
763
|
const kind = normalizeDrawingType(type);
|
|
764
|
+
const t = createFileViewerTranslator(context?.options);
|
|
764
765
|
const zoomEmitter = createFileViewerZoomChangeEmitter();
|
|
765
766
|
let status = 'loading';
|
|
766
767
|
let errorMessage = '';
|
|
@@ -772,23 +773,23 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
|
|
|
772
773
|
const toolbar = createElement(documentRef, 'div', 'drawing-toolbar');
|
|
773
774
|
const title = createElement(documentRef, 'div', 'drawing-title');
|
|
774
775
|
title.append(createElement(documentRef, 'span', undefined, formatDrawingLabel(type)), createElement(documentRef, 'strong', undefined, kind === 'excalidraw'
|
|
775
|
-
? '
|
|
776
|
+
? t('drawing.title.excalidraw')
|
|
776
777
|
: kind === 'mermaid'
|
|
777
|
-
? '
|
|
778
|
+
? t('drawing.title.mermaid')
|
|
778
779
|
: kind === 'plantuml'
|
|
779
|
-
? '
|
|
780
|
-
: '
|
|
780
|
+
? t('drawing.title.plantuml')
|
|
781
|
+
: t('drawing.title.drawio')));
|
|
781
782
|
const actions = createElement(documentRef, 'div', 'drawing-actions');
|
|
782
783
|
const zoomOutButton = createElement(documentRef, 'button', undefined, '-');
|
|
783
784
|
const zoomLabel = createElement(documentRef, 'span');
|
|
784
785
|
const zoomInButton = createElement(documentRef, 'button', undefined, '+');
|
|
785
|
-
const resetButton = createElement(documentRef, 'button', undefined, '
|
|
786
|
+
const resetButton = createElement(documentRef, 'button', undefined, t('drawing.toolbar.fit'));
|
|
786
787
|
[zoomOutButton, zoomInButton, resetButton].forEach(button => {
|
|
787
788
|
button.type = 'button';
|
|
788
789
|
});
|
|
789
|
-
zoomOutButton.title = '
|
|
790
|
-
zoomInButton.title = '
|
|
791
|
-
resetButton.title = '
|
|
790
|
+
zoomOutButton.title = t('drawing.toolbar.zoomOut');
|
|
791
|
+
zoomInButton.title = t('drawing.toolbar.zoomIn');
|
|
792
|
+
resetButton.title = t('drawing.toolbar.fitWidth');
|
|
792
793
|
actions.append(zoomOutButton, zoomLabel, zoomInButton, resetButton);
|
|
793
794
|
toolbar.append(title, actions);
|
|
794
795
|
const stageWrapper = createElement(documentRef, 'div', 'drawing-stage');
|
|
@@ -843,7 +844,7 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
|
|
|
843
844
|
state.classList.toggle('error', status === 'error');
|
|
844
845
|
state.textContent = status === 'error'
|
|
845
846
|
? errorMessage
|
|
846
|
-
: '
|
|
847
|
+
: t('drawing.state.loading');
|
|
847
848
|
applyZoom();
|
|
848
849
|
};
|
|
849
850
|
const loadDrawing = async () => {
|
|
@@ -858,7 +859,7 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
|
|
|
858
859
|
return;
|
|
859
860
|
}
|
|
860
861
|
if (kind === 'excalidraw') {
|
|
861
|
-
await renderExcalidraw(documentRef, text, canvas);
|
|
862
|
+
await renderExcalidraw(documentRef, text, canvas, t);
|
|
862
863
|
}
|
|
863
864
|
else if (kind === 'mermaid' || kind === 'plantuml') {
|
|
864
865
|
const { renderDiagram } = await import('./diagram.js');
|
|
@@ -869,10 +870,11 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
|
|
|
869
870
|
kind,
|
|
870
871
|
options: context?.options?.drawing,
|
|
871
872
|
theme: context?.options?.theme,
|
|
873
|
+
viewerOptions: context?.options,
|
|
872
874
|
});
|
|
873
875
|
}
|
|
874
876
|
else {
|
|
875
|
-
await renderDrawio(documentRef, text, canvas, context?.options?.drawing);
|
|
877
|
+
await renderDrawio(documentRef, text, canvas, context?.options?.drawing, t);
|
|
876
878
|
}
|
|
877
879
|
if (disposed) {
|
|
878
880
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-drawing",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone Draw.io, Excalidraw, Mermaid, and PlantUML renderer plugin for Flyfish File Viewer with pan/zoom support.",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@excalidraw/excalidraw": "^0.18.1",
|
|
60
|
-
"@file-viewer/core": "^2.1.
|
|
60
|
+
"@file-viewer/core": "^2.1.4",
|
|
61
61
|
"@panzoom/panzoom": "^4.6.2",
|
|
62
62
|
"mermaid": "^11.15.0",
|
|
63
63
|
"plantuml-encoder": "^1.4.0",
|