@docmentis/udoc-viewer 0.5.1 → 0.5.3
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/package.json +1 -1
- package/dist/package.json +0 -56
- package/dist/src/UDocClient.d.ts +0 -383
- package/dist/src/UDocClient.d.ts.map +0 -1
- package/dist/src/UDocClient.js +0 -428
- package/dist/src/UDocClient.js.map +0 -1
- package/dist/src/UDocViewer.d.ts +0 -271
- package/dist/src/UDocViewer.d.ts.map +0 -1
- package/dist/src/UDocViewer.js +0 -769
- package/dist/src/UDocViewer.js.map +0 -1
- package/dist/src/fonts.d.ts +0 -29
- package/dist/src/fonts.d.ts.map +0 -1
- package/dist/src/fonts.js +0 -30
- package/dist/src/fonts.js.map +0 -1
- package/dist/src/index.d.ts +0 -9
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -8
- package/dist/src/index.js.map +0 -1
- package/dist/src/performance/PerformanceCounter.d.ts +0 -132
- package/dist/src/performance/PerformanceCounter.d.ts.map +0 -1
- package/dist/src/performance/PerformanceCounter.js +0 -129
- package/dist/src/performance/PerformanceCounter.js.map +0 -1
- package/dist/src/performance/index.d.ts +0 -2
- package/dist/src/performance/index.d.ts.map +0 -1
- package/dist/src/performance/index.js +0 -2
- package/dist/src/performance/index.js.map +0 -1
- package/dist/src/ui/framework/component.d.ts +0 -68
- package/dist/src/ui/framework/component.d.ts.map +0 -1
- package/dist/src/ui/framework/component.js +0 -87
- package/dist/src/ui/framework/component.js.map +0 -1
- package/dist/src/ui/framework/dom.d.ts +0 -19
- package/dist/src/ui/framework/dom.d.ts.map +0 -1
- package/dist/src/ui/framework/dom.js +0 -29
- package/dist/src/ui/framework/dom.js.map +0 -1
- package/dist/src/ui/framework/events.d.ts +0 -18
- package/dist/src/ui/framework/events.d.ts.map +0 -1
- package/dist/src/ui/framework/events.js +0 -23
- package/dist/src/ui/framework/events.js.map +0 -1
- package/dist/src/ui/framework/index.d.ts +0 -15
- package/dist/src/ui/framework/index.d.ts.map +0 -1
- package/dist/src/ui/framework/index.js +0 -15
- package/dist/src/ui/framework/index.js.map +0 -1
- package/dist/src/ui/framework/selectors.d.ts +0 -51
- package/dist/src/ui/framework/selectors.d.ts.map +0 -1
- package/dist/src/ui/framework/selectors.js +0 -30
- package/dist/src/ui/framework/selectors.js.map +0 -1
- package/dist/src/ui/framework/store.d.ts +0 -37
- package/dist/src/ui/framework/store.d.ts.map +0 -1
- package/dist/src/ui/framework/store.js +0 -54
- package/dist/src/ui/framework/store.js.map +0 -1
- package/dist/src/ui/viewer/actions.d.ts +0 -131
- package/dist/src/ui/viewer/actions.d.ts.map +0 -1
- package/dist/src/ui/viewer/actions.js +0 -2
- package/dist/src/ui/viewer/actions.js.map +0 -1
- package/dist/src/ui/viewer/annotation/LinkRenderer.d.ts +0 -9
- package/dist/src/ui/viewer/annotation/LinkRenderer.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/LinkRenderer.js +0 -17
- package/dist/src/ui/viewer/annotation/LinkRenderer.js.map +0 -1
- package/dist/src/ui/viewer/annotation/MarkupRenderer.d.ts +0 -21
- package/dist/src/ui/viewer/annotation/MarkupRenderer.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/MarkupRenderer.js +0 -138
- package/dist/src/ui/viewer/annotation/MarkupRenderer.js.map +0 -1
- package/dist/src/ui/viewer/annotation/ShapeRenderer.d.ts +0 -33
- package/dist/src/ui/viewer/annotation/ShapeRenderer.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/ShapeRenderer.js +0 -378
- package/dist/src/ui/viewer/annotation/ShapeRenderer.js.map +0 -1
- package/dist/src/ui/viewer/annotation/TextRenderer.d.ts +0 -23
- package/dist/src/ui/viewer/annotation/TextRenderer.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/TextRenderer.js +0 -196
- package/dist/src/ui/viewer/annotation/TextRenderer.js.map +0 -1
- package/dist/src/ui/viewer/annotation/index.d.ts +0 -8
- package/dist/src/ui/viewer/annotation/index.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/index.js +0 -8
- package/dist/src/ui/viewer/annotation/index.js.map +0 -1
- package/dist/src/ui/viewer/annotation/render.d.ts +0 -24
- package/dist/src/ui/viewer/annotation/render.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/render.js +0 -184
- package/dist/src/ui/viewer/annotation/render.js.map +0 -1
- package/dist/src/ui/viewer/annotation/types.d.ts +0 -239
- package/dist/src/ui/viewer/annotation/types.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/types.js +0 -7
- package/dist/src/ui/viewer/annotation/types.js.map +0 -1
- package/dist/src/ui/viewer/annotation/utils.d.ts +0 -37
- package/dist/src/ui/viewer/annotation/utils.d.ts.map +0 -1
- package/dist/src/ui/viewer/annotation/utils.js +0 -82
- package/dist/src/ui/viewer/annotation/utils.js.map +0 -1
- package/dist/src/ui/viewer/components/AnnotationPanel.d.ts +0 -19
- package/dist/src/ui/viewer/components/AnnotationPanel.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/AnnotationPanel.js +0 -284
- package/dist/src/ui/viewer/components/AnnotationPanel.js.map +0 -1
- package/dist/src/ui/viewer/components/FloatingToolbar.d.ts +0 -9
- package/dist/src/ui/viewer/components/FloatingToolbar.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/FloatingToolbar.js +0 -305
- package/dist/src/ui/viewer/components/FloatingToolbar.js.map +0 -1
- package/dist/src/ui/viewer/components/LeftPanel.d.ts +0 -10
- package/dist/src/ui/viewer/components/LeftPanel.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/LeftPanel.js +0 -165
- package/dist/src/ui/viewer/components/LeftPanel.js.map +0 -1
- package/dist/src/ui/viewer/components/LoadingOverlay.d.ts +0 -12
- package/dist/src/ui/viewer/components/LoadingOverlay.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/LoadingOverlay.js +0 -88
- package/dist/src/ui/viewer/components/LoadingOverlay.js.map +0 -1
- package/dist/src/ui/viewer/components/OutlinePanel.d.ts +0 -10
- package/dist/src/ui/viewer/components/OutlinePanel.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/OutlinePanel.js +0 -169
- package/dist/src/ui/viewer/components/OutlinePanel.js.map +0 -1
- package/dist/src/ui/viewer/components/PasswordDialog.d.ts +0 -15
- package/dist/src/ui/viewer/components/PasswordDialog.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/PasswordDialog.js +0 -143
- package/dist/src/ui/viewer/components/PasswordDialog.js.map +0 -1
- package/dist/src/ui/viewer/components/RightPanel.d.ts +0 -9
- package/dist/src/ui/viewer/components/RightPanel.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/RightPanel.js +0 -102
- package/dist/src/ui/viewer/components/RightPanel.js.map +0 -1
- package/dist/src/ui/viewer/components/Spread.d.ts +0 -43
- package/dist/src/ui/viewer/components/Spread.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/Spread.js +0 -345
- package/dist/src/ui/viewer/components/Spread.js.map +0 -1
- package/dist/src/ui/viewer/components/ThumbnailPanel.d.ts +0 -11
- package/dist/src/ui/viewer/components/ThumbnailPanel.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/ThumbnailPanel.js +0 -240
- package/dist/src/ui/viewer/components/ThumbnailPanel.js.map +0 -1
- package/dist/src/ui/viewer/components/Toolbar.d.ts +0 -9
- package/dist/src/ui/viewer/components/Toolbar.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/Toolbar.js +0 -93
- package/dist/src/ui/viewer/components/Toolbar.js.map +0 -1
- package/dist/src/ui/viewer/components/ViewModeMenu.d.ts +0 -9
- package/dist/src/ui/viewer/components/ViewModeMenu.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/ViewModeMenu.js +0 -169
- package/dist/src/ui/viewer/components/ViewModeMenu.js.map +0 -1
- package/dist/src/ui/viewer/components/Viewport.d.ts +0 -10
- package/dist/src/ui/viewer/components/Viewport.d.ts.map +0 -1
- package/dist/src/ui/viewer/components/Viewport.js +0 -1076
- package/dist/src/ui/viewer/components/Viewport.js.map +0 -1
- package/dist/src/ui/viewer/effects.d.ts +0 -8
- package/dist/src/ui/viewer/effects.d.ts.map +0 -1
- package/dist/src/ui/viewer/effects.js +0 -207
- package/dist/src/ui/viewer/effects.js.map +0 -1
- package/dist/src/ui/viewer/icons.d.ts +0 -32
- package/dist/src/ui/viewer/icons.d.ts.map +0 -1
- package/dist/src/ui/viewer/icons.js +0 -44
- package/dist/src/ui/viewer/icons.js.map +0 -1
- package/dist/src/ui/viewer/index.d.ts +0 -6
- package/dist/src/ui/viewer/index.d.ts.map +0 -1
- package/dist/src/ui/viewer/index.js +0 -6
- package/dist/src/ui/viewer/index.js.map +0 -1
- package/dist/src/ui/viewer/layout/index.d.ts +0 -3
- package/dist/src/ui/viewer/layout/index.d.ts.map +0 -1
- package/dist/src/ui/viewer/layout/index.js +0 -3
- package/dist/src/ui/viewer/layout/index.js.map +0 -1
- package/dist/src/ui/viewer/layout/pixelAlign.d.ts +0 -7
- package/dist/src/ui/viewer/layout/pixelAlign.d.ts.map +0 -1
- package/dist/src/ui/viewer/layout/pixelAlign.js +0 -22
- package/dist/src/ui/viewer/layout/pixelAlign.js.map +0 -1
- package/dist/src/ui/viewer/layout/spreadLayout.d.ts +0 -93
- package/dist/src/ui/viewer/layout/spreadLayout.d.ts.map +0 -1
- package/dist/src/ui/viewer/layout/spreadLayout.js +0 -315
- package/dist/src/ui/viewer/layout/spreadLayout.js.map +0 -1
- package/dist/src/ui/viewer/navigation.d.ts +0 -80
- package/dist/src/ui/viewer/navigation.d.ts.map +0 -1
- package/dist/src/ui/viewer/navigation.js +0 -59
- package/dist/src/ui/viewer/navigation.js.map +0 -1
- package/dist/src/ui/viewer/reducer.d.ts +0 -4
- package/dist/src/ui/viewer/reducer.d.ts.map +0 -1
- package/dist/src/ui/viewer/reducer.js +0 -305
- package/dist/src/ui/viewer/reducer.js.map +0 -1
- package/dist/src/ui/viewer/shell.d.ts +0 -34
- package/dist/src/ui/viewer/shell.d.ts.map +0 -1
- package/dist/src/ui/viewer/shell.js +0 -93
- package/dist/src/ui/viewer/shell.js.map +0 -1
- package/dist/src/ui/viewer/state.d.ts +0 -89
- package/dist/src/ui/viewer/state.d.ts.map +0 -1
- package/dist/src/ui/viewer/state.js +0 -55
- package/dist/src/ui/viewer/state.js.map +0 -1
- package/dist/src/ui/viewer/styles-inline.d.ts +0 -2
- package/dist/src/ui/viewer/styles-inline.d.ts.map +0 -1
- package/dist/src/ui/viewer/styles-inline.js +0 -1584
- package/dist/src/ui/viewer/styles-inline.js.map +0 -1
- package/dist/src/ui/viewer/text/index.d.ts +0 -7
- package/dist/src/ui/viewer/text/index.d.ts.map +0 -1
- package/dist/src/ui/viewer/text/index.js +0 -3
- package/dist/src/ui/viewer/text/index.js.map +0 -1
- package/dist/src/ui/viewer/text/render.d.ts +0 -19
- package/dist/src/ui/viewer/text/render.d.ts.map +0 -1
- package/dist/src/ui/viewer/text/render.js +0 -228
- package/dist/src/ui/viewer/text/render.js.map +0 -1
- package/dist/src/ui/viewer/text/selection.d.ts +0 -12
- package/dist/src/ui/viewer/text/selection.d.ts.map +0 -1
- package/dist/src/ui/viewer/text/selection.js +0 -70
- package/dist/src/ui/viewer/text/selection.js.map +0 -1
- package/dist/src/ui/viewer/text/types.d.ts +0 -37
- package/dist/src/ui/viewer/text/types.d.ts.map +0 -1
- package/dist/src/ui/viewer/text/types.js +0 -7
- package/dist/src/ui/viewer/text/types.js.map +0 -1
- package/dist/src/wasm/LICENSE +0 -104
- package/dist/src/wasm/udoc.d.ts +0 -480
- package/dist/src/wasm/udoc.js +0 -1738
- package/dist/src/wasm/udoc_bg.wasm +0 -0
- package/dist/src/wasm/udoc_bg.wasm.d.ts +0 -45
- package/dist/src/worker/WorkerClient.d.ts +0 -335
- package/dist/src/worker/WorkerClient.d.ts.map +0 -1
- package/dist/src/worker/WorkerClient.js +0 -903
- package/dist/src/worker/WorkerClient.js.map +0 -1
- package/dist/src/worker/index.d.ts +0 -4
- package/dist/src/worker/index.d.ts.map +0 -1
- package/dist/src/worker/index.js +0 -2
- package/dist/src/worker/index.js.map +0 -1
- package/dist/src/worker/worker.d.ts +0 -437
- package/dist/src/worker/worker.d.ts.map +0 -1
- package/dist/src/worker/worker.js +0 -237
- package/dist/src/worker/worker.js.map +0 -1
package/dist/src/UDocViewer.js
DELETED
|
@@ -1,769 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UDocViewer - Document viewer component.
|
|
3
|
-
*
|
|
4
|
-
* Binds to a loaded document and optionally provides UI.
|
|
5
|
-
* Created via `client.createViewer()`.
|
|
6
|
-
*/
|
|
7
|
-
import { mountViewerShell } from "./ui/viewer/shell.js";
|
|
8
|
-
import { PerformanceCounter, NoOpPerformanceCounter, } from "./performance/index.js";
|
|
9
|
-
/**
|
|
10
|
-
* Document viewer component.
|
|
11
|
-
*
|
|
12
|
-
* Supports both UI mode (with container) and headless mode (without container).
|
|
13
|
-
* Use `client.createViewer()` to create instances.
|
|
14
|
-
*/
|
|
15
|
-
export class UDocViewer {
|
|
16
|
-
workerClient;
|
|
17
|
-
container = null;
|
|
18
|
-
uiShell = null;
|
|
19
|
-
documentId = null;
|
|
20
|
-
_pageCount = 0;
|
|
21
|
-
_pageInfo = [];
|
|
22
|
-
destroyed = false;
|
|
23
|
-
eventHandlers = new Map();
|
|
24
|
-
_performanceCounter;
|
|
25
|
-
googleFontsEnabled;
|
|
26
|
-
/**
|
|
27
|
-
* @internal
|
|
28
|
-
* Use `client.createViewer()` instead.
|
|
29
|
-
*/
|
|
30
|
-
constructor(workerClient, options = {}) {
|
|
31
|
-
this.workerClient = workerClient;
|
|
32
|
-
this.googleFontsEnabled = options.googleFonts ?? true;
|
|
33
|
-
// Initialize performance counter
|
|
34
|
-
if (options.enablePerformanceCounter) {
|
|
35
|
-
const counter = new PerformanceCounter();
|
|
36
|
-
this._performanceCounter = counter;
|
|
37
|
-
if (options.onPerformanceLog) {
|
|
38
|
-
counter.onLog(options.onPerformanceLog);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
this._performanceCounter = new NoOpPerformanceCounter();
|
|
43
|
-
}
|
|
44
|
-
if (options.container) {
|
|
45
|
-
this.container = this.resolveContainer(options.container);
|
|
46
|
-
const overrides = this.buildStateOverrides(options);
|
|
47
|
-
this.uiShell = mountViewerShell(this.container, this.createEngineAdapter(), this.workerClient, overrides);
|
|
48
|
-
// Set up password callback
|
|
49
|
-
this.uiShell.setCallbacks({
|
|
50
|
-
onPasswordSubmit: (password) => this.handlePasswordSubmit(password)
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Performance counter for tracking operation timings.
|
|
56
|
-
* Only records data when `enablePerformanceCounter` is true.
|
|
57
|
-
*/
|
|
58
|
-
get performanceCounter() {
|
|
59
|
-
return this._performanceCounter;
|
|
60
|
-
}
|
|
61
|
-
buildStateOverrides(options) {
|
|
62
|
-
const overrides = {};
|
|
63
|
-
if (options.scrollMode !== undefined)
|
|
64
|
-
overrides.scrollMode = options.scrollMode;
|
|
65
|
-
if (options.layoutMode !== undefined)
|
|
66
|
-
overrides.layoutMode = options.layoutMode;
|
|
67
|
-
if (options.zoomMode !== undefined)
|
|
68
|
-
overrides.zoomMode = options.zoomMode;
|
|
69
|
-
if (options.zoom !== undefined)
|
|
70
|
-
overrides.zoom = options.zoom;
|
|
71
|
-
if (options.zoomSteps !== undefined)
|
|
72
|
-
overrides.zoomSteps = options.zoomSteps;
|
|
73
|
-
if (options.dpi !== undefined)
|
|
74
|
-
overrides.dpi = options.dpi;
|
|
75
|
-
if (options.pageSpacing !== undefined)
|
|
76
|
-
overrides.pageSpacing = options.pageSpacing;
|
|
77
|
-
if (options.spreadSpacing !== undefined)
|
|
78
|
-
overrides.spreadSpacing = options.spreadSpacing;
|
|
79
|
-
if (options.activePanel !== undefined)
|
|
80
|
-
overrides.activePanel = options.activePanel;
|
|
81
|
-
return overrides;
|
|
82
|
-
}
|
|
83
|
-
// ===========================================================================
|
|
84
|
-
// Document Loading
|
|
85
|
-
// ===========================================================================
|
|
86
|
-
/**
|
|
87
|
-
* Load a document.
|
|
88
|
-
*
|
|
89
|
-
* @param source - URL string, File object, or raw bytes
|
|
90
|
-
*/
|
|
91
|
-
async load(source) {
|
|
92
|
-
this.ensureNotDestroyed();
|
|
93
|
-
// Reset performance counter and start timing
|
|
94
|
-
this._performanceCounter.reset();
|
|
95
|
-
this._performanceCounter.setLoadStartTime();
|
|
96
|
-
// Close any existing document
|
|
97
|
-
if (this.documentId) {
|
|
98
|
-
this.close();
|
|
99
|
-
}
|
|
100
|
-
try {
|
|
101
|
-
// Track download phase
|
|
102
|
-
const downloadId = this._performanceCounter.markStart("download");
|
|
103
|
-
const { bytes, filename } = await this.resolveSourceWithFilename(source);
|
|
104
|
-
this._performanceCounter.markEnd(downloadId);
|
|
105
|
-
// Detect format and load appropriately
|
|
106
|
-
const format = detectDocumentFormat(bytes, filename);
|
|
107
|
-
const loadId = this._performanceCounter.markStart(format === "image" ? "loadImage" : format === "pptx" ? "loadPptx" : "loadPdf");
|
|
108
|
-
this.documentId =
|
|
109
|
-
format === "image"
|
|
110
|
-
? await this.workerClient.loadImage(bytes)
|
|
111
|
-
: format === "pptx"
|
|
112
|
-
? await this.workerClient.loadPptx(bytes)
|
|
113
|
-
: await this.workerClient.loadPdf(bytes);
|
|
114
|
-
this._performanceCounter.markEnd(loadId);
|
|
115
|
-
// Enable Google Fonts if requested
|
|
116
|
-
if (this.googleFontsEnabled) {
|
|
117
|
-
await this.workerClient.enableGoogleFonts(this.documentId);
|
|
118
|
-
}
|
|
119
|
-
// Register performance counter with WorkerClient for this document
|
|
120
|
-
// This enables tracking of all subsequent operations (getPageInfo, render, etc.)
|
|
121
|
-
if (this._performanceCounter.enabled) {
|
|
122
|
-
this.workerClient.setPerformanceCounter(this.documentId, this._performanceCounter);
|
|
123
|
-
}
|
|
124
|
-
// Check if document needs password
|
|
125
|
-
const passwordRequired = await this.workerClient.needsPassword(this.documentId);
|
|
126
|
-
if (passwordRequired) {
|
|
127
|
-
// Document needs password - show dialog and wait for authentication
|
|
128
|
-
if (this.uiShell) {
|
|
129
|
-
this.uiShell.dispatch({
|
|
130
|
-
type: "SET_DOC",
|
|
131
|
-
doc: { id: this.documentId },
|
|
132
|
-
pageCount: 0,
|
|
133
|
-
pageInfos: []
|
|
134
|
-
});
|
|
135
|
-
this.uiShell.dispatch({ type: "SET_NEEDS_PASSWORD", needsPassword: true });
|
|
136
|
-
}
|
|
137
|
-
// Don't emit document:load yet - wait for successful authentication
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// Load all page info upfront (fast operation)
|
|
141
|
-
this._pageInfo = await this.workerClient.getAllPageInfo(this.documentId);
|
|
142
|
-
this._pageCount = this._pageInfo.length;
|
|
143
|
-
if (this.uiShell) {
|
|
144
|
-
const initUiId = this._performanceCounter.markStart("initUiShell");
|
|
145
|
-
this.uiShell.dispatch({
|
|
146
|
-
type: "SET_DOC",
|
|
147
|
-
doc: { id: this.documentId },
|
|
148
|
-
pageCount: this._pageCount,
|
|
149
|
-
pageInfos: this._pageInfo
|
|
150
|
-
});
|
|
151
|
-
this._performanceCounter.markEnd(initUiId);
|
|
152
|
-
}
|
|
153
|
-
this.emit("document:load", { pageCount: this._pageCount });
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
const phase = error instanceof TypeError ? "fetch" : "parse";
|
|
157
|
-
this.emit("error", { error: error, phase });
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Close the current document.
|
|
163
|
-
* Viewer returns to empty state.
|
|
164
|
-
*/
|
|
165
|
-
close() {
|
|
166
|
-
if (this.documentId) {
|
|
167
|
-
const docId = this.documentId;
|
|
168
|
-
// Remove performance counter for this document
|
|
169
|
-
this.workerClient.removePerformanceCounter(docId);
|
|
170
|
-
// Clean up render cache first (cancel pending, clear cache)
|
|
171
|
-
this.workerClient.cancelRenders(docId);
|
|
172
|
-
this.workerClient.invalidateRenderCache(docId);
|
|
173
|
-
// Unload from WASM worker
|
|
174
|
-
this.workerClient.unloadPdf(docId).catch(() => {
|
|
175
|
-
// Ignore errors during close
|
|
176
|
-
});
|
|
177
|
-
this.documentId = null;
|
|
178
|
-
this._pageCount = 0;
|
|
179
|
-
this._pageInfo = [];
|
|
180
|
-
if (this.uiShell) {
|
|
181
|
-
this.uiShell.dispatch({ type: "CLEAR_DOC" });
|
|
182
|
-
}
|
|
183
|
-
this.emit("document:close", {});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Whether a document is currently loaded.
|
|
188
|
-
*/
|
|
189
|
-
get isLoaded() {
|
|
190
|
-
return this.documentId !== null;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Check if the loaded document requires a password to open.
|
|
194
|
-
* @returns True if the document needs authentication before pages can be accessed.
|
|
195
|
-
*/
|
|
196
|
-
async needsPassword() {
|
|
197
|
-
this.ensureLoaded();
|
|
198
|
-
return this.workerClient.needsPassword(this.documentId);
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Authenticate with a password to unlock an encrypted document.
|
|
202
|
-
*
|
|
203
|
-
* After successful authentication, page info is reloaded and the document
|
|
204
|
-
* becomes fully accessible.
|
|
205
|
-
*
|
|
206
|
-
* @param password - The password to try
|
|
207
|
-
* @returns True if authentication succeeded, false if the password was incorrect.
|
|
208
|
-
*/
|
|
209
|
-
async authenticate(password) {
|
|
210
|
-
this.ensureLoaded();
|
|
211
|
-
// Dispatch authenticating state for UI
|
|
212
|
-
if (this.uiShell) {
|
|
213
|
-
this.uiShell.dispatch({ type: "AUTHENTICATE_START" });
|
|
214
|
-
}
|
|
215
|
-
try {
|
|
216
|
-
const success = await this.workerClient.authenticate(this.documentId, password);
|
|
217
|
-
if (success) {
|
|
218
|
-
// Clear any cached renders from before authentication (they would be invalid)
|
|
219
|
-
this.workerClient.cancelRenders(this.documentId);
|
|
220
|
-
this.workerClient.invalidateRenderCache(this.documentId);
|
|
221
|
-
// Enable Google Fonts if requested
|
|
222
|
-
if (this.googleFontsEnabled) {
|
|
223
|
-
await this.workerClient.enableGoogleFonts(this.documentId);
|
|
224
|
-
}
|
|
225
|
-
// Reload page info after successful authentication
|
|
226
|
-
this._pageInfo = await this.workerClient.getAllPageInfo(this.documentId);
|
|
227
|
-
this._pageCount = this._pageInfo.length;
|
|
228
|
-
if (this.uiShell) {
|
|
229
|
-
this.uiShell.dispatch({ type: "AUTHENTICATE_SUCCESS" });
|
|
230
|
-
this.uiShell.dispatch({
|
|
231
|
-
type: "SET_DOC",
|
|
232
|
-
doc: { id: this.documentId },
|
|
233
|
-
pageCount: this._pageCount,
|
|
234
|
-
pageInfos: this._pageInfo
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
this.emit("document:load", { pageCount: this._pageCount });
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
if (this.uiShell) {
|
|
241
|
-
this.uiShell.dispatch({ type: "AUTHENTICATE_FAILURE", error: "Incorrect password" });
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return success;
|
|
245
|
-
}
|
|
246
|
-
catch (error) {
|
|
247
|
-
if (this.uiShell) {
|
|
248
|
-
this.uiShell.dispatch({
|
|
249
|
-
type: "AUTHENTICATE_FAILURE",
|
|
250
|
-
error: error instanceof Error ? error.message : "Authentication failed"
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
throw error;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Handle password submission from the UI dialog.
|
|
258
|
-
* @internal
|
|
259
|
-
*/
|
|
260
|
-
async handlePasswordSubmit(password) {
|
|
261
|
-
try {
|
|
262
|
-
await this.authenticate(password);
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
// Error is already dispatched to UI in authenticate()
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// ===========================================================================
|
|
269
|
-
// Document Information
|
|
270
|
-
// ===========================================================================
|
|
271
|
-
/**
|
|
272
|
-
* Total number of pages.
|
|
273
|
-
* Returns 0 if no document is loaded.
|
|
274
|
-
*/
|
|
275
|
-
get pageCount() {
|
|
276
|
-
return this._pageCount;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Document metadata (title, author, etc.).
|
|
280
|
-
* Returns null if no document is loaded.
|
|
281
|
-
*/
|
|
282
|
-
get metadata() {
|
|
283
|
-
// TODO: Implement metadata retrieval from WASM
|
|
284
|
-
if (!this.documentId)
|
|
285
|
-
return null;
|
|
286
|
-
return {};
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Get document outline (table of contents / bookmarks).
|
|
290
|
-
*/
|
|
291
|
-
async getOutline() {
|
|
292
|
-
this.ensureLoaded();
|
|
293
|
-
const raw = await this.workerClient.getOutline(this.documentId);
|
|
294
|
-
return raw;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Get page dimensions in points (1 point = 1/72 inch).
|
|
298
|
-
* @param page - Page index (0-based)
|
|
299
|
-
*/
|
|
300
|
-
async getPageInfo(page) {
|
|
301
|
-
this.ensureLoaded();
|
|
302
|
-
if (page < 0 || page >= this._pageCount) {
|
|
303
|
-
throw new Error(`Page index ${page} out of bounds (0-${this._pageCount - 1})`);
|
|
304
|
-
}
|
|
305
|
-
// Return cached info if available
|
|
306
|
-
if (this._pageInfo[page]) {
|
|
307
|
-
return this._pageInfo[page];
|
|
308
|
-
}
|
|
309
|
-
// Fetch from worker if not loaded yet
|
|
310
|
-
const info = await this.workerClient.getPageInfo(this.documentId, page);
|
|
311
|
-
this._pageInfo[page] = info;
|
|
312
|
-
return info;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Get annotations on a specific page.
|
|
316
|
-
* @param page - Page index (0-based)
|
|
317
|
-
*/
|
|
318
|
-
async getPageAnnotations(page) {
|
|
319
|
-
this.ensureLoaded();
|
|
320
|
-
const raw = await this.workerClient.getPageAnnotations(this.documentId, page);
|
|
321
|
-
return raw;
|
|
322
|
-
}
|
|
323
|
-
// ===========================================================================
|
|
324
|
-
// Navigation
|
|
325
|
-
// ===========================================================================
|
|
326
|
-
/**
|
|
327
|
-
* Get the current page number (1-based).
|
|
328
|
-
*/
|
|
329
|
-
get currentPage() {
|
|
330
|
-
if (this.uiShell) {
|
|
331
|
-
return this.uiShell.getState().page;
|
|
332
|
-
}
|
|
333
|
-
return 1;
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Navigate to a specific page.
|
|
337
|
-
* @param page - Page number (1-based)
|
|
338
|
-
*/
|
|
339
|
-
goToPage(page) {
|
|
340
|
-
this.ensureNotDestroyed();
|
|
341
|
-
if (!this.uiShell) {
|
|
342
|
-
throw new Error("Navigation requires UI mode (container must be provided)");
|
|
343
|
-
}
|
|
344
|
-
this.uiShell.dispatch({ type: "NAVIGATE_TO_PAGE", page });
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Navigate to a destination (page + position + zoom).
|
|
348
|
-
* @param destination - Full destination object with page index and display mode
|
|
349
|
-
*/
|
|
350
|
-
goToDestination(destination) {
|
|
351
|
-
this.ensureNotDestroyed();
|
|
352
|
-
if (!this.uiShell) {
|
|
353
|
-
throw new Error("Navigation requires UI mode (container must be provided)");
|
|
354
|
-
}
|
|
355
|
-
this.uiShell.dispatch({ type: "NAVIGATE_TO_DESTINATION", destination });
|
|
356
|
-
}
|
|
357
|
-
// ===========================================================================
|
|
358
|
-
// Page Rendering
|
|
359
|
-
// ===========================================================================
|
|
360
|
-
/**
|
|
361
|
-
* Render a page to an image.
|
|
362
|
-
*
|
|
363
|
-
* @param page - Page index (0-based)
|
|
364
|
-
* @param options - Render options (scale, format, etc.)
|
|
365
|
-
*/
|
|
366
|
-
async renderPage(page, options = {}) {
|
|
367
|
-
return this.renderWithType(page, "page", options);
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Render a thumbnail of a page.
|
|
371
|
-
*
|
|
372
|
-
* Similar to renderPage but uses lower priority in the render queue,
|
|
373
|
-
* making it suitable for generating thumbnails without blocking main page renders.
|
|
374
|
-
*
|
|
375
|
-
* @param page - Page index (0-based)
|
|
376
|
-
* @param options - Render options (scale, format, etc.)
|
|
377
|
-
*/
|
|
378
|
-
async renderThumbnail(page, options = {}) {
|
|
379
|
-
return this.renderWithType(page, "thumbnail", options);
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Internal method to render a page with a specific render type.
|
|
383
|
-
*/
|
|
384
|
-
async renderWithType(page, type, options = {}) {
|
|
385
|
-
this.ensureLoaded();
|
|
386
|
-
const scale = options.scale ?? 1;
|
|
387
|
-
const format = options.format ?? "image-data";
|
|
388
|
-
const force = options.force ?? false;
|
|
389
|
-
const boost = options.boost ?? false;
|
|
390
|
-
const renderRequest = {
|
|
391
|
-
docId: this.documentId,
|
|
392
|
-
page: page + 1, // Uses 1-based page numbers
|
|
393
|
-
type,
|
|
394
|
-
scale
|
|
395
|
-
};
|
|
396
|
-
let result;
|
|
397
|
-
if (force) {
|
|
398
|
-
// Bypass cache and queue, call worker directly
|
|
399
|
-
result = await this.workerClient.forceRender(renderRequest);
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
// Boost priority if requested (before queueing the render)
|
|
403
|
-
if (boost) {
|
|
404
|
-
if (type === "page") {
|
|
405
|
-
this.workerClient.boostPageRenderPriority(this.documentId, page + 1);
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
408
|
-
this.workerClient.boostThumbnailRenderPriority(this.documentId, page + 1);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
// Request render through WorkerClient
|
|
412
|
-
// Performance tracking is handled by WorkerClient.doRender()
|
|
413
|
-
result = await this.workerClient.requestRender(renderRequest);
|
|
414
|
-
}
|
|
415
|
-
// Convert ImageBitmap to the requested format
|
|
416
|
-
return this.convertBitmapToFormat(result.bitmap, format, options);
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Convert an ImageBitmap to the requested output format.
|
|
420
|
-
*/
|
|
421
|
-
async convertBitmapToFormat(bitmap, format, options) {
|
|
422
|
-
if (format === "image-bitmap") {
|
|
423
|
-
return bitmap;
|
|
424
|
-
}
|
|
425
|
-
const canvas = document.createElement("canvas");
|
|
426
|
-
canvas.width = bitmap.width;
|
|
427
|
-
canvas.height = bitmap.height;
|
|
428
|
-
const ctx = canvas.getContext("2d");
|
|
429
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
430
|
-
if (format === "image-data") {
|
|
431
|
-
return ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
432
|
-
}
|
|
433
|
-
const imageType = options.imageType ?? "image/png";
|
|
434
|
-
const quality = options.quality ?? 0.92;
|
|
435
|
-
if (format === "blob") {
|
|
436
|
-
return new Promise((resolve, reject) => {
|
|
437
|
-
canvas.toBlob((blob) => {
|
|
438
|
-
if (blob)
|
|
439
|
-
resolve(blob);
|
|
440
|
-
else
|
|
441
|
-
reject(new Error("Failed to create blob"));
|
|
442
|
-
}, imageType, quality);
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
// data-url
|
|
446
|
-
return canvas.toDataURL(imageType, quality);
|
|
447
|
-
}
|
|
448
|
-
// ===========================================================================
|
|
449
|
-
// Export
|
|
450
|
-
// ===========================================================================
|
|
451
|
-
/**
|
|
452
|
-
* Export document as bytes.
|
|
453
|
-
*/
|
|
454
|
-
async toBytes() {
|
|
455
|
-
this.ensureLoaded();
|
|
456
|
-
return this.workerClient.getBytes(this.documentId);
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Download document to user's device.
|
|
460
|
-
* @param filename - Filename for download
|
|
461
|
-
*/
|
|
462
|
-
async download(filename) {
|
|
463
|
-
const bytes = await this.toBytes();
|
|
464
|
-
const blob = new Blob([bytes.buffer], { type: "application/pdf" });
|
|
465
|
-
const url = URL.createObjectURL(blob);
|
|
466
|
-
const a = document.createElement("a");
|
|
467
|
-
a.href = url;
|
|
468
|
-
a.download = filename ?? "document.pdf";
|
|
469
|
-
a.click();
|
|
470
|
-
URL.revokeObjectURL(url);
|
|
471
|
-
}
|
|
472
|
-
// ===========================================================================
|
|
473
|
-
// Events
|
|
474
|
-
// ===========================================================================
|
|
475
|
-
/**
|
|
476
|
-
* Subscribe to an event.
|
|
477
|
-
* @returns Unsubscribe function
|
|
478
|
-
*/
|
|
479
|
-
on(event, handler) {
|
|
480
|
-
if (!this.eventHandlers.has(event)) {
|
|
481
|
-
this.eventHandlers.set(event, new Set());
|
|
482
|
-
}
|
|
483
|
-
this.eventHandlers.get(event).add(handler);
|
|
484
|
-
return () => this.off(event, handler);
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* Unsubscribe from an event.
|
|
488
|
-
*/
|
|
489
|
-
off(event, handler) {
|
|
490
|
-
this.eventHandlers.get(event)?.delete(handler);
|
|
491
|
-
}
|
|
492
|
-
// ===========================================================================
|
|
493
|
-
// Lifecycle
|
|
494
|
-
// ===========================================================================
|
|
495
|
-
/**
|
|
496
|
-
* Destroy the viewer and release resources.
|
|
497
|
-
*/
|
|
498
|
-
destroy() {
|
|
499
|
-
if (this.destroyed)
|
|
500
|
-
return;
|
|
501
|
-
this.destroyed = true;
|
|
502
|
-
if (this.uiShell) {
|
|
503
|
-
this.uiShell.destroy();
|
|
504
|
-
this.uiShell = null;
|
|
505
|
-
}
|
|
506
|
-
this.close();
|
|
507
|
-
this.eventHandlers.clear();
|
|
508
|
-
}
|
|
509
|
-
// ===========================================================================
|
|
510
|
-
// Internal Helpers
|
|
511
|
-
// ===========================================================================
|
|
512
|
-
/**
|
|
513
|
-
* Get the document ID (for internal use).
|
|
514
|
-
* @internal
|
|
515
|
-
*/
|
|
516
|
-
getDocumentId() {
|
|
517
|
-
return this.documentId;
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Initialize the viewer with an already-loaded document ID.
|
|
521
|
-
* Used by UDocClient.compose() to create viewers for composed documents.
|
|
522
|
-
* @internal
|
|
523
|
-
*/
|
|
524
|
-
async initializeFromDocId(docId) {
|
|
525
|
-
this.ensureNotDestroyed();
|
|
526
|
-
if (this.documentId) {
|
|
527
|
-
this.close();
|
|
528
|
-
}
|
|
529
|
-
this.documentId = docId;
|
|
530
|
-
// Load all page info upfront (fast operation)
|
|
531
|
-
this._pageInfo = await this.workerClient.getAllPageInfo(docId);
|
|
532
|
-
this._pageCount = this._pageInfo.length;
|
|
533
|
-
if (this.uiShell) {
|
|
534
|
-
this.uiShell.dispatch({
|
|
535
|
-
type: "SET_DOC",
|
|
536
|
-
doc: { id: docId },
|
|
537
|
-
pageCount: this._pageCount,
|
|
538
|
-
pageInfos: this._pageInfo
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
this.emit("document:load", { pageCount: this._pageCount });
|
|
542
|
-
}
|
|
543
|
-
resolveContainer(container) {
|
|
544
|
-
if (typeof container === "string") {
|
|
545
|
-
const element = document.querySelector(container);
|
|
546
|
-
if (!element) {
|
|
547
|
-
throw new Error(`Container not found: ${container}`);
|
|
548
|
-
}
|
|
549
|
-
return element;
|
|
550
|
-
}
|
|
551
|
-
return container;
|
|
552
|
-
}
|
|
553
|
-
async resolveSourceWithFilename(source) {
|
|
554
|
-
if (source instanceof Uint8Array) {
|
|
555
|
-
return { bytes: source };
|
|
556
|
-
}
|
|
557
|
-
if (source instanceof File) {
|
|
558
|
-
const buffer = await source.arrayBuffer();
|
|
559
|
-
return { bytes: new Uint8Array(buffer), filename: source.name };
|
|
560
|
-
}
|
|
561
|
-
// URL string - use streaming to report progress
|
|
562
|
-
const bytes = await this.fetchWithProgress(source);
|
|
563
|
-
return { bytes, filename: source };
|
|
564
|
-
}
|
|
565
|
-
async fetchWithProgress(url) {
|
|
566
|
-
// Show progress bar immediately before sending the request
|
|
567
|
-
if (this.uiShell) {
|
|
568
|
-
this.uiShell.dispatch({
|
|
569
|
-
type: "SET_DOWNLOAD_PROGRESS",
|
|
570
|
-
loaded: 0,
|
|
571
|
-
total: 0,
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
this.emit("download:progress", { loaded: 0, total: 0, percent: null });
|
|
575
|
-
const response = await fetch(url);
|
|
576
|
-
if (!response.ok) {
|
|
577
|
-
throw new Error(`Failed to fetch document: ${response.statusText}`);
|
|
578
|
-
}
|
|
579
|
-
const contentLength = response.headers.get("Content-Length");
|
|
580
|
-
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
|
581
|
-
// If no body or no streaming support, fall back to simple approach
|
|
582
|
-
if (!response.body) {
|
|
583
|
-
const buffer = await response.arrayBuffer();
|
|
584
|
-
// Clear download progress from UI
|
|
585
|
-
if (this.uiShell) {
|
|
586
|
-
this.uiShell.dispatch({ type: "CLEAR_DOWNLOAD_PROGRESS" });
|
|
587
|
-
}
|
|
588
|
-
return new Uint8Array(buffer);
|
|
589
|
-
}
|
|
590
|
-
const reader = response.body.getReader();
|
|
591
|
-
const chunks = [];
|
|
592
|
-
let loaded = 0;
|
|
593
|
-
// Helper to report progress to both event listeners and UI shell
|
|
594
|
-
const reportProgress = (currentLoaded) => {
|
|
595
|
-
const progress = {
|
|
596
|
-
loaded: currentLoaded,
|
|
597
|
-
total,
|
|
598
|
-
percent: total > 0 ? Math.round((currentLoaded / total) * 100) : null,
|
|
599
|
-
};
|
|
600
|
-
this.emit("download:progress", progress);
|
|
601
|
-
// Dispatch to UI shell for the loading overlay
|
|
602
|
-
if (this.uiShell) {
|
|
603
|
-
this.uiShell.dispatch({
|
|
604
|
-
type: "SET_DOWNLOAD_PROGRESS",
|
|
605
|
-
loaded: currentLoaded,
|
|
606
|
-
total,
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
// Report initial progress with known total (transitions from indeterminate to 0%)
|
|
611
|
-
reportProgress(0);
|
|
612
|
-
while (true) {
|
|
613
|
-
const { done, value } = await reader.read();
|
|
614
|
-
if (done)
|
|
615
|
-
break;
|
|
616
|
-
chunks.push(value);
|
|
617
|
-
loaded += value.length;
|
|
618
|
-
reportProgress(loaded);
|
|
619
|
-
}
|
|
620
|
-
// Clear download progress from UI
|
|
621
|
-
if (this.uiShell) {
|
|
622
|
-
this.uiShell.dispatch({ type: "CLEAR_DOWNLOAD_PROGRESS" });
|
|
623
|
-
}
|
|
624
|
-
// Combine chunks into single array
|
|
625
|
-
const result = new Uint8Array(loaded);
|
|
626
|
-
let offset = 0;
|
|
627
|
-
for (const chunk of chunks) {
|
|
628
|
-
result.set(chunk, offset);
|
|
629
|
-
offset += chunk.length;
|
|
630
|
-
}
|
|
631
|
-
return result;
|
|
632
|
-
}
|
|
633
|
-
emit(event, payload) {
|
|
634
|
-
const handlers = this.eventHandlers.get(event);
|
|
635
|
-
if (handlers) {
|
|
636
|
-
for (const handler of handlers) {
|
|
637
|
-
try {
|
|
638
|
-
handler(payload);
|
|
639
|
-
}
|
|
640
|
-
catch (error) {
|
|
641
|
-
console.error(`Error in event handler for ${event}:`, error);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
createEngineAdapter() {
|
|
647
|
-
return {
|
|
648
|
-
getPageInfo: async (_doc, page) => {
|
|
649
|
-
const pageIndex = Math.max(0, page - 1);
|
|
650
|
-
return this._pageInfo[pageIndex] ?? { width: 0, height: 0 };
|
|
651
|
-
},
|
|
652
|
-
getOutline: async (doc) => {
|
|
653
|
-
const raw = await this.workerClient.getOutline(doc.id);
|
|
654
|
-
return raw;
|
|
655
|
-
},
|
|
656
|
-
getPageAnnotations: async (doc, pageIndex) => {
|
|
657
|
-
const raw = await this.workerClient.getPageAnnotations(doc.id, pageIndex);
|
|
658
|
-
return raw;
|
|
659
|
-
},
|
|
660
|
-
getPageText: async (doc, pageIndex) => {
|
|
661
|
-
const raw = await this.workerClient.getPageText(doc.id, pageIndex);
|
|
662
|
-
return raw;
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
ensureNotDestroyed() {
|
|
667
|
-
if (this.destroyed) {
|
|
668
|
-
throw new Error("UDocViewer has been destroyed");
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
ensureLoaded() {
|
|
672
|
-
this.ensureNotDestroyed();
|
|
673
|
-
if (!this.documentId) {
|
|
674
|
-
throw new Error("No document loaded");
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Detect document format based on magic bytes and filename.
|
|
680
|
-
* Returns "pdf" for PDF files, "pptx" for PowerPoint files, "image" for supported image formats.
|
|
681
|
-
*/
|
|
682
|
-
function detectDocumentFormat(bytes, filename) {
|
|
683
|
-
// Check magic bytes first (most reliable)
|
|
684
|
-
if (bytes.length >= 4) {
|
|
685
|
-
// PDF: %PDF
|
|
686
|
-
if (bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46) {
|
|
687
|
-
return "pdf";
|
|
688
|
-
}
|
|
689
|
-
// ZIP signature: PK\x03\x04 (0x504B0304) - PPTX is a ZIP archive
|
|
690
|
-
if (bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04) {
|
|
691
|
-
// Check filename extension to distinguish OOXML types
|
|
692
|
-
if (filename) {
|
|
693
|
-
const ext = filename.toLowerCase().split(".").pop();
|
|
694
|
-
if (ext === "pptx") {
|
|
695
|
-
return "pptx";
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
// Default ZIP to PPTX for now (could add DOCX/XLSX later)
|
|
699
|
-
return "pptx";
|
|
700
|
-
}
|
|
701
|
-
// JPEG: FF D8 FF
|
|
702
|
-
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
|
|
703
|
-
return "image";
|
|
704
|
-
}
|
|
705
|
-
// PNG: 89 50 4E 47
|
|
706
|
-
if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {
|
|
707
|
-
return "image";
|
|
708
|
-
}
|
|
709
|
-
// GIF: GIF8
|
|
710
|
-
if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38) {
|
|
711
|
-
return "image";
|
|
712
|
-
}
|
|
713
|
-
// BMP: BM
|
|
714
|
-
if (bytes[0] === 0x42 && bytes[1] === 0x4d) {
|
|
715
|
-
return "image";
|
|
716
|
-
}
|
|
717
|
-
// TIFF: II (little-endian) or MM (big-endian) followed by 42
|
|
718
|
-
if ((bytes[0] === 0x49 && bytes[1] === 0x49 && bytes[2] === 0x2a && bytes[3] === 0x00) ||
|
|
719
|
-
(bytes[0] === 0x4d && bytes[1] === 0x4d && bytes[2] === 0x00 && bytes[3] === 0x2a)) {
|
|
720
|
-
return "image";
|
|
721
|
-
}
|
|
722
|
-
// WebP: RIFF....WEBP
|
|
723
|
-
if (bytes.length >= 12 &&
|
|
724
|
-
bytes[0] === 0x52 &&
|
|
725
|
-
bytes[1] === 0x49 &&
|
|
726
|
-
bytes[2] === 0x46 &&
|
|
727
|
-
bytes[3] === 0x46 &&
|
|
728
|
-
bytes[8] === 0x57 &&
|
|
729
|
-
bytes[9] === 0x45 &&
|
|
730
|
-
bytes[10] === 0x42 &&
|
|
731
|
-
bytes[11] === 0x50) {
|
|
732
|
-
return "image";
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
// Fallback to filename extension
|
|
736
|
-
if (filename) {
|
|
737
|
-
const ext = filename.toLowerCase().split(".").pop();
|
|
738
|
-
// PPTX extension
|
|
739
|
-
if (ext === "pptx") {
|
|
740
|
-
return "pptx";
|
|
741
|
-
}
|
|
742
|
-
const imageExtensions = [
|
|
743
|
-
"jpg",
|
|
744
|
-
"jpeg",
|
|
745
|
-
"png",
|
|
746
|
-
"gif",
|
|
747
|
-
"bmp",
|
|
748
|
-
"tiff",
|
|
749
|
-
"tif",
|
|
750
|
-
"webp",
|
|
751
|
-
"ico",
|
|
752
|
-
"pnm",
|
|
753
|
-
"pbm",
|
|
754
|
-
"pgm",
|
|
755
|
-
"ppm",
|
|
756
|
-
"tga",
|
|
757
|
-
"hdr",
|
|
758
|
-
"exr",
|
|
759
|
-
"qoi",
|
|
760
|
-
"ff",
|
|
761
|
-
];
|
|
762
|
-
if (ext && imageExtensions.includes(ext)) {
|
|
763
|
-
return "image";
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
// Default to PDF for unknown formats
|
|
767
|
-
return "pdf";
|
|
768
|
-
}
|
|
769
|
-
//# sourceMappingURL=UDocViewer.js.map
|