@vaadin-component-factory/vcf-pdf-viewer 3.0.2 → 3.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,7 +1,6 @@
1
- import { getOutputScale, watchScroll, getVisibleElements, scrollIntoView, isValidRotation } from './ui_utils.js';
1
+ import { RenderingStates, OutputScale, watchScroll, getVisibleElements, scrollIntoView, isValidRotation } from './ui_utils.js';
2
2
  import './pdf.js';
3
- import { RenderingStates } from './pdf_rendering_queue.js';
4
- import { R as RenderingCancelledException } from './display_utils.js';
3
+ import { R as RenderingCancelledException } from './node_stream2.js';
5
4
  import './util.js';
6
5
  import './message_handler.js';
7
6
 
@@ -20,15 +19,13 @@ import './message_handler.js';
20
19
  * limitations under the License.
21
20
  */
22
21
  const DRAW_UPSCALE_FACTOR = 2; // See comment in `PDFThumbnailView.draw` below.
23
-
24
22
  const MAX_NUM_SCALING_STEPS = 3;
25
- const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
26
-
27
23
  const THUMBNAIL_WIDTH = 98; // px
28
24
 
29
25
  /**
30
26
  * @typedef {Object} PDFThumbnailViewOptions
31
27
  * @property {HTMLDivElement} container - The viewer element.
28
+ * @property {EventBus} eventBus - The application event bus.
32
29
  * @property {number} id - The thumbnail's unique ID (normally its number).
33
30
  * @property {PageViewport} defaultViewport - The page viewport.
34
31
  * @property {Promise<OptionalContentConfig>} [optionalContentConfigPromise] -
@@ -36,72 +33,57 @@ const THUMBNAIL_WIDTH = 98; // px
36
33
  * The default value is `null`.
37
34
  * @property {IPDFLinkService} linkService - The navigation/linking service.
38
35
  * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
39
- * @property {function} checkSetImageDisabled
40
- * @property {IL10n} l10n - Localization service.
36
+ * @property {Object} [pageColors] - Overwrites background and foreground colors
37
+ * with user defined ones in order to improve readability in high contrast
38
+ * mode.
41
39
  */
42
40
 
43
- const TempImageFactory = function TempImageFactoryClosure() {
44
- let tempCanvasCache = null;
45
- return {
46
- getCanvas(width, height) {
47
- let tempCanvas = tempCanvasCache;
48
-
49
- if (!tempCanvas) {
50
- tempCanvas = document.createElement("canvas");
51
- tempCanvasCache = tempCanvas;
52
- }
53
-
54
- tempCanvas.width = width;
55
- tempCanvas.height = height; // Since this is a temporary canvas, we need to fill it with a white
56
- // background ourselves. `_getPageDrawContext` uses CSS rules for this.
57
-
58
- if (typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL || GENERIC")) {
59
- tempCanvas.mozOpaque = true;
60
- }
61
-
62
- const ctx = tempCanvas.getContext("2d", {
63
- alpha: false
64
- });
65
- ctx.save();
66
- ctx.fillStyle = "rgb(255, 255, 255)";
67
- ctx.fillRect(0, 0, width, height);
68
- ctx.restore();
69
- return [tempCanvas, tempCanvas.getContext("2d")];
70
- },
71
-
72
- destroyCanvas() {
73
- const tempCanvas = tempCanvasCache;
74
-
75
- if (tempCanvas) {
76
- // Zeroing the width and height causes Firefox to release graphics
77
- // resources immediately, which can greatly reduce memory consumption.
78
- tempCanvas.width = 0;
79
- tempCanvas.height = 0;
80
- }
41
+ class TempImageFactory {
42
+ static #tempCanvas = null;
43
+ static getCanvas(width, height) {
44
+ const tempCanvas = this.#tempCanvas || (this.#tempCanvas = document.createElement("canvas"));
45
+ tempCanvas.width = width;
46
+ tempCanvas.height = height;
81
47
 
82
- tempCanvasCache = null;
48
+ // Since this is a temporary canvas, we need to fill it with a white
49
+ // background ourselves. `#getPageDrawContext` uses CSS rules for this.
50
+ const ctx = tempCanvas.getContext("2d", {
51
+ alpha: false
52
+ });
53
+ ctx.save();
54
+ ctx.fillStyle = "rgb(255, 255, 255)";
55
+ ctx.fillRect(0, 0, width, height);
56
+ ctx.restore();
57
+ return [tempCanvas, tempCanvas.getContext("2d")];
58
+ }
59
+ static destroyCanvas() {
60
+ const tempCanvas = this.#tempCanvas;
61
+ if (tempCanvas) {
62
+ // Zeroing the width and height causes Firefox to release graphics
63
+ // resources immediately, which can greatly reduce memory consumption.
64
+ tempCanvas.width = 0;
65
+ tempCanvas.height = 0;
83
66
  }
67
+ this.#tempCanvas = null;
68
+ }
69
+ }
84
70
 
85
- };
86
- }();
87
71
  /**
88
72
  * @implements {IRenderableView}
89
73
  */
90
-
91
-
92
74
  class PDFThumbnailView {
93
75
  /**
94
76
  * @param {PDFThumbnailViewOptions} options
95
77
  */
96
78
  constructor({
97
79
  container,
80
+ eventBus,
98
81
  id,
99
82
  defaultViewport,
100
83
  optionalContentConfigPromise,
101
84
  linkService,
102
85
  renderingQueue,
103
- checkSetImageDisabled,
104
- l10n
86
+ pageColors
105
87
  }) {
106
88
  this.id = id;
107
89
  this.renderingId = "thumbnail" + id;
@@ -111,51 +93,49 @@ class PDFThumbnailView {
111
93
  this.viewport = defaultViewport;
112
94
  this.pdfPageRotate = defaultViewport.rotation;
113
95
  this._optionalContentConfigPromise = optionalContentConfigPromise || null;
96
+ this.pageColors = pageColors || null;
97
+ this.eventBus = eventBus;
114
98
  this.linkService = linkService;
115
99
  this.renderingQueue = renderingQueue;
116
100
  this.renderTask = null;
117
101
  this.renderingState = RenderingStates.INITIAL;
118
102
  this.resume = null;
119
-
120
- this._checkSetImageDisabled = checkSetImageDisabled || function () {
121
- return false;
122
- };
123
-
124
- const pageWidth = this.viewport.width,
125
- pageHeight = this.viewport.height,
126
- pageRatio = pageWidth / pageHeight;
127
- this.canvasWidth = THUMBNAIL_WIDTH;
128
- this.canvasHeight = this.canvasWidth / pageRatio | 0;
129
- this.scale = this.canvasWidth / pageWidth;
130
- this.l10n = l10n;
131
103
  const anchor = document.createElement("a");
132
104
  anchor.href = linkService.getAnchorUrl("#page=" + id);
133
-
134
- this._thumbPageTitle.then(msg => {
135
- anchor.title = msg;
136
- });
137
-
105
+ anchor.setAttribute("data-l10n-id", "pdfjs-thumb-page-title");
106
+ anchor.setAttribute("data-l10n-args", this.#pageL10nArgs);
138
107
  anchor.onclick = function () {
139
108
  linkService.goToPage(id);
140
109
  return false;
141
110
  };
142
-
143
111
  this.anchor = anchor;
144
112
  const div = document.createElement("div");
145
113
  div.className = "thumbnail";
146
114
  div.setAttribute("data-page-number", this.id);
147
115
  this.div = div;
148
- const ring = document.createElement("div");
149
- ring.className = "thumbnailSelectionRing";
150
- const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
151
- ring.style.width = this.canvasWidth + borderAdjustment + "px";
152
- ring.style.height = this.canvasHeight + borderAdjustment + "px";
153
- this.ring = ring;
154
- div.appendChild(ring);
155
- anchor.appendChild(div);
156
- container.appendChild(anchor);
116
+ this.#updateDims();
117
+ const img = document.createElement("div");
118
+ img.className = "thumbnailImage";
119
+ this._placeholderImg = img;
120
+ div.append(img);
121
+ anchor.append(div);
122
+ container.append(anchor);
123
+ }
124
+ #updateDims() {
125
+ const {
126
+ width,
127
+ height
128
+ } = this.viewport;
129
+ const ratio = width / height;
130
+ this.canvasWidth = THUMBNAIL_WIDTH;
131
+ this.canvasHeight = this.canvasWidth / ratio | 0;
132
+ this.scale = this.canvasWidth / width;
133
+ const {
134
+ style
135
+ } = this.div;
136
+ style.setProperty("--thumbnail-width", `${this.canvasWidth}px`);
137
+ style.setProperty("--thumbnail-height", `${this.canvasHeight}px`);
157
138
  }
158
-
159
139
  setPdfPage(pdfPage) {
160
140
  this.pdfPage = pdfPage;
161
141
  this.pdfPageRotate = pdfPage.rotate;
@@ -166,42 +146,24 @@ class PDFThumbnailView {
166
146
  });
167
147
  this.reset();
168
148
  }
169
-
170
149
  reset() {
150
+ var _this$image;
171
151
  this.cancelRendering();
172
152
  this.renderingState = RenderingStates.INITIAL;
173
- const pageWidth = this.viewport.width,
174
- pageHeight = this.viewport.height,
175
- pageRatio = pageWidth / pageHeight;
176
- this.canvasHeight = this.canvasWidth / pageRatio | 0;
177
- this.scale = this.canvasWidth / pageWidth;
178
153
  this.div.removeAttribute("data-loaded");
179
- const ring = this.ring;
180
- ring.textContent = ""; // Remove the thumbnail from the DOM.
181
-
182
- const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
183
- ring.style.width = this.canvasWidth + borderAdjustment + "px";
184
- ring.style.height = this.canvasHeight + borderAdjustment + "px";
185
-
186
- if (this.canvas) {
187
- // Zeroing the width and height causes Firefox to release graphics
188
- // resources immediately, which can greatly reduce memory consumption.
189
- this.canvas.width = 0;
190
- this.canvas.height = 0;
191
- delete this.canvas;
192
- }
193
-
154
+ (_this$image = this.image) === null || _this$image === void 0 ? void 0 : _this$image.replaceWith(this._placeholderImg);
155
+ this.#updateDims();
194
156
  if (this.image) {
195
157
  this.image.removeAttribute("src");
196
158
  delete this.image;
197
159
  }
198
160
  }
199
-
200
- update(rotation) {
201
- if (typeof rotation !== "undefined") {
202
- this.rotation = rotation;
161
+ update({
162
+ rotation = null
163
+ }) {
164
+ if (typeof rotation === "number") {
165
+ this.rotation = rotation; // The rotation may be zero.
203
166
  }
204
-
205
167
  const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
206
168
  this.viewport = this.viewport.clone({
207
169
  scale: 1,
@@ -209,38 +171,26 @@ class PDFThumbnailView {
209
171
  });
210
172
  this.reset();
211
173
  }
174
+
212
175
  /**
213
176
  * PLEASE NOTE: Most likely you want to use the `this.reset()` method,
214
177
  * rather than calling this one directly.
215
178
  */
216
-
217
-
218
179
  cancelRendering() {
219
180
  if (this.renderTask) {
220
181
  this.renderTask.cancel();
221
182
  this.renderTask = null;
222
183
  }
223
-
224
184
  this.resume = null;
225
185
  }
226
- /**
227
- * @private
228
- */
229
-
230
-
231
- _getPageDrawContext(upscaleFactor = 1) {
186
+ #getPageDrawContext(upscaleFactor = 1) {
232
187
  // Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
233
188
  // until rendering/image conversion is complete, to avoid display issues.
234
189
  const canvas = document.createElement("canvas");
235
-
236
- if (typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL || GENERIC")) {
237
- canvas.mozOpaque = true;
238
- }
239
-
240
190
  const ctx = canvas.getContext("2d", {
241
191
  alpha: false
242
192
  });
243
- const outputScale = getOutputScale(ctx);
193
+ const outputScale = new OutputScale();
244
194
  canvas.width = upscaleFactor * this.canvasWidth * outputScale.sx | 0;
245
195
  canvas.height = upscaleFactor * this.canvasHeight * outputScale.sy | 0;
246
196
  const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
@@ -250,238 +200,169 @@ class PDFThumbnailView {
250
200
  transform
251
201
  };
252
202
  }
253
- /**
254
- * @private
255
- */
256
-
257
-
258
- _convertCanvasToImage(canvas) {
203
+ #convertCanvasToImage(canvas) {
259
204
  if (this.renderingState !== RenderingStates.FINISHED) {
260
- throw new Error("_convertCanvasToImage: Rendering has not finished.");
205
+ throw new Error("#convertCanvasToImage: Rendering has not finished.");
261
206
  }
262
-
263
- const reducedCanvas = this._reduceImage(canvas);
264
-
207
+ const reducedCanvas = this.#reduceImage(canvas);
265
208
  const image = document.createElement("img");
266
209
  image.className = "thumbnailImage";
267
-
268
- this._thumbPageCanvas.then(msg => {
269
- image.setAttribute("aria-label", msg);
270
- });
271
-
272
- image.style.width = this.canvasWidth + "px";
273
- image.style.height = this.canvasHeight + "px";
210
+ image.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas");
211
+ image.setAttribute("data-l10n-args", this.#pageL10nArgs);
274
212
  image.src = reducedCanvas.toDataURL();
275
213
  this.image = image;
276
214
  this.div.setAttribute("data-loaded", true);
277
- this.ring.appendChild(image); // Zeroing the width and height causes Firefox to release graphics
278
- // resources immediately, which can greatly reduce memory consumption.
215
+ this._placeholderImg.replaceWith(image);
279
216
 
217
+ // Zeroing the width and height causes Firefox to release graphics
218
+ // resources immediately, which can greatly reduce memory consumption.
280
219
  reducedCanvas.width = 0;
281
220
  reducedCanvas.height = 0;
282
221
  }
283
-
284
- draw() {
222
+ async #finishRenderTask(renderTask, canvas, error = null) {
223
+ // The renderTask may have been replaced by a new one, so only remove
224
+ // the reference to the renderTask if it matches the one that is
225
+ // triggering this callback.
226
+ if (renderTask === this.renderTask) {
227
+ this.renderTask = null;
228
+ }
229
+ if (error instanceof RenderingCancelledException) {
230
+ return;
231
+ }
232
+ this.renderingState = RenderingStates.FINISHED;
233
+ this.#convertCanvasToImage(canvas);
234
+ if (error) {
235
+ throw error;
236
+ }
237
+ }
238
+ async draw() {
285
239
  if (this.renderingState !== RenderingStates.INITIAL) {
286
240
  console.error("Must be in new state before drawing");
287
- return Promise.resolve(undefined);
241
+ return undefined;
288
242
  }
289
-
290
243
  const {
291
244
  pdfPage
292
245
  } = this;
293
-
294
246
  if (!pdfPage) {
295
247
  this.renderingState = RenderingStates.FINISHED;
296
- return Promise.reject(new Error("pdfPage is not loaded"));
248
+ throw new Error("pdfPage is not loaded");
297
249
  }
298
-
299
250
  this.renderingState = RenderingStates.RUNNING;
300
251
 
301
- const finishRenderTask = async (error = null) => {
302
- // The renderTask may have been replaced by a new one, so only remove
303
- // the reference to the renderTask if it matches the one that is
304
- // triggering this callback.
305
- if (renderTask === this.renderTask) {
306
- this.renderTask = null;
307
- }
308
-
309
- if (error instanceof RenderingCancelledException) {
310
- return;
311
- }
312
-
313
- this.renderingState = RenderingStates.FINISHED;
314
-
315
- this._convertCanvasToImage(canvas);
316
-
317
- if (error) {
318
- throw error;
319
- }
320
- }; // Render the thumbnail at a larger size and downsize the canvas (similar
252
+ // Render the thumbnail at a larger size and downsize the canvas (similar
321
253
  // to `setImage`), to improve consistency between thumbnails created by
322
254
  // the `draw` and `setImage` methods (fixes issue 8233).
323
255
  // NOTE: To primarily avoid increasing memory usage too much, but also to
324
256
  // reduce downsizing overhead, we purposely limit the up-scaling factor.
325
-
326
-
327
257
  const {
328
258
  ctx,
329
259
  canvas,
330
260
  transform
331
- } = this._getPageDrawContext(DRAW_UPSCALE_FACTOR);
332
-
261
+ } = this.#getPageDrawContext(DRAW_UPSCALE_FACTOR);
333
262
  const drawViewport = this.viewport.clone({
334
263
  scale: DRAW_UPSCALE_FACTOR * this.scale
335
264
  });
336
-
337
265
  const renderContinueCallback = cont => {
338
266
  if (!this.renderingQueue.isHighestPriority(this)) {
339
267
  this.renderingState = RenderingStates.PAUSED;
340
-
341
268
  this.resume = () => {
342
269
  this.renderingState = RenderingStates.RUNNING;
343
270
  cont();
344
271
  };
345
-
346
272
  return;
347
273
  }
348
-
349
274
  cont();
350
275
  };
351
-
352
276
  const renderContext = {
353
277
  canvasContext: ctx,
354
278
  transform,
355
279
  viewport: drawViewport,
356
- optionalContentConfigPromise: this._optionalContentConfigPromise
280
+ optionalContentConfigPromise: this._optionalContentConfigPromise,
281
+ pageColors: this.pageColors
357
282
  };
358
283
  const renderTask = this.renderTask = pdfPage.render(renderContext);
359
284
  renderTask.onContinue = renderContinueCallback;
360
- const resultPromise = renderTask.promise.then(function () {
361
- return finishRenderTask(null);
362
- }, function (error) {
363
- return finishRenderTask(error);
364
- });
285
+ const resultPromise = renderTask.promise.then(() => this.#finishRenderTask(renderTask, canvas), error => this.#finishRenderTask(renderTask, canvas, error));
365
286
  resultPromise.finally(() => {
366
287
  // Zeroing the width and height causes Firefox to release graphics
367
288
  // resources immediately, which can greatly reduce memory consumption.
368
289
  canvas.width = 0;
369
- canvas.height = 0; // Only trigger cleanup, once rendering has finished, when the current
370
- // pageView is *not* cached on the `BaseViewer`-instance.
371
-
372
- const pageCached = this.linkService.isPageCached(this.id);
373
-
374
- if (!pageCached) {
375
- var _this$pdfPage;
376
-
377
- (_this$pdfPage = this.pdfPage) === null || _this$pdfPage === void 0 ? void 0 : _this$pdfPage.cleanup();
378
- }
290
+ canvas.height = 0;
291
+ this.eventBus.dispatch("thumbnailrendered", {
292
+ source: this,
293
+ pageNumber: this.id,
294
+ pdfPage: this.pdfPage
295
+ });
379
296
  });
380
297
  return resultPromise;
381
298
  }
382
-
383
299
  setImage(pageView) {
384
- if (this._checkSetImageDisabled()) {
385
- return;
386
- }
387
-
388
300
  if (this.renderingState !== RenderingStates.INITIAL) {
389
301
  return;
390
302
  }
391
-
392
303
  const {
393
- canvas,
394
- pdfPage
304
+ thumbnailCanvas: canvas,
305
+ pdfPage,
306
+ scale
395
307
  } = pageView;
396
-
397
308
  if (!canvas) {
398
309
  return;
399
310
  }
400
-
401
311
  if (!this.pdfPage) {
402
312
  this.setPdfPage(pdfPage);
403
313
  }
404
-
314
+ if (scale < this.scale) {
315
+ // Avoid upscaling the image, since that makes the thumbnail look blurry.
316
+ return;
317
+ }
405
318
  this.renderingState = RenderingStates.FINISHED;
406
-
407
- this._convertCanvasToImage(canvas);
319
+ this.#convertCanvasToImage(canvas);
408
320
  }
409
- /**
410
- * @private
411
- */
412
-
413
-
414
- _reduceImage(img) {
321
+ #reduceImage(img) {
415
322
  const {
416
323
  ctx,
417
324
  canvas
418
- } = this._getPageDrawContext();
419
-
325
+ } = this.#getPageDrawContext();
420
326
  if (img.width <= 2 * canvas.width) {
421
327
  ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
422
328
  return canvas;
423
- } // drawImage does an awful job of rescaling the image, doing it gradually.
424
-
425
-
329
+ }
330
+ // drawImage does an awful job of rescaling the image, doing it gradually.
426
331
  let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
427
332
  let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
428
333
  const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(reducedWidth, reducedHeight);
429
-
430
334
  while (reducedWidth > img.width || reducedHeight > img.height) {
431
335
  reducedWidth >>= 1;
432
336
  reducedHeight >>= 1;
433
337
  }
434
-
435
338
  reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight);
436
-
437
339
  while (reducedWidth > 2 * canvas.width) {
438
340
  reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1);
439
341
  reducedWidth >>= 1;
440
342
  reducedHeight >>= 1;
441
343
  }
442
-
443
344
  ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height);
444
345
  return canvas;
445
346
  }
446
-
447
- get _thumbPageTitle() {
347
+ get #pageL10nArgs() {
448
348
  var _this$pageLabel;
449
-
450
- return this.l10n.get("thumb_page_title", {
349
+ return JSON.stringify({
451
350
  page: (_this$pageLabel = this.pageLabel) !== null && _this$pageLabel !== void 0 ? _this$pageLabel : this.id
452
351
  });
453
352
  }
454
353
 
455
- get _thumbPageCanvas() {
456
- var _this$pageLabel2;
457
-
458
- return this.l10n.get("thumb_page_canvas", {
459
- page: (_this$pageLabel2 = this.pageLabel) !== null && _this$pageLabel2 !== void 0 ? _this$pageLabel2 : this.id
460
- });
461
- }
462
354
  /**
463
355
  * @param {string|null} label
464
356
  */
465
-
466
-
467
357
  setPageLabel(label) {
358
+ var _this$image2;
468
359
  this.pageLabel = typeof label === "string" ? label : null;
469
-
470
- this._thumbPageTitle.then(msg => {
471
- this.anchor.title = msg;
472
- });
473
-
360
+ this.anchor.setAttribute("data-l10n-args", this.#pageL10nArgs);
474
361
  if (this.renderingState !== RenderingStates.FINISHED) {
475
362
  return;
476
363
  }
477
-
478
- this._thumbPageCanvas.then(msg => {
479
- var _this$image;
480
-
481
- (_this$image = this.image) === null || _this$image === void 0 ? void 0 : _this$image.setAttribute("aria-label", msg);
482
- });
364
+ (_this$image2 = this.image) === null || _this$image2 === void 0 ? void 0 : _this$image2.setAttribute("data-l10n-args", this.#pageL10nArgs);
483
365
  }
484
-
485
366
  }
486
367
 
487
368
  /* Copyright 2012 Mozilla Foundation
@@ -500,6 +381,7 @@ class PDFThumbnailView {
500
381
  */
501
382
  const THUMBNAIL_SCROLL_MARGIN = -19;
502
383
  const THUMBNAIL_SELECTED_CLASS = "selected";
384
+
503
385
  /**
504
386
  * @typedef {Object} PDFThumbnailViewerOptions
505
387
  * @property {HTMLDivElement} container - The container for the thumbnail
@@ -507,15 +389,14 @@ const THUMBNAIL_SELECTED_CLASS = "selected";
507
389
  * @property {EventBus} eventBus - The application event bus.
508
390
  * @property {IPDFLinkService} linkService - The navigation/linking service.
509
391
  * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
510
- * @property {IL10n} l10n - Localization service.
392
+ * @property {Object} [pageColors] - Overwrites background and foreground colors
393
+ * with user defined ones in order to improve readability in high contrast
394
+ * mode.
511
395
  */
512
396
 
513
397
  /**
514
398
  * Viewer control to display thumbnails for pages in a PDF document.
515
- *
516
- * @implements {IRenderableView}
517
399
  */
518
-
519
400
  class PDFThumbnailViewer {
520
401
  /**
521
402
  * @param {PDFThumbnailViewerOptions} options
@@ -525,228 +406,174 @@ class PDFThumbnailViewer {
525
406
  eventBus,
526
407
  linkService,
527
408
  renderingQueue,
528
- l10n
409
+ pageColors
529
410
  }) {
530
411
  this.container = container;
412
+ this.eventBus = eventBus;
531
413
  this.linkService = linkService;
532
414
  this.renderingQueue = renderingQueue;
533
- this.l10n = l10n;
534
- this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));
535
-
536
- this._resetView();
537
-
538
- eventBus._on("optionalcontentconfigchanged", () => {
539
- // Ensure that the thumbnails always render with the *default* optional
540
- // content configuration.
541
- this._setImageDisabled = true;
542
- });
415
+ this.pageColors = pageColors || null;
416
+ this.scroll = watchScroll(this.container, this.#scrollUpdated.bind(this));
417
+ this.#resetView();
543
418
  }
544
- /**
545
- * @private
546
- */
547
-
548
-
549
- _scrollUpdated() {
419
+ #scrollUpdated() {
550
420
  this.renderingQueue.renderHighestPriority();
551
421
  }
552
-
553
422
  getThumbnail(index) {
554
423
  return this._thumbnails[index];
555
424
  }
556
- /**
557
- * @private
558
- */
559
-
560
-
561
- _getVisibleThumbs() {
425
+ #getVisibleThumbs() {
562
426
  return getVisibleElements({
563
427
  scrollEl: this.container,
564
428
  views: this._thumbnails
565
429
  });
566
430
  }
567
-
568
431
  scrollThumbnailIntoView(pageNumber) {
569
432
  if (!this.pdfDocument) {
570
433
  return;
571
434
  }
572
-
573
435
  const thumbnailView = this._thumbnails[pageNumber - 1];
574
-
575
436
  if (!thumbnailView) {
576
437
  console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.');
577
438
  return;
578
439
  }
579
-
580
440
  if (pageNumber !== this._currentPageNumber) {
581
- const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1]; // Remove the highlight from the previous thumbnail...
582
-
583
- prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS); // ... and add the highlight to the new thumbnail.
584
-
441
+ const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1];
442
+ // Remove the highlight from the previous thumbnail...
443
+ prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS);
444
+ // ... and add the highlight to the new thumbnail.
585
445
  thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS);
586
446
  }
447
+ const {
448
+ first,
449
+ last,
450
+ views
451
+ } = this.#getVisibleThumbs();
587
452
 
588
- const visibleThumbs = this._getVisibleThumbs();
589
-
590
- const numVisibleThumbs = visibleThumbs.views.length; // If the thumbnail isn't currently visible, scroll it into view.
591
-
592
- if (numVisibleThumbs > 0) {
593
- const first = visibleThumbs.first.id; // Account for only one thumbnail being visible.
594
-
595
- const last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first;
453
+ // If the thumbnail isn't currently visible, scroll it into view.
454
+ if (views.length > 0) {
596
455
  let shouldScroll = false;
597
-
598
- if (pageNumber <= first || pageNumber >= last) {
456
+ if (pageNumber <= first.id || pageNumber >= last.id) {
599
457
  shouldScroll = true;
600
458
  } else {
601
- visibleThumbs.views.some(function (view) {
602
- if (view.id !== pageNumber) {
603
- return false;
459
+ for (const {
460
+ id,
461
+ percent
462
+ } of views) {
463
+ if (id !== pageNumber) {
464
+ continue;
604
465
  }
605
-
606
- shouldScroll = view.percent < 100;
607
- return true;
608
- });
466
+ shouldScroll = percent < 100;
467
+ break;
468
+ }
609
469
  }
610
-
611
470
  if (shouldScroll) {
612
471
  scrollIntoView(thumbnailView.div, {
613
472
  top: THUMBNAIL_SCROLL_MARGIN
614
473
  });
615
474
  }
616
475
  }
617
-
618
476
  this._currentPageNumber = pageNumber;
619
477
  }
620
-
621
478
  get pagesRotation() {
622
479
  return this._pagesRotation;
623
480
  }
624
-
625
481
  set pagesRotation(rotation) {
626
482
  if (!isValidRotation(rotation)) {
627
483
  throw new Error("Invalid thumbnails rotation angle.");
628
484
  }
629
-
630
485
  if (!this.pdfDocument) {
631
486
  return;
632
487
  }
633
-
634
488
  if (this._pagesRotation === rotation) {
635
489
  return; // The rotation didn't change.
636
490
  }
637
-
638
491
  this._pagesRotation = rotation;
639
-
640
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
641
- this._thumbnails[i].update(rotation);
492
+ const updateArgs = {
493
+ rotation
494
+ };
495
+ for (const thumbnail of this._thumbnails) {
496
+ thumbnail.update(updateArgs);
642
497
  }
643
498
  }
644
-
645
499
  cleanup() {
646
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
647
- if (this._thumbnails[i] && this._thumbnails[i].renderingState !== RenderingStates.FINISHED) {
648
- this._thumbnails[i].reset();
500
+ for (const thumbnail of this._thumbnails) {
501
+ if (thumbnail.renderingState !== RenderingStates.FINISHED) {
502
+ thumbnail.reset();
649
503
  }
650
504
  }
651
-
652
505
  TempImageFactory.destroyCanvas();
653
506
  }
654
- /**
655
- * @private
656
- */
657
-
658
-
659
- _resetView() {
507
+ #resetView() {
660
508
  this._thumbnails = [];
661
509
  this._currentPageNumber = 1;
662
510
  this._pageLabels = null;
663
511
  this._pagesRotation = 0;
664
- this._optionalContentConfigPromise = null;
665
- this._pagesRequests = new WeakMap();
666
- this._setImageDisabled = false; // Remove the thumbnails from the DOM.
667
512
 
513
+ // Remove the thumbnails from the DOM.
668
514
  this.container.textContent = "";
669
515
  }
670
516
 
517
+ /**
518
+ * @param {PDFDocumentProxy} pdfDocument
519
+ */
671
520
  setDocument(pdfDocument) {
672
521
  if (this.pdfDocument) {
673
- this._cancelRendering();
674
-
675
- this._resetView();
522
+ this.#cancelRendering();
523
+ this.#resetView();
676
524
  }
677
-
678
525
  this.pdfDocument = pdfDocument;
679
-
680
526
  if (!pdfDocument) {
681
527
  return;
682
528
  }
683
-
684
529
  const firstPagePromise = pdfDocument.getPage(1);
685
- const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
530
+ const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
531
+ intent: "display"
532
+ });
686
533
  firstPagePromise.then(firstPdfPage => {
687
- this._optionalContentConfigPromise = optionalContentConfigPromise;
534
+ var _this$_thumbnails$;
688
535
  const pagesCount = pdfDocument.numPages;
689
536
  const viewport = firstPdfPage.getViewport({
690
537
  scale: 1
691
538
  });
692
-
693
- const checkSetImageDisabled = () => {
694
- return this._setImageDisabled;
695
- };
696
-
697
539
  for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
698
540
  const thumbnail = new PDFThumbnailView({
699
541
  container: this.container,
542
+ eventBus: this.eventBus,
700
543
  id: pageNum,
701
544
  defaultViewport: viewport.clone(),
702
545
  optionalContentConfigPromise,
703
546
  linkService: this.linkService,
704
547
  renderingQueue: this.renderingQueue,
705
- checkSetImageDisabled,
706
- l10n: this.l10n
548
+ pageColors: this.pageColors
707
549
  });
708
-
709
550
  this._thumbnails.push(thumbnail);
710
- } // Set the first `pdfPage` immediately, since it's already loaded,
551
+ }
552
+ // Set the first `pdfPage` immediately, since it's already loaded,
711
553
  // rather than having to repeat the `PDFDocumentProxy.getPage` call in
712
- // the `this._ensurePdfPageLoaded` method before rendering can start.
713
-
714
-
715
- const firstThumbnailView = this._thumbnails[0];
716
-
717
- if (firstThumbnailView) {
718
- firstThumbnailView.setPdfPage(firstPdfPage);
719
- } // Ensure that the current thumbnail is always highlighted on load.
720
-
554
+ // the `this.#ensurePdfPageLoaded` method before rendering can start.
555
+ (_this$_thumbnails$ = this._thumbnails[0]) === null || _this$_thumbnails$ === void 0 ? void 0 : _this$_thumbnails$.setPdfPage(firstPdfPage);
721
556
 
557
+ // Ensure that the current thumbnail is always highlighted on load.
722
558
  const thumbnailView = this._thumbnails[this._currentPageNumber - 1];
723
559
  thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS);
724
560
  }).catch(reason => {
725
561
  console.error("Unable to initialize thumbnail viewer", reason);
726
562
  });
727
563
  }
728
- /**
729
- * @private
730
- */
731
-
732
-
733
- _cancelRendering() {
734
- for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
735
- if (this._thumbnails[i]) {
736
- this._thumbnails[i].cancelRendering();
737
- }
564
+ #cancelRendering() {
565
+ for (const thumbnail of this._thumbnails) {
566
+ thumbnail.cancelRendering();
738
567
  }
739
568
  }
569
+
740
570
  /**
741
571
  * @param {Array|null} labels
742
572
  */
743
-
744
-
745
573
  setPageLabels(labels) {
746
574
  if (!this.pdfDocument) {
747
575
  return;
748
576
  }
749
-
750
577
  if (!labels) {
751
578
  this._pageLabels = null;
752
579
  } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
@@ -754,66 +581,54 @@ class PDFThumbnailViewer {
754
581
  console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels.");
755
582
  } else {
756
583
  this._pageLabels = labels;
757
- } // Update all the `PDFThumbnailView` instances.
758
-
759
-
584
+ }
585
+ // Update all the `PDFThumbnailView` instances.
760
586
  for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
761
587
  var _this$_pageLabels$i, _this$_pageLabels;
762
-
763
588
  this._thumbnails[i].setPageLabel((_this$_pageLabels$i = (_this$_pageLabels = this._pageLabels) === null || _this$_pageLabels === void 0 ? void 0 : _this$_pageLabels[i]) !== null && _this$_pageLabels$i !== void 0 ? _this$_pageLabels$i : null);
764
589
  }
765
590
  }
591
+
766
592
  /**
767
593
  * @param {PDFThumbnailView} thumbView
768
- * @returns {PDFPage}
769
- * @private
594
+ * @returns {Promise<PDFPageProxy | null>}
770
595
  */
771
-
772
-
773
- _ensurePdfPageLoaded(thumbView) {
596
+ async #ensurePdfPageLoaded(thumbView) {
774
597
  if (thumbView.pdfPage) {
775
- return Promise.resolve(thumbView.pdfPage);
776
- }
777
-
778
- if (this._pagesRequests.has(thumbView)) {
779
- return this._pagesRequests.get(thumbView);
598
+ return thumbView.pdfPage;
780
599
  }
781
-
782
- const promise = this.pdfDocument.getPage(thumbView.id).then(pdfPage => {
600
+ try {
601
+ const pdfPage = await this.pdfDocument.getPage(thumbView.id);
783
602
  if (!thumbView.pdfPage) {
784
603
  thumbView.setPdfPage(pdfPage);
785
604
  }
786
-
787
- this._pagesRequests.delete(thumbView);
788
-
789
605
  return pdfPage;
790
- }).catch(reason => {
791
- console.error("Unable to get page for thumb view", reason); // Page error -- there is nothing that can be done.
792
-
793
- this._pagesRequests.delete(thumbView);
794
- });
795
-
796
- this._pagesRequests.set(thumbView, promise);
797
-
798
- return promise;
606
+ } catch (reason) {
607
+ console.error("Unable to get page for thumb view", reason);
608
+ return null; // Page error -- there is nothing that can be done.
609
+ }
610
+ }
611
+ #getScrollAhead(visible) {
612
+ var _visible$first, _visible$last;
613
+ if (((_visible$first = visible.first) === null || _visible$first === void 0 ? void 0 : _visible$first.id) === 1) {
614
+ return true;
615
+ } else if (((_visible$last = visible.last) === null || _visible$last === void 0 ? void 0 : _visible$last.id) === this._thumbnails.length) {
616
+ return false;
617
+ }
618
+ return this.scroll.down;
799
619
  }
800
-
801
620
  forceRendering() {
802
- const visibleThumbs = this._getVisibleThumbs();
803
-
804
- const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down);
805
-
621
+ const visibleThumbs = this.#getVisibleThumbs();
622
+ const scrollAhead = this.#getScrollAhead(visibleThumbs);
623
+ const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead);
806
624
  if (thumbView) {
807
- this._ensurePdfPageLoaded(thumbView).then(() => {
625
+ this.#ensurePdfPageLoaded(thumbView).then(() => {
808
626
  this.renderingQueue.renderView(thumbView);
809
627
  });
810
-
811
628
  return true;
812
629
  }
813
-
814
630
  return false;
815
631
  }
816
-
817
632
  }
818
633
 
819
634
  export { PDFThumbnailViewer };