box-content-preview 3.72.0 → 3.74.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 +7 -7
- package/dist/lib/index.js +439 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
[](https://mergify.io)
|
|
3
3
|
[](https://github.com/prettier/prettier)
|
|
4
4
|
[](https://travis-ci.org/box/box-content-preview)
|
|
5
|
-
[](https://github.com/box/box-content-preview)
|
|
6
6
|
[](https://www.npmjs.com/package/box-ui-elements)
|
|
7
7
|
|
|
8
8
|
# [Box Content Preview](https://developer.box.com/docs/box-content-preview)
|
|
@@ -22,11 +22,11 @@ We encourage all users to update their applications to utilize modern browsers f
|
|
|
22
22
|
|
|
23
23
|
## Current Version
|
|
24
24
|
|
|
25
|
-
- Version: v3.
|
|
25
|
+
- Version: v3.74.0
|
|
26
26
|
- Locale: en-US
|
|
27
27
|
|
|
28
|
-
https://cdn01.boxcdn.net/platform/preview/3.
|
|
29
|
-
https://cdn01.boxcdn.net/platform/preview/3.
|
|
28
|
+
https://cdn01.boxcdn.net/platform/preview/3.74.0/en-US/preview.js
|
|
29
|
+
https://cdn01.boxcdn.net/platform/preview/3.74.0/en-US/preview.css
|
|
30
30
|
|
|
31
31
|
## Supported Locales
|
|
32
32
|
|
|
@@ -52,10 +52,10 @@ You can self-host the Box Content Preview library or reference the versions avai
|
|
|
52
52
|
<title>Box Content Preview Demo</title>
|
|
53
53
|
|
|
54
54
|
<!-- Latest version of Preview SDK for your locale -->
|
|
55
|
-
<script src="https://cdn01.boxcdn.net/platform/preview/3.
|
|
55
|
+
<script src="https://cdn01.boxcdn.net/platform/preview/3.74.0/en-US/preview.js"></script>
|
|
56
56
|
<link
|
|
57
57
|
rel="stylesheet"
|
|
58
|
-
href="https://cdn01.boxcdn.net/platform/preview/3.
|
|
58
|
+
href="https://cdn01.boxcdn.net/platform/preview/3.74.0/en-US/preview.css"
|
|
59
59
|
/>
|
|
60
60
|
</head>
|
|
61
61
|
<body>
|
|
@@ -76,7 +76,7 @@ To self-host the Box Content Preview library, follow these steps:
|
|
|
76
76
|
|
|
77
77
|
1. Either fork the repo and check out the version you want to host or download the specific version as a zip:
|
|
78
78
|
|
|
79
|
-
- Check out a specific version with `git checkout v3.
|
|
79
|
+
- Check out a specific version with `git checkout v3.74.0`
|
|
80
80
|
- Download a specific version as a zip from https://github.com/box/box-content-preview/releases
|
|
81
81
|
|
|
82
82
|
2. Install dependencies and build the library with `yarn install && yarn build:i18n && yarn build:prod`
|
package/dist/lib/index.js
CHANGED
|
@@ -15388,7 +15388,7 @@ function util_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var
|
|
|
15388
15388
|
const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
|
|
15389
15389
|
const CLIENT_NAME_KEY = 'box_client_name';
|
|
15390
15390
|
const CLIENT_VERSION_KEY = 'box_client_version';
|
|
15391
|
-
const CLIENT_VERSION = "3.
|
|
15391
|
+
const CLIENT_VERSION = "3.74.0"; // eslint-disable-line no-undef
|
|
15392
15392
|
const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
|
|
15393
15393
|
const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
|
|
15394
15394
|
const PROMISE_MAP = {};
|
|
@@ -16487,7 +16487,9 @@ const X_REP_HINT_BASE = '[3d][pdf][text][mp3][json]';
|
|
|
16487
16487
|
const X_REP_HINT_DOC_THUMBNAIL = '[jpg?dimensions=1024x1024&paged=false]';
|
|
16488
16488
|
const X_REP_HINT_IMAGE = '[jpg?dimensions=2048x2048,png?dimensions=2048x2048]';
|
|
16489
16489
|
const X_REP_HINT_VIDEO_DASH = '[dash,mp4][filmstrip]';
|
|
16490
|
+
const X_REP_HINT_VIDEO_DASH_EXTRACTED_TEXT = '[extracted_text]';
|
|
16490
16491
|
const X_REP_HINT_VIDEO_MP4 = '[mp4]';
|
|
16492
|
+
const AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES = 'aiTranscriptionForVideoSubtitles';
|
|
16491
16493
|
const PDFJS_CSS_UNITS = 96.0 / 72.0; // Should match CSS_UNITS in pdf_viewer.js
|
|
16492
16494
|
const PDFJS_MAX_AUTO_SCALE = 1.25; // Should match MAX_AUTO_SCALE in pdf_viewer.js
|
|
16493
16495
|
const PDFJS_WIDTH_PADDING_PX = 40; // Should match SCROLLBAR_PADDING in pdf_viewer.js
|
|
@@ -17083,7 +17085,7 @@ class Browser {
|
|
|
17083
17085
|
;// ./src/lib/Logger.js
|
|
17084
17086
|
/* eslint-disable no-undef */
|
|
17085
17087
|
const Logger_CLIENT_NAME = "box-content-preview";
|
|
17086
|
-
const Logger_CLIENT_VERSION = "3.
|
|
17088
|
+
const Logger_CLIENT_VERSION = "3.74.0";
|
|
17087
17089
|
/* eslint-enable no-undef */
|
|
17088
17090
|
|
|
17089
17091
|
class Logger {
|
|
@@ -27374,6 +27376,23 @@ class Settings extends (events_default()) {
|
|
|
27374
27376
|
this.reset();
|
|
27375
27377
|
}
|
|
27376
27378
|
|
|
27379
|
+
/**
|
|
27380
|
+
* Appends a single subtitle entry to the settings menu without disturbing
|
|
27381
|
+
* existing items or the user's current selection.
|
|
27382
|
+
*
|
|
27383
|
+
* @param {string} subtitle - Display name for the subtitle track
|
|
27384
|
+
* @param {number} idx - data-value index for the new menu item
|
|
27385
|
+
* @return {void}
|
|
27386
|
+
*/
|
|
27387
|
+
addSubtitle(subtitle, idx) {
|
|
27388
|
+
const subtitlesSubMenu = this.settingsEl.querySelector('.bp-media-settings-menu-subtitles');
|
|
27389
|
+
insertTemplate(subtitlesSubMenu, SUBMENU_SUBITEM_TEMPLATE.replace(/{{dataType}}/g, 'subtitles').replace(/{{dataValue}}/g, idx));
|
|
27390
|
+
const languageNode = subtitlesSubMenu.lastChild.querySelector('.bp-media-settings-value');
|
|
27391
|
+
languageNode.textContent = subtitle;
|
|
27392
|
+
this.subtitles.push(subtitle);
|
|
27393
|
+
this.reset();
|
|
27394
|
+
}
|
|
27395
|
+
|
|
27377
27396
|
/**
|
|
27378
27397
|
* Takes an ordered list of audio languages and populates the settings menu
|
|
27379
27398
|
*
|
|
@@ -34426,6 +34445,8 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
34426
34445
|
DashViewer_defineProperty(this, "filmstripInterval", void 0);
|
|
34427
34446
|
/** @property {Object} - Status of the filmstrip representation */
|
|
34428
34447
|
DashViewer_defineProperty(this, "filmstripStatus", void 0);
|
|
34448
|
+
/** @property {Object} - Status of the extracted_text (transcription) representation */
|
|
34449
|
+
DashViewer_defineProperty(this, "transcriptionStatus", void 0);
|
|
34429
34450
|
/** @property {string} - URL for the filmstrip image */
|
|
34430
34451
|
DashViewer_defineProperty(this, "filmstripUrl", void 0);
|
|
34431
34452
|
/** @property {string} - ID of the selected audio track */
|
|
@@ -34518,6 +34539,9 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
34518
34539
|
if (this.filmstripUrl && this.filmstripUrl.startsWith('blob:')) {
|
|
34519
34540
|
URL.revokeObjectURL(this.filmstripUrl);
|
|
34520
34541
|
}
|
|
34542
|
+
if (this.transcriptionStatus) {
|
|
34543
|
+
this.transcriptionStatus.destroy();
|
|
34544
|
+
}
|
|
34521
34545
|
clearInterval(this.statsIntervalId);
|
|
34522
34546
|
if (this.player) {
|
|
34523
34547
|
this.player.destroy();
|
|
@@ -35040,6 +35064,20 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
35040
35064
|
this.mediaControls.addListener('audiochange', this.handleAudioTrack);
|
|
35041
35065
|
}
|
|
35042
35066
|
|
|
35067
|
+
/**
|
|
35068
|
+
* Returns the display-friendly name for a text track's language.
|
|
35069
|
+
* Maps the undetermined language code 'und' to a localized "Auto-Generated" label.
|
|
35070
|
+
*
|
|
35071
|
+
* @param {Object} track - A Shaka text track object
|
|
35072
|
+
* @return {string} Localized language name or the raw language code
|
|
35073
|
+
*/
|
|
35074
|
+
getTrackDisplayLanguage(track) {
|
|
35075
|
+
if (this.featureEnabled(AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES) && track.language === 'und') {
|
|
35076
|
+
return "Auto-Generated";
|
|
35077
|
+
}
|
|
35078
|
+
return getLanguageName(track.language) || track.language;
|
|
35079
|
+
}
|
|
35080
|
+
|
|
35043
35081
|
/**
|
|
35044
35082
|
* Loads captions/subtitles into the settings menu
|
|
35045
35083
|
*
|
|
@@ -35052,7 +35090,7 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
35052
35090
|
if (this.useReactControls()) {
|
|
35053
35091
|
this.initSubtitles();
|
|
35054
35092
|
} else {
|
|
35055
|
-
this.mediaControls.initSubtitles(this.textTracks.map(track =>
|
|
35093
|
+
this.mediaControls.initSubtitles(this.textTracks.map(track => this.getTrackDisplayLanguage(track)), getLanguageName(this.options.location.locale.substring(0, 2)));
|
|
35056
35094
|
}
|
|
35057
35095
|
}
|
|
35058
35096
|
}
|
|
@@ -35086,7 +35124,7 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
35086
35124
|
this.cache.set('media-subtitles-toggle', true, true);
|
|
35087
35125
|
}
|
|
35088
35126
|
this.textTracks = this.textTracks.map(track => DashViewer_objectSpread(DashViewer_objectSpread({}, track), {}, {
|
|
35089
|
-
displayLanguage:
|
|
35127
|
+
displayLanguage: this.getTrackDisplayLanguage(track)
|
|
35090
35128
|
}));
|
|
35091
35129
|
|
|
35092
35130
|
// Do intelligent selection: Prefer user's language, fallback to English, then first subtitle in list
|
|
@@ -35244,6 +35282,7 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
35244
35282
|
this.startBandwidthTracking();
|
|
35245
35283
|
this.loadFilmStrip();
|
|
35246
35284
|
this.loadSubtitles();
|
|
35285
|
+
this.loadTranscription();
|
|
35247
35286
|
this.loadAlternateAudio();
|
|
35248
35287
|
this.showPlayButton();
|
|
35249
35288
|
if (this.userRequestedPlay) {
|
|
@@ -35348,6 +35387,58 @@ class DashViewer extends media_VideoBaseViewer {
|
|
|
35348
35387
|
}
|
|
35349
35388
|
}
|
|
35350
35389
|
|
|
35390
|
+
/**
|
|
35391
|
+
* Loads the extracted_text transcription (.vtt) as a text track when available
|
|
35392
|
+
*
|
|
35393
|
+
* @private
|
|
35394
|
+
* @return {void}
|
|
35395
|
+
*/
|
|
35396
|
+
async loadTranscription() {
|
|
35397
|
+
if (!this.featureEnabled(AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES)) {
|
|
35398
|
+
return;
|
|
35399
|
+
}
|
|
35400
|
+
const extractedText = getRepresentation(this.options.file, 'extracted_text');
|
|
35401
|
+
if (!extractedText?.content?.url_template) {
|
|
35402
|
+
return;
|
|
35403
|
+
}
|
|
35404
|
+
const transcriptionUrl = this.featureEnabled('migrateAccessTokenToHeader') ? this.createContentUrlV2(extractedText.content.url_template) : this.createContentUrlWithAuthParams(extractedText.content.url_template);
|
|
35405
|
+
this.transcriptionStatus = this.getRepStatus(extractedText);
|
|
35406
|
+
try {
|
|
35407
|
+
await this.transcriptionStatus.getPromise();
|
|
35408
|
+
if (this.isDestroyed() || !this.player) {
|
|
35409
|
+
return;
|
|
35410
|
+
}
|
|
35411
|
+
await this.player.addTextTrackAsync(transcriptionUrl, 'und', 'subtitles', 'text/vtt', undefined, "Auto-Generated");
|
|
35412
|
+
if (this.isDestroyed()) {
|
|
35413
|
+
return;
|
|
35414
|
+
}
|
|
35415
|
+
if (this.textTracks.length > 0) {
|
|
35416
|
+
// Subtitles were already initialized — append only the new track(s) at the
|
|
35417
|
+
// end of `this.textTracks`. We must not re-sort: in the non-React path, the
|
|
35418
|
+
// user's selection is cached as an INDEX into `this.textTracks` (see
|
|
35419
|
+
// handleSubtitle) and Settings menu items use the same number as their
|
|
35420
|
+
// `data-value`, so reordering would silently swap which track plays.
|
|
35421
|
+
const existingIds = new Set(this.textTracks.map(t => t.id));
|
|
35422
|
+
const newTracks = this.player.getTextTracks().filter(t => !existingIds.has(t.id));
|
|
35423
|
+
if (this.useReactControls()) {
|
|
35424
|
+
this.textTracks = [...this.textTracks, ...newTracks].map(track => DashViewer_objectSpread(DashViewer_objectSpread({}, track), {}, {
|
|
35425
|
+
displayLanguage: this.getTrackDisplayLanguage(track)
|
|
35426
|
+
}));
|
|
35427
|
+
this.renderUI();
|
|
35428
|
+
} else {
|
|
35429
|
+
newTracks.forEach(track => {
|
|
35430
|
+
this.textTracks.push(track);
|
|
35431
|
+
this.mediaControls.settings.addSubtitle(this.getTrackDisplayLanguage(track), this.textTracks.length - 1);
|
|
35432
|
+
});
|
|
35433
|
+
}
|
|
35434
|
+
} else {
|
|
35435
|
+
this.loadSubtitles();
|
|
35436
|
+
}
|
|
35437
|
+
} catch {
|
|
35438
|
+
// Transcription is non-critical; allow the viewer to continue without it
|
|
35439
|
+
}
|
|
35440
|
+
}
|
|
35441
|
+
|
|
35351
35442
|
/**
|
|
35352
35443
|
* Calculates the video dimension based on representations
|
|
35353
35444
|
*
|
|
@@ -37237,10 +37328,17 @@ function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string")
|
|
|
37237
37328
|
function Thumbnail_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
37238
37329
|
|
|
37239
37330
|
|
|
37331
|
+
|
|
37240
37332
|
const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
|
|
37241
37333
|
const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
|
|
37242
37334
|
const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
|
|
37243
37335
|
|
|
37336
|
+
function createRejectedTask(message) {
|
|
37337
|
+
return {
|
|
37338
|
+
cancel: (noop_default()),
|
|
37339
|
+
promise: Promise.reject(new Error(message))
|
|
37340
|
+
};
|
|
37341
|
+
}
|
|
37244
37342
|
class Thumbnail {
|
|
37245
37343
|
/**
|
|
37246
37344
|
* [constructor]
|
|
@@ -37252,13 +37350,17 @@ class Thumbnail {
|
|
|
37252
37350
|
Thumbnail_defineProperty(this, "pdfViewer", void 0);
|
|
37253
37351
|
/** @property {Object} - Cache for the thumbnail image elements */
|
|
37254
37352
|
Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
|
|
37353
|
+
/** @property {Set} - Active PDF.js render tasks */
|
|
37354
|
+
Thumbnail_defineProperty(this, "renderTasks", void 0);
|
|
37255
37355
|
Thumbnail_defineProperty(this, "preloader", void 0);
|
|
37256
37356
|
this.preloader = preloader;
|
|
37257
37357
|
this.createImageEl = this.createImageEl.bind(this);
|
|
37258
37358
|
this.createThumbnailImage = this.createThumbnailImage.bind(this);
|
|
37259
37359
|
this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
|
|
37360
|
+
this.renderPageImage = this.renderPageImage.bind(this);
|
|
37260
37361
|
this.pdfViewer = pdfViewer;
|
|
37261
37362
|
this.thumbnailImageCache = new lib_BoundedCache();
|
|
37363
|
+
this.renderTasks = new Set();
|
|
37262
37364
|
}
|
|
37263
37365
|
|
|
37264
37366
|
/**
|
|
@@ -37267,6 +37369,11 @@ class Thumbnail {
|
|
|
37267
37369
|
* @return {void}
|
|
37268
37370
|
*/
|
|
37269
37371
|
destroy() {
|
|
37372
|
+
if (this.renderTasks) {
|
|
37373
|
+
this.renderTasks.forEach(task => task.cancel());
|
|
37374
|
+
this.renderTasks.clear();
|
|
37375
|
+
this.renderTasks = null;
|
|
37376
|
+
}
|
|
37270
37377
|
if (this.thumbnailImageCache) {
|
|
37271
37378
|
this.thumbnailImageCache.destroy();
|
|
37272
37379
|
this.thumbnailImageCache = null;
|
|
@@ -37385,6 +37492,12 @@ class Thumbnail {
|
|
|
37385
37492
|
if (!this.thumbnailImageCache) {
|
|
37386
37493
|
return null;
|
|
37387
37494
|
}
|
|
37495
|
+
if (!dataUrl) {
|
|
37496
|
+
this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
|
|
37497
|
+
inProgress: false
|
|
37498
|
+
}));
|
|
37499
|
+
return null;
|
|
37500
|
+
}
|
|
37388
37501
|
const imageEl = this.createImageEl(dataUrl, thumbOptions);
|
|
37389
37502
|
// Cache this image element for future use
|
|
37390
37503
|
this.thumbnailImageCache.set(itemIndex, {
|
|
@@ -37414,22 +37527,35 @@ class Thumbnail {
|
|
|
37414
37527
|
}
|
|
37415
37528
|
|
|
37416
37529
|
/**
|
|
37417
|
-
*
|
|
37418
|
-
* @param {number} pageNum
|
|
37419
|
-
* @
|
|
37530
|
+
* Renders a page image without caching it.
|
|
37531
|
+
* @param {number} pageNum - The page number of the document (1 indexed)
|
|
37532
|
+
* @param {Object} thumbOptions - Thumbnail render options
|
|
37533
|
+
* @return {Object} A cancellable render task
|
|
37420
37534
|
*/
|
|
37421
|
-
|
|
37422
|
-
if (this.preloader?.preloadedImages?.[pageNum]) {
|
|
37423
|
-
return Promise.resolve(this.preloader.preloadedImages[pageNum]);
|
|
37424
|
-
}
|
|
37535
|
+
renderPageImage(pageNum, thumbOptions) {
|
|
37425
37536
|
const pdfDocument = this.pdfViewer?.pdfDocument;
|
|
37426
37537
|
if (!pdfDocument) {
|
|
37427
|
-
return
|
|
37538
|
+
return createRejectedTask('PDF document not ready');
|
|
37428
37539
|
}
|
|
37429
|
-
const canvas = document.createElement('canvas');
|
|
37430
37540
|
const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
|
|
37431
|
-
|
|
37432
|
-
|
|
37541
|
+
if (!isFinite_default()(thumbnailImageWidth) || thumbnailImageWidth <= 0) {
|
|
37542
|
+
return createRejectedTask('Invalid thumbnail render dimensions');
|
|
37543
|
+
}
|
|
37544
|
+
const canvas = document.createElement('canvas');
|
|
37545
|
+
let isCancelled = false;
|
|
37546
|
+
let pdfRenderTask = null;
|
|
37547
|
+
const task = {
|
|
37548
|
+
cancel: () => {
|
|
37549
|
+
if (isCancelled) {
|
|
37550
|
+
return;
|
|
37551
|
+
}
|
|
37552
|
+
isCancelled = true;
|
|
37553
|
+
pdfRenderTask?.cancel();
|
|
37554
|
+
},
|
|
37555
|
+
promise: null
|
|
37556
|
+
};
|
|
37557
|
+
task.promise = pdfDocument.getPage(pageNum).then(page => {
|
|
37558
|
+
if (isCancelled || !this.thumbnailImageCache) {
|
|
37433
37559
|
return null;
|
|
37434
37560
|
}
|
|
37435
37561
|
const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
|
|
@@ -37437,48 +37563,249 @@ class Thumbnail {
|
|
|
37437
37563
|
scale: 1,
|
|
37438
37564
|
rotation
|
|
37439
37565
|
});
|
|
37440
|
-
if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
|
|
37566
|
+
if (!viewport || !isFinite_default()(viewport.width) || viewport.width <= 0 || !isFinite_default()(viewport.height) || viewport.height <= 0) {
|
|
37441
37567
|
return Promise.reject(new Error('Invalid page viewport'));
|
|
37442
37568
|
}
|
|
37443
37569
|
const {
|
|
37444
37570
|
width,
|
|
37445
37571
|
height
|
|
37446
37572
|
} = viewport;
|
|
37447
|
-
|
|
37448
|
-
|
|
37449
|
-
|
|
37450
|
-
|
|
37451
|
-
// `pageRatio` which means that this page is probably more portrait than
|
|
37452
|
-
// landscape
|
|
37453
|
-
if (curPageRatio < this.pageRatio) {
|
|
37454
|
-
// Set the canvas height to that of the thumbnail max height
|
|
37573
|
+
const currentPageRatio = width / height;
|
|
37574
|
+
|
|
37575
|
+
// More-portrait pages are constrained by the first page's height budget.
|
|
37576
|
+
if (currentPageRatio < this.pageRatio) {
|
|
37455
37577
|
canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
|
|
37456
|
-
|
|
37457
|
-
canvas.width = canvas.height * curPageRatio;
|
|
37578
|
+
canvas.width = canvas.height * currentPageRatio;
|
|
37458
37579
|
} else {
|
|
37459
|
-
// In case the current page ratio is same as the first page
|
|
37460
|
-
// or in case it's larger (which means that it's wider), keep
|
|
37461
|
-
// the width at the max thumbnail width
|
|
37462
37580
|
canvas.width = thumbnailImageWidth;
|
|
37463
|
-
|
|
37464
|
-
canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
|
|
37581
|
+
canvas.height = Math.ceil(thumbnailImageWidth / currentPageRatio);
|
|
37465
37582
|
}
|
|
37466
|
-
// The amount for which to scale down the current page
|
|
37467
37583
|
const {
|
|
37468
37584
|
width: canvasWidth
|
|
37469
37585
|
} = canvas;
|
|
37470
37586
|
const scale = canvasWidth / width;
|
|
37471
|
-
|
|
37587
|
+
pdfRenderTask = page.render({
|
|
37472
37588
|
canvasContext: canvas.getContext('2d'),
|
|
37473
37589
|
viewport: page.getViewport({
|
|
37474
37590
|
scale,
|
|
37475
37591
|
rotation
|
|
37476
37592
|
})
|
|
37477
|
-
})
|
|
37478
|
-
|
|
37593
|
+
});
|
|
37594
|
+
return pdfRenderTask.promise.then(() => {
|
|
37595
|
+
if (isCancelled || !this.thumbnailImageCache) {
|
|
37596
|
+
return null;
|
|
37597
|
+
}
|
|
37598
|
+
return {
|
|
37599
|
+
dataUrl: canvas.toDataURL(),
|
|
37600
|
+
height: canvas.height,
|
|
37601
|
+
width: canvas.width
|
|
37602
|
+
};
|
|
37603
|
+
});
|
|
37604
|
+
}).catch(error => {
|
|
37605
|
+
if (isCancelled) {
|
|
37606
|
+
return null;
|
|
37607
|
+
}
|
|
37608
|
+
throw error;
|
|
37609
|
+
}).finally(() => {
|
|
37610
|
+
canvas.width = 0;
|
|
37611
|
+
canvas.height = 0;
|
|
37612
|
+
this.renderTasks?.delete(task);
|
|
37613
|
+
});
|
|
37614
|
+
this.renderTasks.add(task);
|
|
37615
|
+
return task;
|
|
37616
|
+
}
|
|
37617
|
+
|
|
37618
|
+
/**
|
|
37619
|
+
* Given a page number, generates the image data URL for the image of the page
|
|
37620
|
+
* @param {number} pageNum - The page number of the document
|
|
37621
|
+
* @return {string} The data URL of the page image
|
|
37622
|
+
*/
|
|
37623
|
+
getThumbnailDataURL(pageNum, thumbOptions) {
|
|
37624
|
+
if (this.preloader?.preloadedImages?.[pageNum]) {
|
|
37625
|
+
return Promise.resolve(this.preloader.preloadedImages[pageNum]);
|
|
37626
|
+
}
|
|
37627
|
+
return this.renderPageImage(pageNum, thumbOptions).promise.then(result => result?.dataUrl || null);
|
|
37479
37628
|
}
|
|
37480
37629
|
}
|
|
37481
37630
|
/* harmony default export */ const lib_Thumbnail = (Thumbnail);
|
|
37631
|
+
;// ./src/lib/viewers/gallery/HighResThumbnailStore.ts
|
|
37632
|
+
function HighResThumbnailStore_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
37633
|
+
function HighResThumbnailStore_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? HighResThumbnailStore_ownKeys(Object(t), !0).forEach(function (r) { HighResThumbnailStore_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : HighResThumbnailStore_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
37634
|
+
function HighResThumbnailStore_defineProperty(e, r, t) { return (r = HighResThumbnailStore_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
37635
|
+
function HighResThumbnailStore_toPropertyKey(t) { var i = HighResThumbnailStore_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
37636
|
+
function HighResThumbnailStore_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
37637
|
+
class HighResThumbnailStore {
|
|
37638
|
+
constructor({
|
|
37639
|
+
maxBytes,
|
|
37640
|
+
maxConcurrent,
|
|
37641
|
+
maxPages,
|
|
37642
|
+
onChange,
|
|
37643
|
+
render
|
|
37644
|
+
}) {
|
|
37645
|
+
HighResThumbnailStore_defineProperty(this, "activeCount", 0);
|
|
37646
|
+
HighResThumbnailStore_defineProperty(this, "cache", new Map());
|
|
37647
|
+
HighResThumbnailStore_defineProperty(this, "currentBytes", 0);
|
|
37648
|
+
HighResThumbnailStore_defineProperty(this, "failed", new Set());
|
|
37649
|
+
HighResThumbnailStore_defineProperty(this, "inFlight", new Map());
|
|
37650
|
+
HighResThumbnailStore_defineProperty(this, "isDestroyed", false);
|
|
37651
|
+
HighResThumbnailStore_defineProperty(this, "maxBytes", void 0);
|
|
37652
|
+
HighResThumbnailStore_defineProperty(this, "maxConcurrent", void 0);
|
|
37653
|
+
HighResThumbnailStore_defineProperty(this, "maxPages", void 0);
|
|
37654
|
+
HighResThumbnailStore_defineProperty(this, "onChange", void 0);
|
|
37655
|
+
HighResThumbnailStore_defineProperty(this, "queue", []);
|
|
37656
|
+
HighResThumbnailStore_defineProperty(this, "render", void 0);
|
|
37657
|
+
HighResThumbnailStore_defineProperty(this, "retained", new Set());
|
|
37658
|
+
HighResThumbnailStore_defineProperty(this, "targetWidth", 0);
|
|
37659
|
+
this.maxBytes = maxBytes;
|
|
37660
|
+
this.maxConcurrent = maxConcurrent;
|
|
37661
|
+
this.maxPages = maxPages;
|
|
37662
|
+
this.onChange = onChange;
|
|
37663
|
+
this.render = render;
|
|
37664
|
+
}
|
|
37665
|
+
setRetained(pages, width, pageRatio) {
|
|
37666
|
+
if (this.isDestroyed) {
|
|
37667
|
+
return;
|
|
37668
|
+
}
|
|
37669
|
+
const previousWidth = this.targetWidth;
|
|
37670
|
+
this.targetWidth = width;
|
|
37671
|
+
if (previousWidth !== width) {
|
|
37672
|
+
this.failed.clear();
|
|
37673
|
+
}
|
|
37674
|
+
const ratio = Number.isFinite(pageRatio) && pageRatio > 0 ? pageRatio : 1;
|
|
37675
|
+
const estimatedBytes = width * Math.ceil(width / ratio) * 4;
|
|
37676
|
+
const pageLimit = Math.min(this.maxPages, Math.floor(this.maxBytes / estimatedBytes));
|
|
37677
|
+
const retainedPages = Array.from(new Set(pages)).slice(0, pageLimit);
|
|
37678
|
+
const retainedSet = new Set(retainedPages);
|
|
37679
|
+
this.retained = retainedSet;
|
|
37680
|
+
this.failed.forEach(pageNum => {
|
|
37681
|
+
if (!retainedSet.has(pageNum)) {
|
|
37682
|
+
this.failed.delete(pageNum);
|
|
37683
|
+
}
|
|
37684
|
+
});
|
|
37685
|
+
let didEvict = false;
|
|
37686
|
+
this.cache.forEach((entry, pageNum) => {
|
|
37687
|
+
if (!this.retained.has(pageNum) || entry.requestedWidth !== width) {
|
|
37688
|
+
this.cache.delete(pageNum);
|
|
37689
|
+
this.currentBytes -= entry.bytes;
|
|
37690
|
+
didEvict = true;
|
|
37691
|
+
}
|
|
37692
|
+
});
|
|
37693
|
+
this.inFlight.forEach((pending, pageNum) => {
|
|
37694
|
+
if (!this.retained.has(pageNum) || pending.width !== width) {
|
|
37695
|
+
pending.task.cancel();
|
|
37696
|
+
this.inFlight.delete(pageNum);
|
|
37697
|
+
}
|
|
37698
|
+
});
|
|
37699
|
+
this.queue = retainedPages.filter(pageNum => !this.cache.has(pageNum) && !this.inFlight.has(pageNum) && !this.failed.has(pageNum));
|
|
37700
|
+
if (didEvict) {
|
|
37701
|
+
this.emit();
|
|
37702
|
+
}
|
|
37703
|
+
this.pump();
|
|
37704
|
+
}
|
|
37705
|
+
destroy() {
|
|
37706
|
+
if (this.isDestroyed) {
|
|
37707
|
+
return;
|
|
37708
|
+
}
|
|
37709
|
+
this.isDestroyed = true;
|
|
37710
|
+
this.inFlight.forEach(({
|
|
37711
|
+
task
|
|
37712
|
+
}) => task.cancel());
|
|
37713
|
+
this.inFlight.clear();
|
|
37714
|
+
this.cache.clear();
|
|
37715
|
+
this.failed.clear();
|
|
37716
|
+
this.queue = [];
|
|
37717
|
+
this.retained.clear();
|
|
37718
|
+
this.currentBytes = 0;
|
|
37719
|
+
this.onChange = null;
|
|
37720
|
+
this.render = null;
|
|
37721
|
+
}
|
|
37722
|
+
emit() {
|
|
37723
|
+
if (!this.onChange) {
|
|
37724
|
+
return;
|
|
37725
|
+
}
|
|
37726
|
+
const images = {};
|
|
37727
|
+
this.cache.forEach((entry, pageNum) => {
|
|
37728
|
+
images[pageNum] = entry.dataUrl;
|
|
37729
|
+
});
|
|
37730
|
+
this.onChange(images);
|
|
37731
|
+
}
|
|
37732
|
+
pump() {
|
|
37733
|
+
if (this.isDestroyed || !this.render) {
|
|
37734
|
+
return;
|
|
37735
|
+
}
|
|
37736
|
+
while (this.activeCount < this.maxConcurrent && this.queue.length > 0) {
|
|
37737
|
+
const pageNum = this.queue.shift();
|
|
37738
|
+
if (pageNum && this.retained.has(pageNum)) {
|
|
37739
|
+
this.startRender(pageNum);
|
|
37740
|
+
}
|
|
37741
|
+
}
|
|
37742
|
+
}
|
|
37743
|
+
startRender(pageNum) {
|
|
37744
|
+
if (!this.render) {
|
|
37745
|
+
return;
|
|
37746
|
+
}
|
|
37747
|
+
const width = this.targetWidth;
|
|
37748
|
+
let task;
|
|
37749
|
+
try {
|
|
37750
|
+
task = this.render(pageNum, width);
|
|
37751
|
+
} catch {
|
|
37752
|
+
this.failed.add(pageNum);
|
|
37753
|
+
return;
|
|
37754
|
+
}
|
|
37755
|
+
const pending = {
|
|
37756
|
+
task,
|
|
37757
|
+
width
|
|
37758
|
+
};
|
|
37759
|
+
this.activeCount += 1;
|
|
37760
|
+
this.inFlight.set(pageNum, pending);
|
|
37761
|
+
task.promise.then(result => this.handleRenderResult(pageNum, pending, result), () => this.handleRenderFailure(pageNum, pending)).then(() => this.finishRender(), () => this.finishRender());
|
|
37762
|
+
}
|
|
37763
|
+
clearInFlight(pageNum, pending) {
|
|
37764
|
+
if (this.inFlight.get(pageNum) !== pending) {
|
|
37765
|
+
return false;
|
|
37766
|
+
}
|
|
37767
|
+
this.inFlight.delete(pageNum);
|
|
37768
|
+
return true;
|
|
37769
|
+
}
|
|
37770
|
+
finishRender() {
|
|
37771
|
+
this.activeCount -= 1;
|
|
37772
|
+
this.pump();
|
|
37773
|
+
}
|
|
37774
|
+
handleRenderFailure(pageNum, pending) {
|
|
37775
|
+
if (this.clearInFlight(pageNum, pending) && this.isStillWanted(pageNum, pending)) {
|
|
37776
|
+
this.failed.add(pageNum);
|
|
37777
|
+
}
|
|
37778
|
+
}
|
|
37779
|
+
handleRenderResult(pageNum, pending, result) {
|
|
37780
|
+
if (!this.clearInFlight(pageNum, pending) || !result || !this.isStillWanted(pageNum, pending)) {
|
|
37781
|
+
return;
|
|
37782
|
+
}
|
|
37783
|
+
const {
|
|
37784
|
+
height,
|
|
37785
|
+
width
|
|
37786
|
+
} = result;
|
|
37787
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
|
|
37788
|
+
this.failed.add(pageNum);
|
|
37789
|
+
return;
|
|
37790
|
+
}
|
|
37791
|
+
const bytes = width * height * 4;
|
|
37792
|
+
const existing = this.cache.get(pageNum);
|
|
37793
|
+
const nextBytes = this.currentBytes - (existing?.bytes || 0) + bytes;
|
|
37794
|
+
if (nextBytes > this.maxBytes) {
|
|
37795
|
+
this.failed.add(pageNum);
|
|
37796
|
+
return;
|
|
37797
|
+
}
|
|
37798
|
+
this.cache.set(pageNum, HighResThumbnailStore_objectSpread(HighResThumbnailStore_objectSpread({}, result), {}, {
|
|
37799
|
+
bytes,
|
|
37800
|
+
requestedWidth: pending.width
|
|
37801
|
+
}));
|
|
37802
|
+
this.currentBytes = nextBytes;
|
|
37803
|
+
this.emit();
|
|
37804
|
+
}
|
|
37805
|
+
isStillWanted(pageNum, pending) {
|
|
37806
|
+
return !this.isDestroyed && this.targetWidth === pending.width && this.retained.has(pageNum);
|
|
37807
|
+
}
|
|
37808
|
+
}
|
|
37482
37809
|
;// ./src/lib/viewers/gallery/useGalleryPinch.ts
|
|
37483
37810
|
|
|
37484
37811
|
|
|
@@ -37613,12 +37940,20 @@ function GalleryGrid_toPrimitive(t, r) { if ("object" != typeof t || !t) return
|
|
|
37613
37940
|
|
|
37614
37941
|
|
|
37615
37942
|
|
|
37943
|
+
|
|
37616
37944
|
const GALLERY_THUMB_MAX_WIDTH = 440;
|
|
37617
37945
|
const CONCURRENT_LOADS = 4;
|
|
37618
37946
|
const SCROLL_THROTTLE_MS = 200;
|
|
37619
37947
|
// Keep in sync with the 100% grid rule in GalleryGrid.scss
|
|
37620
37948
|
const GALLERY_TILE_GAP = 16;
|
|
37621
37949
|
const GALLERY_TILE_MIN_WIDTH = 220;
|
|
37950
|
+
const GALLERY_THUMB_WIDTH_TIERS = [GALLERY_THUMB_MAX_WIDTH, GALLERY_THUMB_MAX_WIDTH * 2, GALLERY_THUMB_MAX_WIDTH * 3];
|
|
37951
|
+
const GALLERY_THUMB_MAX_TIER = GALLERY_THUMB_WIDTH_TIERS[GALLERY_THUMB_WIDTH_TIERS.length - 1];
|
|
37952
|
+
const GALLERY_THUMB_MAX_DPR = 2;
|
|
37953
|
+
const GALLERY_HIGH_RES_MAX_BYTES = 64 * 1024 * 1024;
|
|
37954
|
+
const GALLERY_HIGH_RES_MAX_PAGES = 16;
|
|
37955
|
+
const GALLERY_HIGH_RES_CONCURRENCY = 2;
|
|
37956
|
+
const GALLERY_DEFAULT_PAGE_RATIO = 0.775;
|
|
37622
37957
|
const GalleryTile = /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.memo(function GalleryTile({
|
|
37623
37958
|
pageNum,
|
|
37624
37959
|
isFocused,
|
|
@@ -37678,6 +38013,7 @@ function GalleryGrid({
|
|
|
37678
38013
|
thumbnail
|
|
37679
38014
|
}) {
|
|
37680
38015
|
const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
|
|
38016
|
+
const [highResImages, setHighResImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
|
|
37681
38017
|
const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
|
|
37682
38018
|
const [pageRatio, setPageRatio] = __WEBPACK_EXTERNAL_MODULE_react_useState__(null);
|
|
37683
38019
|
// Topmost visible page — the scroll anchor used to restore the viewed area after a reflow.
|
|
@@ -37690,37 +38026,56 @@ function GalleryGrid({
|
|
|
37690
38026
|
const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
|
|
37691
38027
|
const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
|
|
37692
38028
|
const inFlightRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(new Set());
|
|
38029
|
+
const highResStoreRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
|
|
37693
38030
|
const byDistanceFromAnchor = (a, b) => Math.abs(a - anchorPageRef.current) - Math.abs(b - anchorPageRef.current);
|
|
38031
|
+
function getNeededThumbWidth() {
|
|
38032
|
+
if (scaleRef.current === 1) {
|
|
38033
|
+
return GALLERY_THUMB_MAX_WIDTH;
|
|
38034
|
+
}
|
|
38035
|
+
const tile = gridRef.current?.querySelector('[data-page]');
|
|
38036
|
+
const neededWidth = (tile?.offsetWidth || 0) * Math.min(window.devicePixelRatio || 1, GALLERY_THUMB_MAX_DPR);
|
|
38037
|
+
return GALLERY_THUMB_WIDTH_TIERS.find(tier => tier >= neededWidth) || GALLERY_THUMB_MAX_TIER;
|
|
38038
|
+
}
|
|
37694
38039
|
|
|
37695
|
-
//
|
|
37696
|
-
|
|
37697
|
-
// (in flight) are excluded so re-derives can't waste loader slots on them.
|
|
37698
|
-
function getUnloadedNearViewport() {
|
|
38040
|
+
// Prioritize visible pages before spending work on the surrounding buffer.
|
|
38041
|
+
function getPagesNearViewport(marginRatio, isEligible) {
|
|
37699
38042
|
const grid = gridRef.current;
|
|
37700
38043
|
if (!grid) return [];
|
|
37701
38044
|
const {
|
|
37702
38045
|
scrollTop,
|
|
37703
38046
|
clientHeight
|
|
37704
38047
|
} = grid;
|
|
37705
|
-
const bufferZone = clientHeight * 3;
|
|
37706
38048
|
const viewportBottom = scrollTop + clientHeight;
|
|
37707
|
-
const
|
|
37708
|
-
const
|
|
37709
|
-
const
|
|
37710
|
-
|
|
37711
|
-
|
|
37712
|
-
|
|
37713
|
-
|
|
37714
|
-
|
|
37715
|
-
const
|
|
37716
|
-
const tileBottom = tileTop + el.offsetHeight;
|
|
38049
|
+
const margin = clientHeight * marginRatio;
|
|
38050
|
+
const visible = [];
|
|
38051
|
+
const nearby = [];
|
|
38052
|
+
grid.querySelectorAll('[data-page]').forEach(tile => {
|
|
38053
|
+
if (!tile.dataset.page) return;
|
|
38054
|
+
const pageNum = parseInt(tile.dataset.page, 10);
|
|
38055
|
+
if (isEligible && !isEligible(tile, pageNum)) return;
|
|
38056
|
+
const tileTop = tile.offsetTop;
|
|
38057
|
+
const tileBottom = tileTop + tile.offsetHeight;
|
|
37717
38058
|
if (tileBottom > scrollTop && tileTop < viewportBottom) {
|
|
37718
|
-
|
|
37719
|
-
} else if (tileBottom > scrollTop -
|
|
37720
|
-
|
|
38059
|
+
visible.push(pageNum);
|
|
38060
|
+
} else if (tileBottom > scrollTop - margin && tileTop < viewportBottom + margin) {
|
|
38061
|
+
nearby.push(pageNum);
|
|
37721
38062
|
}
|
|
37722
38063
|
});
|
|
37723
|
-
return [...
|
|
38064
|
+
return [...visible.sort(byDistanceFromAnchor), ...nearby.sort(byDistanceFromAnchor)];
|
|
38065
|
+
}
|
|
38066
|
+
function syncHighRes() {
|
|
38067
|
+
const store = highResStoreRef.current;
|
|
38068
|
+
if (!store) return;
|
|
38069
|
+
const width = getNeededThumbWidth();
|
|
38070
|
+
const ratio = thumbnail.pageRatio || GALLERY_DEFAULT_PAGE_RATIO;
|
|
38071
|
+
if (width === GALLERY_THUMB_MAX_WIDTH) {
|
|
38072
|
+
store.setRetained([], width, ratio);
|
|
38073
|
+
} else if (!isProcessingRef.current) {
|
|
38074
|
+
store.setRetained(getPagesNearViewport(0.5), width, ratio);
|
|
38075
|
+
}
|
|
38076
|
+
}
|
|
38077
|
+
function getUnloadedNearViewport() {
|
|
38078
|
+
return getPagesNearViewport(3, (tile, pageNum) => !inFlightRef.current.has(pageNum) && !tile.querySelector('img'));
|
|
37724
38079
|
}
|
|
37725
38080
|
function processQueue() {
|
|
37726
38081
|
if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
|
|
@@ -37750,6 +38105,7 @@ function GalleryGrid({
|
|
|
37750
38105
|
queueRef.current = getUnloadedNearViewport().filter(p => remaining.has(p));
|
|
37751
38106
|
if (queueRef.current.length === 0) {
|
|
37752
38107
|
isProcessingRef.current = false;
|
|
38108
|
+
syncHighRes();
|
|
37753
38109
|
return;
|
|
37754
38110
|
}
|
|
37755
38111
|
processQueue();
|
|
@@ -37788,6 +38144,7 @@ function GalleryGrid({
|
|
|
37788
38144
|
queueRef.current = [...toAdd, ...queueRef.current];
|
|
37789
38145
|
startProcessing();
|
|
37790
38146
|
}
|
|
38147
|
+
syncHighRes();
|
|
37791
38148
|
}, SCROLL_THROTTLE_MS));
|
|
37792
38149
|
|
|
37793
38150
|
// Unthrottled so the anchor is accurate the instant a reflow (e.g. fullscreen) happens.
|
|
@@ -37860,6 +38217,20 @@ function GalleryGrid({
|
|
|
37860
38217
|
}, [applyZoomLayout, scale]);
|
|
37861
38218
|
__WEBPACK_EXTERNAL_MODULE_react_useEffect__(() => {
|
|
37862
38219
|
const throttledScroll = handleScrollRef.current;
|
|
38220
|
+
const highResStore = new HighResThumbnailStore({
|
|
38221
|
+
maxBytes: GALLERY_HIGH_RES_MAX_BYTES,
|
|
38222
|
+
maxConcurrent: GALLERY_HIGH_RES_CONCURRENCY,
|
|
38223
|
+
maxPages: GALLERY_HIGH_RES_MAX_PAGES,
|
|
38224
|
+
onChange: images => {
|
|
38225
|
+
if (isMountedRef.current) {
|
|
38226
|
+
setHighResImages(images);
|
|
38227
|
+
}
|
|
38228
|
+
},
|
|
38229
|
+
render: (pageNum, width) => thumbnail.renderPageImage(pageNum, {
|
|
38230
|
+
thumbMaxWidth: width
|
|
38231
|
+
})
|
|
38232
|
+
});
|
|
38233
|
+
highResStoreRef.current = highResStore;
|
|
37863
38234
|
if (gridRef.current) {
|
|
37864
38235
|
const tile = gridRef.current.querySelector(`[data-page="${currentPage}"]`);
|
|
37865
38236
|
if (tile) {
|
|
@@ -37892,11 +38263,14 @@ function GalleryGrid({
|
|
|
37892
38263
|
// Guarded start: the mount scrollIntoView can fire the scroll handler first, and a
|
|
37893
38264
|
// second unguarded pump would double the concurrent thumbnail renders.
|
|
37894
38265
|
startProcessing();
|
|
38266
|
+
syncHighRes();
|
|
37895
38267
|
});
|
|
37896
38268
|
return () => {
|
|
37897
38269
|
isMountedRef.current = false;
|
|
37898
38270
|
queueRef.current = [];
|
|
37899
38271
|
isProcessingRef.current = false;
|
|
38272
|
+
highResStore.destroy();
|
|
38273
|
+
highResStoreRef.current = null;
|
|
37900
38274
|
throttledScroll.cancel();
|
|
37901
38275
|
};
|
|
37902
38276
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -37927,12 +38301,12 @@ function GalleryGrid({
|
|
|
37927
38301
|
observer.observe(grid);
|
|
37928
38302
|
return () => observer.disconnect();
|
|
37929
38303
|
}, [applyZoomLayout]);
|
|
37930
|
-
const focusTile = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(pageNum => {
|
|
38304
|
+
const focusTile = __WEBPACK_EXTERNAL_MODULE_react_useCallback__((pageNum, options) => {
|
|
37931
38305
|
const grid = gridRef.current;
|
|
37932
38306
|
if (!grid) return;
|
|
37933
38307
|
const tile = grid.querySelector(`[data-page="${pageNum}"]`);
|
|
37934
38308
|
if (tile) {
|
|
37935
|
-
tile.focus();
|
|
38309
|
+
tile.focus(options);
|
|
37936
38310
|
}
|
|
37937
38311
|
}, []);
|
|
37938
38312
|
const handleTileFocus = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(pageNum => {
|
|
@@ -37946,7 +38320,9 @@ function GalleryGrid({
|
|
|
37946
38320
|
}, [onPageNavigate]);
|
|
37947
38321
|
const handleGridFocus = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(event => {
|
|
37948
38322
|
if (event.target === gridRef.current) {
|
|
37949
|
-
focusTile(focusedPage
|
|
38323
|
+
focusTile(focusedPage, {
|
|
38324
|
+
preventScroll: true
|
|
38325
|
+
});
|
|
37950
38326
|
}
|
|
37951
38327
|
}, [focusedPage, focusTile]);
|
|
37952
38328
|
const handleGridKeyDown = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(event => {
|
|
@@ -37997,7 +38373,7 @@ function GalleryGrid({
|
|
|
37997
38373
|
for (let i = 1; i <= pageCount; i += 1) {
|
|
37998
38374
|
tiles.push(/*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryTile, {
|
|
37999
38375
|
key: i,
|
|
38000
|
-
imageSrc: loadedImages[i],
|
|
38376
|
+
imageSrc: highResImages[i] || loadedImages[i],
|
|
38001
38377
|
isFocused: i === focusedPage,
|
|
38002
38378
|
onClick: handleTileClick,
|
|
38003
38379
|
onFocus: handleTileFocus,
|
|
@@ -49561,7 +49937,11 @@ class Preview extends (events_default()) {
|
|
|
49561
49937
|
* @return {Object} Headers
|
|
49562
49938
|
*/
|
|
49563
49939
|
getRequestHeaders(token) {
|
|
49564
|
-
const
|
|
49940
|
+
const isDash = lib_Browser.canPlayDash() && !this.disabledViewers.Dash;
|
|
49941
|
+
let videoHint = isDash ? X_REP_HINT_VIDEO_DASH : X_REP_HINT_VIDEO_MP4;
|
|
49942
|
+
if (isDash && isFeatureEnabled(this.options.features, AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES)) {
|
|
49943
|
+
videoHint += X_REP_HINT_VIDEO_DASH_EXTRACTED_TEXT;
|
|
49944
|
+
}
|
|
49565
49945
|
const headers = {
|
|
49566
49946
|
'X-Rep-Hints': `${X_REP_HINT_BASE}${X_REP_HINT_DOC_THUMBNAIL}${X_REP_HINT_IMAGE}${videoHint}`
|
|
49567
49947
|
};
|