svelte-pdf-view 0.1.13 → 0.3.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/README.md +2 -4
- package/dist/PdfRenderer.svelte +27 -4
- package/dist/PdfToolbar.svelte +10 -2
- package/dist/PdfViewer.svelte +15 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pdf-viewer/AnnotationLayerBuilder.d.ts +54 -0
- package/dist/pdf-viewer/AnnotationLayerBuilder.js +145 -0
- package/dist/pdf-viewer/PDFPageView.d.ts +7 -1
- package/dist/pdf-viewer/PDFPageView.js +51 -0
- package/dist/pdf-viewer/PDFViewerCore.d.ts +1 -0
- package/dist/pdf-viewer/PDFViewerCore.js +12 -1
- package/dist/pdf-viewer/PdfPresentationMode.d.ts +96 -0
- package/dist/pdf-viewer/PdfPresentationMode.js +437 -0
- package/dist/pdf-viewer/SimpleLinkService.d.ts +74 -0
- package/dist/pdf-viewer/SimpleLinkService.js +212 -0
- package/dist/pdf-viewer/context.d.ts +12 -0
- package/dist/pdf-viewer/context.js +8 -0
- package/dist/pdf-viewer/renderer-styles.d.ts +1 -1
- package/dist/pdf-viewer/renderer-styles.js +155 -0
- package/dist/pdf-viewer/styles.css +1 -137
- package/package.json +1 -1
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/* Copyright 2024 Mozilla Foundation
|
|
2
|
+
*
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
export var PresentationModeState;
|
|
16
|
+
(function (PresentationModeState) {
|
|
17
|
+
PresentationModeState[PresentationModeState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
18
|
+
PresentationModeState[PresentationModeState["NORMAL"] = 1] = "NORMAL";
|
|
19
|
+
PresentationModeState[PresentationModeState["CHANGING"] = 2] = "CHANGING";
|
|
20
|
+
PresentationModeState[PresentationModeState["FULLSCREEN"] = 3] = "FULLSCREEN";
|
|
21
|
+
})(PresentationModeState || (PresentationModeState = {}));
|
|
22
|
+
const MOUSE_SCROLL_COOLDOWN_TIME = 50; // in ms
|
|
23
|
+
const PAGE_SWITCH_THRESHOLD = 0.1;
|
|
24
|
+
const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
|
|
25
|
+
const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
|
|
26
|
+
export class PdfPresentationMode {
|
|
27
|
+
state = PresentationModeState.UNKNOWN;
|
|
28
|
+
pdfDocument = null;
|
|
29
|
+
currentPageNumber = 1;
|
|
30
|
+
totalPages = 0;
|
|
31
|
+
container = null;
|
|
32
|
+
canvas = null;
|
|
33
|
+
callbacks;
|
|
34
|
+
fullscreenChangeAbortController = null;
|
|
35
|
+
windowAbortController = null;
|
|
36
|
+
mouseScrollTimeStamp = 0;
|
|
37
|
+
mouseScrollDelta = 0;
|
|
38
|
+
touchSwipeState = null;
|
|
39
|
+
renderingPage = false;
|
|
40
|
+
constructor(callbacks = {}) {
|
|
41
|
+
this.callbacks = callbacks;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Set the PDF document for presentation
|
|
45
|
+
*/
|
|
46
|
+
setDocument(pdfDocument) {
|
|
47
|
+
this.pdfDocument = pdfDocument;
|
|
48
|
+
this.totalPages = pdfDocument?.numPages ?? 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Set the current page number (used when entering presentation mode)
|
|
52
|
+
*/
|
|
53
|
+
setCurrentPage(pageNumber) {
|
|
54
|
+
this.currentPageNumber = Math.max(1, Math.min(pageNumber, this.totalPages));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if presentation mode is active
|
|
58
|
+
*/
|
|
59
|
+
get active() {
|
|
60
|
+
return (this.state === PresentationModeState.CHANGING ||
|
|
61
|
+
this.state === PresentationModeState.FULLSCREEN);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get current state
|
|
65
|
+
*/
|
|
66
|
+
get currentState() {
|
|
67
|
+
return this.state;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Request entering fullscreen presentation mode
|
|
71
|
+
*/
|
|
72
|
+
async request() {
|
|
73
|
+
if (this.active || !this.pdfDocument || this.totalPages === 0) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Create the presentation container
|
|
77
|
+
this.createPresentationContainer();
|
|
78
|
+
if (!this.container) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
this.addFullscreenChangeListeners();
|
|
82
|
+
this.notifyStateChange(PresentationModeState.CHANGING);
|
|
83
|
+
try {
|
|
84
|
+
await this.container.requestFullscreen();
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
this.removeFullscreenChangeListeners();
|
|
89
|
+
this.notifyStateChange(PresentationModeState.NORMAL);
|
|
90
|
+
this.destroyPresentationContainer();
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Exit presentation mode
|
|
96
|
+
*/
|
|
97
|
+
async exit() {
|
|
98
|
+
if (!this.active) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (document.fullscreenElement) {
|
|
102
|
+
await document.exitFullscreen();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Go to next page
|
|
107
|
+
*/
|
|
108
|
+
nextPage() {
|
|
109
|
+
if (this.currentPageNumber >= this.totalPages) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
this.currentPageNumber++;
|
|
113
|
+
this.renderCurrentPage();
|
|
114
|
+
this.callbacks.onPageChange?.(this.currentPageNumber);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Go to previous page
|
|
119
|
+
*/
|
|
120
|
+
previousPage() {
|
|
121
|
+
if (this.currentPageNumber <= 1) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
this.currentPageNumber--;
|
|
125
|
+
this.renderCurrentPage();
|
|
126
|
+
this.callbacks.onPageChange?.(this.currentPageNumber);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Go to a specific page
|
|
131
|
+
*/
|
|
132
|
+
goToPage(pageNumber) {
|
|
133
|
+
if (pageNumber < 1 || pageNumber > this.totalPages) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
this.currentPageNumber = pageNumber;
|
|
137
|
+
this.renderCurrentPage();
|
|
138
|
+
this.callbacks.onPageChange?.(this.currentPageNumber);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Destroy and cleanup
|
|
143
|
+
*/
|
|
144
|
+
destroy() {
|
|
145
|
+
this.exit();
|
|
146
|
+
this.removeWindowListeners();
|
|
147
|
+
this.removeFullscreenChangeListeners();
|
|
148
|
+
this.destroyPresentationContainer();
|
|
149
|
+
}
|
|
150
|
+
// Private methods
|
|
151
|
+
createPresentationContainer() {
|
|
152
|
+
// Create fullscreen container
|
|
153
|
+
this.container = document.createElement('div');
|
|
154
|
+
this.container.className = 'pdf-presentation-mode';
|
|
155
|
+
this.container.style.cssText = `
|
|
156
|
+
position: fixed;
|
|
157
|
+
top: 0;
|
|
158
|
+
left: 0;
|
|
159
|
+
width: 100%;
|
|
160
|
+
height: 100%;
|
|
161
|
+
background-color: #000;
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
justify-content: center;
|
|
165
|
+
z-index: 999999;
|
|
166
|
+
`;
|
|
167
|
+
// Create canvas for rendering
|
|
168
|
+
this.canvas = document.createElement('canvas');
|
|
169
|
+
this.canvas.style.cssText = `
|
|
170
|
+
max-width: 100%;
|
|
171
|
+
max-height: 100%;
|
|
172
|
+
object-fit: contain;
|
|
173
|
+
`;
|
|
174
|
+
this.container.appendChild(this.canvas);
|
|
175
|
+
document.body.appendChild(this.container);
|
|
176
|
+
}
|
|
177
|
+
destroyPresentationContainer() {
|
|
178
|
+
if (this.container) {
|
|
179
|
+
this.container.remove();
|
|
180
|
+
this.container = null;
|
|
181
|
+
this.canvas = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async renderCurrentPage() {
|
|
185
|
+
if (!this.pdfDocument || !this.canvas || !this.container || this.renderingPage) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.renderingPage = true;
|
|
189
|
+
try {
|
|
190
|
+
const page = await this.pdfDocument.getPage(this.currentPageNumber);
|
|
191
|
+
// Calculate scale to fit the screen while maintaining aspect ratio
|
|
192
|
+
const containerWidth = window.innerWidth;
|
|
193
|
+
const containerHeight = window.innerHeight;
|
|
194
|
+
const viewport = page.getViewport({ scale: 1, rotation: 0 });
|
|
195
|
+
const pageWidth = viewport.width;
|
|
196
|
+
const pageHeight = viewport.height;
|
|
197
|
+
// Calculate scale to fit
|
|
198
|
+
const scaleX = containerWidth / pageWidth;
|
|
199
|
+
const scaleY = containerHeight / pageHeight;
|
|
200
|
+
const scale = Math.min(scaleX, scaleY);
|
|
201
|
+
const scaledViewport = page.getViewport({ scale, rotation: 0 });
|
|
202
|
+
// Set canvas size
|
|
203
|
+
this.canvas.width = scaledViewport.width;
|
|
204
|
+
this.canvas.height = scaledViewport.height;
|
|
205
|
+
const context = this.canvas.getContext('2d');
|
|
206
|
+
if (!context) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Clear and render
|
|
210
|
+
context.fillStyle = '#fff';
|
|
211
|
+
context.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
212
|
+
await page.render({
|
|
213
|
+
canvasContext: context,
|
|
214
|
+
viewport: scaledViewport,
|
|
215
|
+
canvas: this.canvas
|
|
216
|
+
}).promise;
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
console.error('Failed to render presentation page:', e);
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
this.renderingPage = false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
notifyStateChange(newState) {
|
|
226
|
+
this.state = newState;
|
|
227
|
+
this.callbacks.onStateChange?.(newState);
|
|
228
|
+
}
|
|
229
|
+
enter() {
|
|
230
|
+
this.notifyStateChange(PresentationModeState.FULLSCREEN);
|
|
231
|
+
this.addWindowListeners();
|
|
232
|
+
this.renderCurrentPage();
|
|
233
|
+
// Clear any text selection
|
|
234
|
+
document.getSelection()?.empty();
|
|
235
|
+
}
|
|
236
|
+
doExit() {
|
|
237
|
+
this.removeWindowListeners();
|
|
238
|
+
this.destroyPresentationContainer();
|
|
239
|
+
this.resetMouseScrollState();
|
|
240
|
+
this.removeFullscreenChangeListeners();
|
|
241
|
+
this.notifyStateChange(PresentationModeState.NORMAL);
|
|
242
|
+
}
|
|
243
|
+
handleMouseWheel = (evt) => {
|
|
244
|
+
if (!this.active) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
evt.preventDefault();
|
|
248
|
+
const delta = this.normalizeWheelDelta(evt);
|
|
249
|
+
const currentTime = Date.now();
|
|
250
|
+
const storedTime = this.mouseScrollTimeStamp;
|
|
251
|
+
// Cooldown to prevent accidental double-switching
|
|
252
|
+
if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Reset if direction changed
|
|
256
|
+
if ((this.mouseScrollDelta > 0 && delta < 0) || (this.mouseScrollDelta < 0 && delta > 0)) {
|
|
257
|
+
this.resetMouseScrollState();
|
|
258
|
+
}
|
|
259
|
+
this.mouseScrollDelta += delta;
|
|
260
|
+
if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
|
|
261
|
+
const totalDelta = this.mouseScrollDelta;
|
|
262
|
+
this.resetMouseScrollState();
|
|
263
|
+
const success = totalDelta > 0 ? this.previousPage() : this.nextPage();
|
|
264
|
+
if (success) {
|
|
265
|
+
this.mouseScrollTimeStamp = currentTime;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
normalizeWheelDelta(evt) {
|
|
270
|
+
let delta = Math.hypot(evt.deltaX, evt.deltaY);
|
|
271
|
+
const angle = Math.atan2(evt.deltaY, evt.deltaX);
|
|
272
|
+
if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {
|
|
273
|
+
delta = -delta;
|
|
274
|
+
}
|
|
275
|
+
if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
|
276
|
+
delta *= 30;
|
|
277
|
+
}
|
|
278
|
+
else if (evt.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
|
279
|
+
delta *= 30 * 10;
|
|
280
|
+
}
|
|
281
|
+
return delta / 30;
|
|
282
|
+
}
|
|
283
|
+
handleMouseDown = (evt) => {
|
|
284
|
+
// Left click (0) = next page, Right click (2) = previous page
|
|
285
|
+
if (evt.button === 0) {
|
|
286
|
+
evt.preventDefault();
|
|
287
|
+
if (evt.shiftKey) {
|
|
288
|
+
this.previousPage();
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
this.nextPage();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else if (evt.button === 2) {
|
|
295
|
+
evt.preventDefault();
|
|
296
|
+
this.previousPage();
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
handleKeyDown = (evt) => {
|
|
300
|
+
if (!this.active) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.resetMouseScrollState();
|
|
304
|
+
switch (evt.key) {
|
|
305
|
+
case 'ArrowRight':
|
|
306
|
+
case 'ArrowDown':
|
|
307
|
+
case ' ':
|
|
308
|
+
case 'PageDown':
|
|
309
|
+
case 'Enter':
|
|
310
|
+
evt.preventDefault();
|
|
311
|
+
this.nextPage();
|
|
312
|
+
break;
|
|
313
|
+
case 'ArrowLeft':
|
|
314
|
+
case 'ArrowUp':
|
|
315
|
+
case 'PageUp':
|
|
316
|
+
case 'Backspace':
|
|
317
|
+
evt.preventDefault();
|
|
318
|
+
this.previousPage();
|
|
319
|
+
break;
|
|
320
|
+
case 'Home':
|
|
321
|
+
evt.preventDefault();
|
|
322
|
+
this.goToPage(1);
|
|
323
|
+
break;
|
|
324
|
+
case 'End':
|
|
325
|
+
evt.preventDefault();
|
|
326
|
+
this.goToPage(this.totalPages);
|
|
327
|
+
break;
|
|
328
|
+
case 'Escape':
|
|
329
|
+
// Escape is handled by the browser for fullscreen exit
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
handleContextMenu = (evt) => {
|
|
334
|
+
// Prevent context menu - right-click is handled in handleMouseDown
|
|
335
|
+
evt.preventDefault();
|
|
336
|
+
};
|
|
337
|
+
handleTouchSwipe = (evt) => {
|
|
338
|
+
if (!this.active) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (evt.touches.length > 1) {
|
|
342
|
+
this.touchSwipeState = null;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
switch (evt.type) {
|
|
346
|
+
case 'touchstart':
|
|
347
|
+
this.touchSwipeState = {
|
|
348
|
+
startX: evt.touches[0].pageX,
|
|
349
|
+
startY: evt.touches[0].pageY,
|
|
350
|
+
endX: evt.touches[0].pageX,
|
|
351
|
+
endY: evt.touches[0].pageY
|
|
352
|
+
};
|
|
353
|
+
break;
|
|
354
|
+
case 'touchmove':
|
|
355
|
+
if (this.touchSwipeState === null) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
this.touchSwipeState.endX = evt.touches[0].pageX;
|
|
359
|
+
this.touchSwipeState.endY = evt.touches[0].pageY;
|
|
360
|
+
evt.preventDefault();
|
|
361
|
+
break;
|
|
362
|
+
case 'touchend': {
|
|
363
|
+
if (this.touchSwipeState === null) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
|
|
367
|
+
const dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
|
|
368
|
+
const absAngle = Math.abs(Math.atan2(dy, dx));
|
|
369
|
+
let delta = 0;
|
|
370
|
+
if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD &&
|
|
371
|
+
(absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
|
|
372
|
+
// Horizontal swipe
|
|
373
|
+
delta = dx;
|
|
374
|
+
}
|
|
375
|
+
else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD &&
|
|
376
|
+
Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
|
|
377
|
+
// Vertical swipe
|
|
378
|
+
delta = dy;
|
|
379
|
+
}
|
|
380
|
+
if (delta > 0) {
|
|
381
|
+
this.previousPage();
|
|
382
|
+
}
|
|
383
|
+
else if (delta < 0) {
|
|
384
|
+
this.nextPage();
|
|
385
|
+
}
|
|
386
|
+
this.touchSwipeState = null;
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
handleResize = () => {
|
|
392
|
+
if (this.active) {
|
|
393
|
+
this.renderCurrentPage();
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
resetMouseScrollState() {
|
|
397
|
+
this.mouseScrollTimeStamp = 0;
|
|
398
|
+
this.mouseScrollDelta = 0;
|
|
399
|
+
}
|
|
400
|
+
addWindowListeners() {
|
|
401
|
+
if (this.windowAbortController) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
this.windowAbortController = new AbortController();
|
|
405
|
+
const { signal } = this.windowAbortController;
|
|
406
|
+
window.addEventListener('mousedown', this.handleMouseDown, { signal });
|
|
407
|
+
window.addEventListener('wheel', this.handleMouseWheel, { passive: false, signal });
|
|
408
|
+
window.addEventListener('keydown', this.handleKeyDown, { signal });
|
|
409
|
+
window.addEventListener('contextmenu', this.handleContextMenu, { signal });
|
|
410
|
+
window.addEventListener('touchstart', this.handleTouchSwipe, { signal });
|
|
411
|
+
window.addEventListener('touchmove', this.handleTouchSwipe, { passive: false, signal });
|
|
412
|
+
window.addEventListener('touchend', this.handleTouchSwipe, { signal });
|
|
413
|
+
window.addEventListener('resize', this.handleResize, { signal });
|
|
414
|
+
}
|
|
415
|
+
removeWindowListeners() {
|
|
416
|
+
this.windowAbortController?.abort();
|
|
417
|
+
this.windowAbortController = null;
|
|
418
|
+
}
|
|
419
|
+
addFullscreenChangeListeners() {
|
|
420
|
+
if (this.fullscreenChangeAbortController) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
this.fullscreenChangeAbortController = new AbortController();
|
|
424
|
+
window.addEventListener('fullscreenchange', () => {
|
|
425
|
+
if (document.fullscreenElement) {
|
|
426
|
+
this.enter();
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
this.doExit();
|
|
430
|
+
}
|
|
431
|
+
}, { signal: this.fullscreenChangeAbortController.signal });
|
|
432
|
+
}
|
|
433
|
+
removeFullscreenChangeListeners() {
|
|
434
|
+
this.fullscreenChangeAbortController?.abort();
|
|
435
|
+
this.fullscreenChangeAbortController = null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SimpleLinkService - Provides PDF navigation for annotation links.
|
|
3
|
+
* Adapted from PDF.js pdf_link_service.js
|
|
4
|
+
*/
|
|
5
|
+
import type { PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs';
|
|
6
|
+
import type { EventBus } from './EventBus.js';
|
|
7
|
+
export interface SimpleLinkServiceOptions {
|
|
8
|
+
eventBus: EventBus;
|
|
9
|
+
externalLinkTarget?: number;
|
|
10
|
+
externalLinkRel?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const LinkTarget: {
|
|
13
|
+
readonly NONE: 0;
|
|
14
|
+
readonly SELF: 1;
|
|
15
|
+
readonly BLANK: 2;
|
|
16
|
+
readonly PARENT: 3;
|
|
17
|
+
readonly TOP: 4;
|
|
18
|
+
};
|
|
19
|
+
export declare class SimpleLinkService {
|
|
20
|
+
readonly eventBus: EventBus;
|
|
21
|
+
private externalLinkTarget;
|
|
22
|
+
private externalLinkRel;
|
|
23
|
+
private pdfDocument;
|
|
24
|
+
private pdfViewer;
|
|
25
|
+
externalLinkEnabled: boolean;
|
|
26
|
+
constructor(options: SimpleLinkServiceOptions);
|
|
27
|
+
setDocument(pdfDocument: PDFDocumentProxy | null): void;
|
|
28
|
+
setViewer(pdfViewer: {
|
|
29
|
+
scrollToPage: (page: number) => void;
|
|
30
|
+
pagesCount: number;
|
|
31
|
+
}): void;
|
|
32
|
+
get pagesCount(): number;
|
|
33
|
+
get page(): number;
|
|
34
|
+
set page(value: number);
|
|
35
|
+
get rotation(): number;
|
|
36
|
+
set rotation(_value: number);
|
|
37
|
+
get isInPresentationMode(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Navigate to a PDF destination (internal link).
|
|
40
|
+
*/
|
|
41
|
+
goToDestination(dest: unknown): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Navigate to a specific page.
|
|
44
|
+
*/
|
|
45
|
+
goToPage(pageNumber: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Get a hash string for a destination (for href).
|
|
48
|
+
*/
|
|
49
|
+
getDestinationHash(dest: unknown): string;
|
|
50
|
+
/**
|
|
51
|
+
* Get anchor URL with proper prefix.
|
|
52
|
+
*/
|
|
53
|
+
getAnchorUrl(anchor: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Add attributes to external link elements.
|
|
56
|
+
*/
|
|
57
|
+
addLinkAttributes(link: HTMLAnchorElement, url: string, newWindow?: boolean): void;
|
|
58
|
+
/**
|
|
59
|
+
* Execute a named action (e.g., Print, GoBack).
|
|
60
|
+
*/
|
|
61
|
+
executeNamedAction(action: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Execute a SetOCGState action.
|
|
64
|
+
*/
|
|
65
|
+
executeSetOCGState(_action: unknown): void;
|
|
66
|
+
/**
|
|
67
|
+
* Navigate to specific coordinates on a page.
|
|
68
|
+
*/
|
|
69
|
+
goToXY(pageNumber: number, _x: number, _y: number): void;
|
|
70
|
+
/**
|
|
71
|
+
* Set hash for navigation.
|
|
72
|
+
*/
|
|
73
|
+
setHash(_hash: string): void;
|
|
74
|
+
}
|