@vaadin-component-factory/vcf-pdf-viewer 4.0.2 → 4.2.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.
@@ -1,638 +1,483 @@
1
- import { parseQueryString } from './ui_utils.js';
2
-
3
- /* Copyright 2015 Mozilla Foundation
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- /**
18
- * @typedef {Object} PDFLinkServiceOptions
19
- * @property {EventBus} eventBus - The application event bus.
20
- * @property {number} [externalLinkTarget] - Specifies the `target` attribute
21
- * for external links. Must use one of the values from {LinkTarget}.
22
- * Defaults to using no target.
23
- * @property {string} [externalLinkRel] - Specifies the `rel` attribute for
24
- * external links. Defaults to stripping the referrer.
25
- * @property {boolean} [ignoreDestinationZoom] - Ignores the zoom argument,
26
- * thus preserving the current zoom level in the viewer, when navigating
27
- * to internal destinations. The default value is `false`.
28
- */
29
-
30
- /**
31
- * Performs navigation functions inside PDF, such as opening specified page,
32
- * or destination.
33
- * @implements {IPDFLinkService}
34
- */
35
-
36
- class PDFLinkService {
37
- /**
38
- * @param {PDFLinkServiceOptions} options
39
- */
40
- constructor({
41
- eventBus,
42
- externalLinkTarget = null,
43
- externalLinkRel = null,
44
- ignoreDestinationZoom = false
45
- } = {}) {
46
- this.eventBus = eventBus;
47
- this.externalLinkTarget = externalLinkTarget;
48
- this.externalLinkRel = externalLinkRel;
49
- this.externalLinkEnabled = true;
50
- this._ignoreDestinationZoom = ignoreDestinationZoom;
51
- this.baseUrl = null;
52
- this.pdfDocument = null;
53
- this.pdfViewer = null;
54
- this.pdfHistory = null;
55
- this._pagesRefCache = null;
56
- }
57
-
58
- setDocument(pdfDocument, baseUrl = null) {
59
- this.baseUrl = baseUrl;
60
- this.pdfDocument = pdfDocument;
61
- this._pagesRefCache = Object.create(null);
62
- }
63
-
64
- setViewer(pdfViewer) {
65
- this.pdfViewer = pdfViewer;
66
- }
67
-
68
- setHistory(pdfHistory) {
69
- this.pdfHistory = pdfHistory;
70
- }
71
- /**
72
- * @type {number}
73
- */
74
-
75
-
76
- get pagesCount() {
77
- return this.pdfDocument ? this.pdfDocument.numPages : 0;
78
- }
79
- /**
80
- * @type {number}
81
- */
82
-
83
-
84
- get page() {
85
- return this.pdfViewer.currentPageNumber;
86
- }
87
- /**
88
- * @param {number} value
89
- */
90
-
91
-
92
- set page(value) {
93
- this.pdfViewer.currentPageNumber = value;
94
- }
95
- /**
96
- * @type {number}
97
- */
98
-
99
-
100
- get rotation() {
101
- return this.pdfViewer.pagesRotation;
102
- }
103
- /**
104
- * @param {number} value
105
- */
106
-
107
-
108
- set rotation(value) {
109
- this.pdfViewer.pagesRotation = value;
110
- }
111
- /**
112
- * @private
113
- */
114
-
115
-
116
- _goToDestinationHelper(rawDest, namedDest = null, explicitDest) {
117
- // Dest array looks like that: <page-ref> </XYZ|/FitXXX> <args..>
118
- const destRef = explicitDest[0];
119
- let pageNumber;
120
-
121
- if (typeof destRef === "object" && destRef !== null) {
122
- pageNumber = this._cachedPageNumber(destRef);
123
-
124
- if (pageNumber === null) {
125
- // Fetch the page reference if it's not yet available. This could
126
- // only occur during loading, before all pages have been resolved.
127
- this.pdfDocument.getPageIndex(destRef).then(pageIndex => {
128
- this.cachePageRef(pageIndex + 1, destRef);
129
-
130
- this._goToDestinationHelper(rawDest, namedDest, explicitDest);
131
- }).catch(() => {
132
- console.error(`PDFLinkService._goToDestinationHelper: "${destRef}" is not ` + `a valid page reference, for dest="${rawDest}".`);
133
- });
134
- return;
135
- }
136
- } else if (Number.isInteger(destRef)) {
137
- pageNumber = destRef + 1;
138
- } else {
139
- console.error(`PDFLinkService._goToDestinationHelper: "${destRef}" is not ` + `a valid destination reference, for dest="${rawDest}".`);
140
- return;
141
- }
142
-
143
- if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
144
- console.error(`PDFLinkService._goToDestinationHelper: "${pageNumber}" is not ` + `a valid page number, for dest="${rawDest}".`);
145
- return;
146
- }
147
-
148
- if (this.pdfHistory) {
149
- // Update the browser history before scrolling the new destination into
150
- // view, to be able to accurately capture the current document position.
151
- this.pdfHistory.pushCurrentPosition();
152
- this.pdfHistory.push({
153
- namedDest,
154
- explicitDest,
155
- pageNumber
156
- });
157
- }
158
-
159
- this.pdfViewer.scrollPageIntoView({
160
- pageNumber,
161
- destArray: explicitDest,
162
- ignoreDestinationZoom: this._ignoreDestinationZoom
163
- });
164
- }
165
- /**
166
- * This method will, when available, also update the browser history.
167
- *
168
- * @param {string|Array} dest - The named, or explicit, PDF destination.
169
- */
170
-
171
-
172
- async goToDestination(dest) {
173
- if (!this.pdfDocument) {
174
- return;
175
- }
176
-
177
- let namedDest, explicitDest;
178
-
179
- if (typeof dest === "string") {
180
- namedDest = dest;
181
- explicitDest = await this.pdfDocument.getDestination(dest);
182
- } else {
183
- namedDest = null;
184
- explicitDest = await dest;
185
- }
186
-
187
- if (!Array.isArray(explicitDest)) {
188
- console.error(`PDFLinkService.goToDestination: "${explicitDest}" is not ` + `a valid destination array, for dest="${dest}".`);
189
- return;
190
- }
191
-
192
- this._goToDestinationHelper(dest, namedDest, explicitDest);
193
- }
194
- /**
195
- * This method will, when available, also update the browser history.
196
- *
197
- * @param {number|string} val - The page number, or page label.
198
- */
199
-
200
-
201
- goToPage(val) {
202
- if (!this.pdfDocument) {
203
- return;
204
- }
205
-
206
- const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0;
207
-
208
- if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
209
- console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`);
210
- return;
211
- }
212
-
213
- if (this.pdfHistory) {
214
- // Update the browser history before scrolling the new page into view,
215
- // to be able to accurately capture the current document position.
216
- this.pdfHistory.pushCurrentPosition();
217
- this.pdfHistory.pushPage(pageNumber);
218
- }
219
-
220
- this.pdfViewer.scrollPageIntoView({
221
- pageNumber
222
- });
223
- }
224
- /**
225
- * @param {string|Array} dest - The PDF destination object.
226
- * @returns {string} The hyperlink to the PDF object.
227
- */
228
-
229
-
230
- getDestinationHash(dest) {
231
- if (typeof dest === "string") {
232
- if (dest.length > 0) {
233
- return this.getAnchorUrl("#" + escape(dest));
234
- }
235
- } else if (Array.isArray(dest)) {
236
- const str = JSON.stringify(dest);
237
-
238
- if (str.length > 0) {
239
- return this.getAnchorUrl("#" + escape(str));
240
- }
241
- }
242
-
243
- return this.getAnchorUrl("");
244
- }
245
- /**
246
- * Prefix the full url on anchor links to make sure that links are resolved
247
- * relative to the current URL instead of the one defined in <base href>.
248
- * @param {string} anchor - The anchor hash, including the #.
249
- * @returns {string} The hyperlink to the PDF object.
250
- */
251
-
252
-
253
- getAnchorUrl(anchor) {
254
- return (this.baseUrl || "") + anchor;
255
- }
256
- /**
257
- * @param {string} hash
258
- */
259
-
260
-
261
- setHash(hash) {
262
- if (!this.pdfDocument) {
263
- return;
264
- }
265
-
266
- let pageNumber, dest;
267
-
268
- if (hash.includes("=")) {
269
- const params = parseQueryString(hash);
270
-
271
- if ("search" in params) {
272
- this.eventBus.dispatch("findfromurlhash", {
273
- source: this,
274
- query: params.search.replace(/"/g, ""),
275
- phraseSearch: params.phrase === "true"
276
- });
277
- } // borrowing syntax from "Parameters for Opening PDF Files"
278
-
279
-
280
- if ("page" in params) {
281
- pageNumber = params.page | 0 || 1;
282
- }
283
-
284
- if ("zoom" in params) {
285
- // Build the destination array.
286
- const zoomArgs = params.zoom.split(","); // scale,left,top
287
-
288
- const zoomArg = zoomArgs[0];
289
- const zoomArgNumber = parseFloat(zoomArg);
290
-
291
- if (!zoomArg.includes("Fit")) {
292
- // If the zoomArg is a number, it has to get divided by 100. If it's
293
- // a string, it should stay as it is.
294
- dest = [null, {
295
- name: "XYZ"
296
- }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg];
297
- } else {
298
- if (zoomArg === "Fit" || zoomArg === "FitB") {
299
- dest = [null, {
300
- name: zoomArg
301
- }];
302
- } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") {
303
- dest = [null, {
304
- name: zoomArg
305
- }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null];
306
- } else if (zoomArg === "FitR") {
307
- if (zoomArgs.length !== 5) {
308
- console.error('PDFLinkService.setHash: Not enough parameters for "FitR".');
309
- } else {
310
- dest = [null, {
311
- name: zoomArg
312
- }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0];
313
- }
314
- } else {
315
- console.error(`PDFLinkService.setHash: "${zoomArg}" is not ` + "a valid zoom value.");
316
- }
317
- }
318
- }
319
-
320
- if (dest) {
321
- this.pdfViewer.scrollPageIntoView({
322
- pageNumber: pageNumber || this.page,
323
- destArray: dest,
324
- allowNegativeOffset: true
325
- });
326
- } else if (pageNumber) {
327
- this.page = pageNumber; // simple page
328
- }
329
-
330
- if ("pagemode" in params) {
331
- this.eventBus.dispatch("pagemode", {
332
- source: this,
333
- mode: params.pagemode
334
- });
335
- } // Ensure that this parameter is *always* handled last, in order to
336
- // guarantee that it won't be overridden (e.g. by the "page" parameter).
337
-
338
-
339
- if ("nameddest" in params) {
340
- this.goToDestination(params.nameddest);
341
- }
342
- } else {
343
- // Named (or explicit) destination.
344
- dest = unescape(hash);
345
-
346
- try {
347
- dest = JSON.parse(dest);
348
-
349
- if (!Array.isArray(dest)) {
350
- // Avoid incorrectly rejecting a valid named destination, such as
351
- // e.g. "4.3" or "true", because `JSON.parse` converted its type.
352
- dest = dest.toString();
353
- }
354
- } catch (ex) {}
355
-
356
- if (typeof dest === "string" || isValidExplicitDestination(dest)) {
357
- this.goToDestination(dest);
358
- return;
359
- }
360
-
361
- console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not ` + "a valid destination.");
362
- }
363
- }
364
- /**
365
- * @param {string} action
366
- */
367
-
368
-
369
- executeNamedAction(action) {
370
- // See PDF reference, table 8.45 - Named action
371
- switch (action) {
372
- case "GoBack":
373
- if (this.pdfHistory) {
374
- this.pdfHistory.back();
375
- }
376
-
377
- break;
378
-
379
- case "GoForward":
380
- if (this.pdfHistory) {
381
- this.pdfHistory.forward();
382
- }
383
-
384
- break;
385
-
386
- case "NextPage":
387
- this.pdfViewer.nextPage();
388
- break;
389
-
390
- case "PrevPage":
391
- this.pdfViewer.previousPage();
392
- break;
393
-
394
- case "LastPage":
395
- this.page = this.pagesCount;
396
- break;
397
-
398
- case "FirstPage":
399
- this.page = 1;
400
- break;
401
- // No action according to spec
402
- }
403
-
404
- this.eventBus.dispatch("namedaction", {
405
- source: this,
406
- action
407
- });
408
- }
409
- /**
410
- * @param {number} pageNum - page number.
411
- * @param {Object} pageRef - reference to the page.
412
- */
413
-
414
-
415
- cachePageRef(pageNum, pageRef) {
416
- if (!pageRef) {
417
- return;
418
- }
419
-
420
- const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;
421
- this._pagesRefCache[refStr] = pageNum;
422
- }
423
- /**
424
- * @private
425
- */
426
-
427
-
428
- _cachedPageNumber(pageRef) {
429
- var _this$_pagesRefCache;
430
-
431
- const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;
432
- return ((_this$_pagesRefCache = this._pagesRefCache) === null || _this$_pagesRefCache === void 0 ? void 0 : _this$_pagesRefCache[refStr]) || null;
433
- }
434
- /**
435
- * @param {number} pageNumber
436
- */
437
-
438
-
439
- isPageVisible(pageNumber) {
440
- return this.pdfViewer.isPageVisible(pageNumber);
441
- }
442
- /**
443
- * @param {number} pageNumber
444
- */
445
-
446
-
447
- isPageCached(pageNumber) {
448
- return this.pdfViewer.isPageCached(pageNumber);
449
- }
450
-
451
- }
452
-
453
- function isValidExplicitDestination(dest) {
454
- if (!Array.isArray(dest)) {
455
- return false;
456
- }
457
-
458
- const destLength = dest.length;
459
-
460
- if (destLength < 2) {
461
- return false;
462
- }
463
-
464
- const page = dest[0];
465
-
466
- if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) {
467
- return false;
468
- }
469
-
470
- const zoom = dest[1];
471
-
472
- if (!(typeof zoom === "object" && typeof zoom.name === "string")) {
473
- return false;
474
- }
475
-
476
- let allowNull = true;
477
-
478
- switch (zoom.name) {
479
- case "XYZ":
480
- if (destLength !== 5) {
481
- return false;
482
- }
483
-
484
- break;
485
-
486
- case "Fit":
487
- case "FitB":
488
- return destLength === 2;
489
-
490
- case "FitH":
491
- case "FitBH":
492
- case "FitV":
493
- case "FitBV":
494
- if (destLength !== 3) {
495
- return false;
496
- }
497
-
498
- break;
499
-
500
- case "FitR":
501
- if (destLength !== 6) {
502
- return false;
503
- }
504
-
505
- allowNull = false;
506
- break;
507
-
508
- default:
509
- return false;
510
- }
511
-
512
- for (let i = 2; i < destLength; i++) {
513
- const param = dest[i];
514
-
515
- if (!(typeof param === "number" || allowNull && param === null)) {
516
- return false;
517
- }
518
- }
519
-
520
- return true;
521
- }
522
- /**
523
- * @implements {IPDFLinkService}
524
- */
525
-
526
-
527
- class SimpleLinkService {
528
- constructor() {
529
- this.externalLinkTarget = null;
530
- this.externalLinkRel = null;
531
- this.externalLinkEnabled = true;
532
- this._ignoreDestinationZoom = false;
533
- }
534
- /**
535
- * @type {number}
536
- */
537
-
538
-
539
- get pagesCount() {
540
- return 0;
541
- }
542
- /**
543
- * @type {number}
544
- */
545
-
546
-
547
- get page() {
548
- return 0;
549
- }
550
- /**
551
- * @param {number} value
552
- */
553
-
554
-
555
- set page(value) {}
556
- /**
557
- * @type {number}
558
- */
559
-
560
-
561
- get rotation() {
562
- return 0;
563
- }
564
- /**
565
- * @param {number} value
566
- */
567
-
568
-
569
- set rotation(value) {}
570
- /**
571
- * @param {string|Array} dest - The named, or explicit, PDF destination.
572
- */
573
-
574
-
575
- async goToDestination(dest) {}
576
- /**
577
- * @param {number|string} val - The page number, or page label.
578
- */
579
-
580
-
581
- goToPage(val) {}
582
- /**
583
- * @param dest - The PDF destination object.
584
- * @returns {string} The hyperlink to the PDF object.
585
- */
586
-
587
-
588
- getDestinationHash(dest) {
589
- return "#";
590
- }
591
- /**
592
- * @param hash - The PDF parameters/hash.
593
- * @returns {string} The hyperlink to the PDF object.
594
- */
595
-
596
-
597
- getAnchorUrl(hash) {
598
- return "#";
599
- }
600
- /**
601
- * @param {string} hash
602
- */
603
-
604
-
605
- setHash(hash) {}
606
- /**
607
- * @param {string} action
608
- */
609
-
610
-
611
- executeNamedAction(action) {}
612
- /**
613
- * @param {number} pageNum - page number.
614
- * @param {Object} pageRef - reference to the page.
615
- */
616
-
617
-
618
- cachePageRef(pageNum, pageRef) {}
619
- /**
620
- * @param {number} pageNumber
621
- */
622
-
623
-
624
- isPageVisible(pageNumber) {
625
- return true;
626
- }
627
- /**
628
- * @param {number} pageNumber
629
- */
630
-
631
-
632
- isPageCached(pageNumber) {
633
- return true;
634
- }
635
-
636
- }
637
-
638
- export { PDFLinkService, SimpleLinkService };
1
+ import { parseQueryString } from './ui_utils.js';
2
+
3
+ /* Copyright 2015 Mozilla Foundation
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ const DEFAULT_LINK_REL = "noopener noreferrer nofollow";
19
+ const LinkTarget = {
20
+ NONE: 0,
21
+ // Default value.
22
+ SELF: 1,
23
+ BLANK: 2,
24
+ PARENT: 3,
25
+ TOP: 4
26
+ };
27
+
28
+ /**
29
+ * @typedef {Object} PDFLinkServiceOptions
30
+ * @property {EventBus} eventBus - The application event bus.
31
+ * @property {number} [externalLinkTarget] - Specifies the `target` attribute
32
+ * for external links. Must use one of the values from {LinkTarget}.
33
+ * Defaults to using no target.
34
+ * @property {string} [externalLinkRel] - Specifies the `rel` attribute for
35
+ * external links. Defaults to stripping the referrer.
36
+ * @property {boolean} [ignoreDestinationZoom] - Ignores the zoom argument,
37
+ * thus preserving the current zoom level in the viewer, when navigating
38
+ * to internal destinations. The default value is `false`.
39
+ */
40
+
41
+ /**
42
+ * Performs navigation functions inside PDF, such as opening specified page,
43
+ * or destination.
44
+ * @implements {IPDFLinkService}
45
+ */
46
+ class PDFLinkService {
47
+ externalLinkEnabled = true;
48
+
49
+ /**
50
+ * @param {PDFLinkServiceOptions} options
51
+ */
52
+ constructor({
53
+ eventBus,
54
+ externalLinkTarget = null,
55
+ externalLinkRel = null,
56
+ ignoreDestinationZoom = false
57
+ } = {}) {
58
+ this.eventBus = eventBus;
59
+ this.externalLinkTarget = externalLinkTarget;
60
+ this.externalLinkRel = externalLinkRel;
61
+ this._ignoreDestinationZoom = ignoreDestinationZoom;
62
+ this.baseUrl = null;
63
+ this.pdfDocument = null;
64
+ this.pdfViewer = null;
65
+ this.pdfHistory = null;
66
+ }
67
+ setDocument(pdfDocument, baseUrl = null) {
68
+ this.baseUrl = baseUrl;
69
+ this.pdfDocument = pdfDocument;
70
+ }
71
+ setViewer(pdfViewer) {
72
+ this.pdfViewer = pdfViewer;
73
+ }
74
+ setHistory(pdfHistory) {
75
+ this.pdfHistory = pdfHistory;
76
+ }
77
+
78
+ /**
79
+ * @type {number}
80
+ */
81
+ get pagesCount() {
82
+ return this.pdfDocument ? this.pdfDocument.numPages : 0;
83
+ }
84
+
85
+ /**
86
+ * @type {number}
87
+ */
88
+ get page() {
89
+ return this.pdfDocument ? this.pdfViewer.currentPageNumber : 1;
90
+ }
91
+
92
+ /**
93
+ * @param {number} value
94
+ */
95
+ set page(value) {
96
+ if (this.pdfDocument) {
97
+ this.pdfViewer.currentPageNumber = value;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * @type {number}
103
+ */
104
+ get rotation() {
105
+ return this.pdfDocument ? this.pdfViewer.pagesRotation : 0;
106
+ }
107
+
108
+ /**
109
+ * @param {number} value
110
+ */
111
+ set rotation(value) {
112
+ if (this.pdfDocument) {
113
+ this.pdfViewer.pagesRotation = value;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * @type {boolean}
119
+ */
120
+ get isInPresentationMode() {
121
+ return this.pdfDocument ? this.pdfViewer.isInPresentationMode : false;
122
+ }
123
+
124
+ /**
125
+ * This method will, when available, also update the browser history.
126
+ *
127
+ * @param {string|Array} dest - The named, or explicit, PDF destination.
128
+ */
129
+ async goToDestination(dest) {
130
+ if (!this.pdfDocument) {
131
+ return;
132
+ }
133
+ let namedDest, explicitDest, pageNumber;
134
+ if (typeof dest === "string") {
135
+ namedDest = dest;
136
+ explicitDest = await this.pdfDocument.getDestination(dest);
137
+ } else {
138
+ namedDest = null;
139
+ explicitDest = await dest;
140
+ }
141
+ if (!Array.isArray(explicitDest)) {
142
+ console.error(`goToDestination: "${explicitDest}" is not a valid destination array, for dest="${dest}".`);
143
+ return;
144
+ }
145
+ // Dest array looks like that: <page-ref> </XYZ|/FitXXX> <args..>
146
+ const [destRef] = explicitDest;
147
+ if (destRef && typeof destRef === "object") {
148
+ pageNumber = this.pdfDocument.cachedPageNumber(destRef);
149
+ if (!pageNumber) {
150
+ // Fetch the page reference if it's not yet available. This could
151
+ // only occur during loading, before all pages have been resolved.
152
+ try {
153
+ pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
154
+ } catch {
155
+ console.error(`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`);
156
+ return;
157
+ }
158
+ }
159
+ } else if (Number.isInteger(destRef)) {
160
+ pageNumber = destRef + 1;
161
+ }
162
+ if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
163
+ console.error(`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`);
164
+ return;
165
+ }
166
+ if (this.pdfHistory) {
167
+ // Update the browser history before scrolling the new destination into
168
+ // view, to be able to accurately capture the current document position.
169
+ this.pdfHistory.pushCurrentPosition();
170
+ this.pdfHistory.push({
171
+ namedDest,
172
+ explicitDest,
173
+ pageNumber
174
+ });
175
+ }
176
+ this.pdfViewer.scrollPageIntoView({
177
+ pageNumber,
178
+ destArray: explicitDest,
179
+ ignoreDestinationZoom: this._ignoreDestinationZoom
180
+ });
181
+ }
182
+
183
+ /**
184
+ * This method will, when available, also update the browser history.
185
+ *
186
+ * @param {number|string} val - The page number, or page label.
187
+ */
188
+ goToPage(val) {
189
+ if (!this.pdfDocument) {
190
+ return;
191
+ }
192
+ const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0;
193
+ if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
194
+ console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`);
195
+ return;
196
+ }
197
+ if (this.pdfHistory) {
198
+ // Update the browser history before scrolling the new page into view,
199
+ // to be able to accurately capture the current document position.
200
+ this.pdfHistory.pushCurrentPosition();
201
+ this.pdfHistory.pushPage(pageNumber);
202
+ }
203
+ this.pdfViewer.scrollPageIntoView({
204
+ pageNumber
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Adds various attributes (href, title, target, rel) to hyperlinks.
210
+ * @param {HTMLAnchorElement} link
211
+ * @param {string} url
212
+ * @param {boolean} [newWindow]
213
+ */
214
+ addLinkAttributes(link, url, newWindow = false) {
215
+ if (!url || typeof url !== "string") {
216
+ throw new Error('A valid "url" parameter must provided.');
217
+ }
218
+ const target = newWindow ? LinkTarget.BLANK : this.externalLinkTarget,
219
+ rel = this.externalLinkRel;
220
+ if (this.externalLinkEnabled) {
221
+ link.href = link.title = url;
222
+ } else {
223
+ link.href = "";
224
+ link.title = `Disabled: ${url}`;
225
+ link.onclick = () => false;
226
+ }
227
+ let targetStr = ""; // LinkTarget.NONE
228
+ switch (target) {
229
+ case LinkTarget.NONE:
230
+ break;
231
+ case LinkTarget.SELF:
232
+ targetStr = "_self";
233
+ break;
234
+ case LinkTarget.BLANK:
235
+ targetStr = "_blank";
236
+ break;
237
+ case LinkTarget.PARENT:
238
+ targetStr = "_parent";
239
+ break;
240
+ case LinkTarget.TOP:
241
+ targetStr = "_top";
242
+ break;
243
+ }
244
+ link.target = targetStr;
245
+ link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
246
+ }
247
+
248
+ /**
249
+ * @param {string|Array} dest - The PDF destination object.
250
+ * @returns {string} The hyperlink to the PDF object.
251
+ */
252
+ getDestinationHash(dest) {
253
+ if (typeof dest === "string") {
254
+ if (dest.length > 0) {
255
+ return this.getAnchorUrl("#" + escape(dest));
256
+ }
257
+ } else if (Array.isArray(dest)) {
258
+ const str = JSON.stringify(dest);
259
+ if (str.length > 0) {
260
+ return this.getAnchorUrl("#" + escape(str));
261
+ }
262
+ }
263
+ return this.getAnchorUrl("");
264
+ }
265
+
266
+ /**
267
+ * Prefix the full url on anchor links to make sure that links are resolved
268
+ * relative to the current URL instead of the one defined in <base href>.
269
+ * @param {string} anchor - The anchor hash, including the #.
270
+ * @returns {string} The hyperlink to the PDF object.
271
+ */
272
+ getAnchorUrl(anchor) {
273
+ return this.baseUrl ? this.baseUrl + anchor : anchor;
274
+ }
275
+
276
+ /**
277
+ * @param {string} hash
278
+ */
279
+ setHash(hash) {
280
+ if (!this.pdfDocument) {
281
+ return;
282
+ }
283
+ let pageNumber, dest;
284
+ if (hash.includes("=")) {
285
+ const params = parseQueryString(hash);
286
+ if (params.has("search")) {
287
+ const query = params.get("search").replaceAll('"', ""),
288
+ phrase = params.get("phrase") === "true";
289
+ this.eventBus.dispatch("findfromurlhash", {
290
+ source: this,
291
+ query: phrase ? query : query.match(/\S+/g)
292
+ });
293
+ }
294
+ // borrowing syntax from "Parameters for Opening PDF Files"
295
+ if (params.has("page")) {
296
+ pageNumber = params.get("page") | 0 || 1;
297
+ }
298
+ if (params.has("zoom")) {
299
+ // Build the destination array.
300
+ const zoomArgs = params.get("zoom").split(","); // scale,left,top
301
+ const zoomArg = zoomArgs[0];
302
+ const zoomArgNumber = parseFloat(zoomArg);
303
+ if (!zoomArg.includes("Fit")) {
304
+ // If the zoomArg is a number, it has to get divided by 100. If it's
305
+ // a string, it should stay as it is.
306
+ dest = [null, {
307
+ name: "XYZ"
308
+ }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg];
309
+ } else if (zoomArg === "Fit" || zoomArg === "FitB") {
310
+ dest = [null, {
311
+ name: zoomArg
312
+ }];
313
+ } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") {
314
+ dest = [null, {
315
+ name: zoomArg
316
+ }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null];
317
+ } else if (zoomArg === "FitR") {
318
+ if (zoomArgs.length !== 5) {
319
+ console.error('PDFLinkService.setHash: Not enough parameters for "FitR".');
320
+ } else {
321
+ dest = [null, {
322
+ name: zoomArg
323
+ }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0];
324
+ }
325
+ } else {
326
+ console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`);
327
+ }
328
+ }
329
+ if (dest) {
330
+ this.pdfViewer.scrollPageIntoView({
331
+ pageNumber: pageNumber || this.page,
332
+ destArray: dest,
333
+ allowNegativeOffset: true
334
+ });
335
+ } else if (pageNumber) {
336
+ this.page = pageNumber; // simple page
337
+ }
338
+ if (params.has("pagemode")) {
339
+ this.eventBus.dispatch("pagemode", {
340
+ source: this,
341
+ mode: params.get("pagemode")
342
+ });
343
+ }
344
+ // Ensure that this parameter is *always* handled last, in order to
345
+ // guarantee that it won't be overridden (e.g. by the "page" parameter).
346
+ if (params.has("nameddest")) {
347
+ this.goToDestination(params.get("nameddest"));
348
+ }
349
+ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
350
+ return;
351
+ }
352
+ // Support opening of PDF attachments in the Firefox PDF Viewer,
353
+ // which uses a couple of non-standard hash parameters; refer to
354
+ // `DownloadManager.openOrDownloadData` in the firefoxcom.js file.
355
+ if (!params.has("filename") || !params.has("filedest")) {
356
+ return;
357
+ }
358
+ hash = params.get("filedest");
359
+ }
360
+
361
+ // Named (or explicit) destination.
362
+ dest = unescape(hash);
363
+ try {
364
+ dest = JSON.parse(dest);
365
+ if (!Array.isArray(dest)) {
366
+ // Avoid incorrectly rejecting a valid named destination, such as
367
+ // e.g. "4.3" or "true", because `JSON.parse` converted its type.
368
+ dest = dest.toString();
369
+ }
370
+ } catch {}
371
+ if (typeof dest === "string" || PDFLinkService.#isValidExplicitDest(dest)) {
372
+ this.goToDestination(dest);
373
+ return;
374
+ }
375
+ console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`);
376
+ }
377
+
378
+ /**
379
+ * @param {string} action
380
+ */
381
+ executeNamedAction(action) {
382
+ var _this$pdfHistory, _this$pdfHistory2;
383
+ if (!this.pdfDocument) {
384
+ return;
385
+ }
386
+ // See PDF reference, table 8.45 - Named action
387
+ switch (action) {
388
+ case "GoBack":
389
+ (_this$pdfHistory = this.pdfHistory) === null || _this$pdfHistory === void 0 ? void 0 : _this$pdfHistory.back();
390
+ break;
391
+ case "GoForward":
392
+ (_this$pdfHistory2 = this.pdfHistory) === null || _this$pdfHistory2 === void 0 ? void 0 : _this$pdfHistory2.forward();
393
+ break;
394
+ case "NextPage":
395
+ this.pdfViewer.nextPage();
396
+ break;
397
+ case "PrevPage":
398
+ this.pdfViewer.previousPage();
399
+ break;
400
+ case "LastPage":
401
+ this.page = this.pagesCount;
402
+ break;
403
+ case "FirstPage":
404
+ this.page = 1;
405
+ break;
406
+ // No action according to spec
407
+ }
408
+ this.eventBus.dispatch("namedaction", {
409
+ source: this,
410
+ action
411
+ });
412
+ }
413
+
414
+ /**
415
+ * @param {Object} action
416
+ */
417
+ async executeSetOCGState(action) {
418
+ if (!this.pdfDocument) {
419
+ return;
420
+ }
421
+ const pdfDocument = this.pdfDocument,
422
+ optionalContentConfig = await this.pdfViewer.optionalContentConfigPromise;
423
+ if (pdfDocument !== this.pdfDocument) {
424
+ return; // The document was closed while the optional content resolved.
425
+ }
426
+ optionalContentConfig.setOCGState(action);
427
+ this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig);
428
+ }
429
+ static #isValidExplicitDest(dest) {
430
+ if (!Array.isArray(dest) || dest.length < 2) {
431
+ return false;
432
+ }
433
+ const [page, zoom, ...args] = dest;
434
+ if (!(typeof page === "object" && Number.isInteger(page === null || page === void 0 ? void 0 : page.num) && Number.isInteger(page === null || page === void 0 ? void 0 : page.gen)) && !Number.isInteger(page)) {
435
+ return false;
436
+ }
437
+ if (!(typeof zoom === "object" && typeof (zoom === null || zoom === void 0 ? void 0 : zoom.name) === "string")) {
438
+ return false;
439
+ }
440
+ let allowNull = true;
441
+ switch (zoom.name) {
442
+ case "XYZ":
443
+ if (args.length !== 3) {
444
+ return false;
445
+ }
446
+ break;
447
+ case "Fit":
448
+ case "FitB":
449
+ return args.length === 0;
450
+ case "FitH":
451
+ case "FitBH":
452
+ case "FitV":
453
+ case "FitBV":
454
+ if (args.length !== 1) {
455
+ return false;
456
+ }
457
+ break;
458
+ case "FitR":
459
+ if (args.length !== 4) {
460
+ return false;
461
+ }
462
+ allowNull = false;
463
+ break;
464
+ default:
465
+ return false;
466
+ }
467
+ for (const arg of args) {
468
+ if (!(typeof arg === "number" || allowNull && arg === null)) {
469
+ return false;
470
+ }
471
+ }
472
+ return true;
473
+ }
474
+ }
475
+
476
+ /**
477
+ * @implements {IPDFLinkService}
478
+ */
479
+ class SimpleLinkService extends PDFLinkService {
480
+ setDocument(pdfDocument, baseUrl = null) {}
481
+ }
482
+
483
+ export { LinkTarget, PDFLinkService, SimpleLinkService };