box-content-preview 3.72.0 → 3.73.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 +341 -56
- 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.73.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.73.0/en-US/preview.js
|
|
29
|
+
https://cdn01.boxcdn.net/platform/preview/3.73.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.73.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.73.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.73.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.73.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 = {};
|
|
@@ -17083,7 +17083,7 @@ class Browser {
|
|
|
17083
17083
|
;// ./src/lib/Logger.js
|
|
17084
17084
|
/* eslint-disable no-undef */
|
|
17085
17085
|
const Logger_CLIENT_NAME = "box-content-preview";
|
|
17086
|
-
const Logger_CLIENT_VERSION = "3.
|
|
17086
|
+
const Logger_CLIENT_VERSION = "3.73.0";
|
|
17087
17087
|
/* eslint-enable no-undef */
|
|
17088
17088
|
|
|
17089
17089
|
class Logger {
|
|
@@ -37237,10 +37237,17 @@ function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string")
|
|
|
37237
37237
|
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
37238
|
|
|
37239
37239
|
|
|
37240
|
+
|
|
37240
37241
|
const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
|
|
37241
37242
|
const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
|
|
37242
37243
|
const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
|
|
37243
37244
|
|
|
37245
|
+
function createRejectedTask(message) {
|
|
37246
|
+
return {
|
|
37247
|
+
cancel: (noop_default()),
|
|
37248
|
+
promise: Promise.reject(new Error(message))
|
|
37249
|
+
};
|
|
37250
|
+
}
|
|
37244
37251
|
class Thumbnail {
|
|
37245
37252
|
/**
|
|
37246
37253
|
* [constructor]
|
|
@@ -37252,13 +37259,17 @@ class Thumbnail {
|
|
|
37252
37259
|
Thumbnail_defineProperty(this, "pdfViewer", void 0);
|
|
37253
37260
|
/** @property {Object} - Cache for the thumbnail image elements */
|
|
37254
37261
|
Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
|
|
37262
|
+
/** @property {Set} - Active PDF.js render tasks */
|
|
37263
|
+
Thumbnail_defineProperty(this, "renderTasks", void 0);
|
|
37255
37264
|
Thumbnail_defineProperty(this, "preloader", void 0);
|
|
37256
37265
|
this.preloader = preloader;
|
|
37257
37266
|
this.createImageEl = this.createImageEl.bind(this);
|
|
37258
37267
|
this.createThumbnailImage = this.createThumbnailImage.bind(this);
|
|
37259
37268
|
this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
|
|
37269
|
+
this.renderPageImage = this.renderPageImage.bind(this);
|
|
37260
37270
|
this.pdfViewer = pdfViewer;
|
|
37261
37271
|
this.thumbnailImageCache = new lib_BoundedCache();
|
|
37272
|
+
this.renderTasks = new Set();
|
|
37262
37273
|
}
|
|
37263
37274
|
|
|
37264
37275
|
/**
|
|
@@ -37267,6 +37278,11 @@ class Thumbnail {
|
|
|
37267
37278
|
* @return {void}
|
|
37268
37279
|
*/
|
|
37269
37280
|
destroy() {
|
|
37281
|
+
if (this.renderTasks) {
|
|
37282
|
+
this.renderTasks.forEach(task => task.cancel());
|
|
37283
|
+
this.renderTasks.clear();
|
|
37284
|
+
this.renderTasks = null;
|
|
37285
|
+
}
|
|
37270
37286
|
if (this.thumbnailImageCache) {
|
|
37271
37287
|
this.thumbnailImageCache.destroy();
|
|
37272
37288
|
this.thumbnailImageCache = null;
|
|
@@ -37385,6 +37401,12 @@ class Thumbnail {
|
|
|
37385
37401
|
if (!this.thumbnailImageCache) {
|
|
37386
37402
|
return null;
|
|
37387
37403
|
}
|
|
37404
|
+
if (!dataUrl) {
|
|
37405
|
+
this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
|
|
37406
|
+
inProgress: false
|
|
37407
|
+
}));
|
|
37408
|
+
return null;
|
|
37409
|
+
}
|
|
37388
37410
|
const imageEl = this.createImageEl(dataUrl, thumbOptions);
|
|
37389
37411
|
// Cache this image element for future use
|
|
37390
37412
|
this.thumbnailImageCache.set(itemIndex, {
|
|
@@ -37414,22 +37436,35 @@ class Thumbnail {
|
|
|
37414
37436
|
}
|
|
37415
37437
|
|
|
37416
37438
|
/**
|
|
37417
|
-
*
|
|
37418
|
-
* @param {number} pageNum
|
|
37419
|
-
* @
|
|
37439
|
+
* Renders a page image without caching it.
|
|
37440
|
+
* @param {number} pageNum - The page number of the document (1 indexed)
|
|
37441
|
+
* @param {Object} thumbOptions - Thumbnail render options
|
|
37442
|
+
* @return {Object} A cancellable render task
|
|
37420
37443
|
*/
|
|
37421
|
-
|
|
37422
|
-
if (this.preloader?.preloadedImages?.[pageNum]) {
|
|
37423
|
-
return Promise.resolve(this.preloader.preloadedImages[pageNum]);
|
|
37424
|
-
}
|
|
37444
|
+
renderPageImage(pageNum, thumbOptions) {
|
|
37425
37445
|
const pdfDocument = this.pdfViewer?.pdfDocument;
|
|
37426
37446
|
if (!pdfDocument) {
|
|
37427
|
-
return
|
|
37447
|
+
return createRejectedTask('PDF document not ready');
|
|
37428
37448
|
}
|
|
37429
|
-
const canvas = document.createElement('canvas');
|
|
37430
37449
|
const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
|
|
37431
|
-
|
|
37432
|
-
|
|
37450
|
+
if (!isFinite_default()(thumbnailImageWidth) || thumbnailImageWidth <= 0) {
|
|
37451
|
+
return createRejectedTask('Invalid thumbnail render dimensions');
|
|
37452
|
+
}
|
|
37453
|
+
const canvas = document.createElement('canvas');
|
|
37454
|
+
let isCancelled = false;
|
|
37455
|
+
let pdfRenderTask = null;
|
|
37456
|
+
const task = {
|
|
37457
|
+
cancel: () => {
|
|
37458
|
+
if (isCancelled) {
|
|
37459
|
+
return;
|
|
37460
|
+
}
|
|
37461
|
+
isCancelled = true;
|
|
37462
|
+
pdfRenderTask?.cancel();
|
|
37463
|
+
},
|
|
37464
|
+
promise: null
|
|
37465
|
+
};
|
|
37466
|
+
task.promise = pdfDocument.getPage(pageNum).then(page => {
|
|
37467
|
+
if (isCancelled || !this.thumbnailImageCache) {
|
|
37433
37468
|
return null;
|
|
37434
37469
|
}
|
|
37435
37470
|
const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
|
|
@@ -37437,48 +37472,249 @@ class Thumbnail {
|
|
|
37437
37472
|
scale: 1,
|
|
37438
37473
|
rotation
|
|
37439
37474
|
});
|
|
37440
|
-
if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
|
|
37475
|
+
if (!viewport || !isFinite_default()(viewport.width) || viewport.width <= 0 || !isFinite_default()(viewport.height) || viewport.height <= 0) {
|
|
37441
37476
|
return Promise.reject(new Error('Invalid page viewport'));
|
|
37442
37477
|
}
|
|
37443
37478
|
const {
|
|
37444
37479
|
width,
|
|
37445
37480
|
height
|
|
37446
37481
|
} = 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
|
|
37482
|
+
const currentPageRatio = width / height;
|
|
37483
|
+
|
|
37484
|
+
// More-portrait pages are constrained by the first page's height budget.
|
|
37485
|
+
if (currentPageRatio < this.pageRatio) {
|
|
37455
37486
|
canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
|
|
37456
|
-
|
|
37457
|
-
canvas.width = canvas.height * curPageRatio;
|
|
37487
|
+
canvas.width = canvas.height * currentPageRatio;
|
|
37458
37488
|
} 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
37489
|
canvas.width = thumbnailImageWidth;
|
|
37463
|
-
|
|
37464
|
-
canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
|
|
37490
|
+
canvas.height = Math.ceil(thumbnailImageWidth / currentPageRatio);
|
|
37465
37491
|
}
|
|
37466
|
-
// The amount for which to scale down the current page
|
|
37467
37492
|
const {
|
|
37468
37493
|
width: canvasWidth
|
|
37469
37494
|
} = canvas;
|
|
37470
37495
|
const scale = canvasWidth / width;
|
|
37471
|
-
|
|
37496
|
+
pdfRenderTask = page.render({
|
|
37472
37497
|
canvasContext: canvas.getContext('2d'),
|
|
37473
37498
|
viewport: page.getViewport({
|
|
37474
37499
|
scale,
|
|
37475
37500
|
rotation
|
|
37476
37501
|
})
|
|
37477
|
-
})
|
|
37478
|
-
|
|
37502
|
+
});
|
|
37503
|
+
return pdfRenderTask.promise.then(() => {
|
|
37504
|
+
if (isCancelled || !this.thumbnailImageCache) {
|
|
37505
|
+
return null;
|
|
37506
|
+
}
|
|
37507
|
+
return {
|
|
37508
|
+
dataUrl: canvas.toDataURL(),
|
|
37509
|
+
height: canvas.height,
|
|
37510
|
+
width: canvas.width
|
|
37511
|
+
};
|
|
37512
|
+
});
|
|
37513
|
+
}).catch(error => {
|
|
37514
|
+
if (isCancelled) {
|
|
37515
|
+
return null;
|
|
37516
|
+
}
|
|
37517
|
+
throw error;
|
|
37518
|
+
}).finally(() => {
|
|
37519
|
+
canvas.width = 0;
|
|
37520
|
+
canvas.height = 0;
|
|
37521
|
+
this.renderTasks?.delete(task);
|
|
37522
|
+
});
|
|
37523
|
+
this.renderTasks.add(task);
|
|
37524
|
+
return task;
|
|
37525
|
+
}
|
|
37526
|
+
|
|
37527
|
+
/**
|
|
37528
|
+
* Given a page number, generates the image data URL for the image of the page
|
|
37529
|
+
* @param {number} pageNum - The page number of the document
|
|
37530
|
+
* @return {string} The data URL of the page image
|
|
37531
|
+
*/
|
|
37532
|
+
getThumbnailDataURL(pageNum, thumbOptions) {
|
|
37533
|
+
if (this.preloader?.preloadedImages?.[pageNum]) {
|
|
37534
|
+
return Promise.resolve(this.preloader.preloadedImages[pageNum]);
|
|
37535
|
+
}
|
|
37536
|
+
return this.renderPageImage(pageNum, thumbOptions).promise.then(result => result?.dataUrl || null);
|
|
37479
37537
|
}
|
|
37480
37538
|
}
|
|
37481
37539
|
/* harmony default export */ const lib_Thumbnail = (Thumbnail);
|
|
37540
|
+
;// ./src/lib/viewers/gallery/HighResThumbnailStore.ts
|
|
37541
|
+
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; }
|
|
37542
|
+
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; }
|
|
37543
|
+
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; }
|
|
37544
|
+
function HighResThumbnailStore_toPropertyKey(t) { var i = HighResThumbnailStore_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
37545
|
+
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); }
|
|
37546
|
+
class HighResThumbnailStore {
|
|
37547
|
+
constructor({
|
|
37548
|
+
maxBytes,
|
|
37549
|
+
maxConcurrent,
|
|
37550
|
+
maxPages,
|
|
37551
|
+
onChange,
|
|
37552
|
+
render
|
|
37553
|
+
}) {
|
|
37554
|
+
HighResThumbnailStore_defineProperty(this, "activeCount", 0);
|
|
37555
|
+
HighResThumbnailStore_defineProperty(this, "cache", new Map());
|
|
37556
|
+
HighResThumbnailStore_defineProperty(this, "currentBytes", 0);
|
|
37557
|
+
HighResThumbnailStore_defineProperty(this, "failed", new Set());
|
|
37558
|
+
HighResThumbnailStore_defineProperty(this, "inFlight", new Map());
|
|
37559
|
+
HighResThumbnailStore_defineProperty(this, "isDestroyed", false);
|
|
37560
|
+
HighResThumbnailStore_defineProperty(this, "maxBytes", void 0);
|
|
37561
|
+
HighResThumbnailStore_defineProperty(this, "maxConcurrent", void 0);
|
|
37562
|
+
HighResThumbnailStore_defineProperty(this, "maxPages", void 0);
|
|
37563
|
+
HighResThumbnailStore_defineProperty(this, "onChange", void 0);
|
|
37564
|
+
HighResThumbnailStore_defineProperty(this, "queue", []);
|
|
37565
|
+
HighResThumbnailStore_defineProperty(this, "render", void 0);
|
|
37566
|
+
HighResThumbnailStore_defineProperty(this, "retained", new Set());
|
|
37567
|
+
HighResThumbnailStore_defineProperty(this, "targetWidth", 0);
|
|
37568
|
+
this.maxBytes = maxBytes;
|
|
37569
|
+
this.maxConcurrent = maxConcurrent;
|
|
37570
|
+
this.maxPages = maxPages;
|
|
37571
|
+
this.onChange = onChange;
|
|
37572
|
+
this.render = render;
|
|
37573
|
+
}
|
|
37574
|
+
setRetained(pages, width, pageRatio) {
|
|
37575
|
+
if (this.isDestroyed) {
|
|
37576
|
+
return;
|
|
37577
|
+
}
|
|
37578
|
+
const previousWidth = this.targetWidth;
|
|
37579
|
+
this.targetWidth = width;
|
|
37580
|
+
if (previousWidth !== width) {
|
|
37581
|
+
this.failed.clear();
|
|
37582
|
+
}
|
|
37583
|
+
const ratio = Number.isFinite(pageRatio) && pageRatio > 0 ? pageRatio : 1;
|
|
37584
|
+
const estimatedBytes = width * Math.ceil(width / ratio) * 4;
|
|
37585
|
+
const pageLimit = Math.min(this.maxPages, Math.floor(this.maxBytes / estimatedBytes));
|
|
37586
|
+
const retainedPages = Array.from(new Set(pages)).slice(0, pageLimit);
|
|
37587
|
+
const retainedSet = new Set(retainedPages);
|
|
37588
|
+
this.retained = retainedSet;
|
|
37589
|
+
this.failed.forEach(pageNum => {
|
|
37590
|
+
if (!retainedSet.has(pageNum)) {
|
|
37591
|
+
this.failed.delete(pageNum);
|
|
37592
|
+
}
|
|
37593
|
+
});
|
|
37594
|
+
let didEvict = false;
|
|
37595
|
+
this.cache.forEach((entry, pageNum) => {
|
|
37596
|
+
if (!this.retained.has(pageNum) || entry.requestedWidth !== width) {
|
|
37597
|
+
this.cache.delete(pageNum);
|
|
37598
|
+
this.currentBytes -= entry.bytes;
|
|
37599
|
+
didEvict = true;
|
|
37600
|
+
}
|
|
37601
|
+
});
|
|
37602
|
+
this.inFlight.forEach((pending, pageNum) => {
|
|
37603
|
+
if (!this.retained.has(pageNum) || pending.width !== width) {
|
|
37604
|
+
pending.task.cancel();
|
|
37605
|
+
this.inFlight.delete(pageNum);
|
|
37606
|
+
}
|
|
37607
|
+
});
|
|
37608
|
+
this.queue = retainedPages.filter(pageNum => !this.cache.has(pageNum) && !this.inFlight.has(pageNum) && !this.failed.has(pageNum));
|
|
37609
|
+
if (didEvict) {
|
|
37610
|
+
this.emit();
|
|
37611
|
+
}
|
|
37612
|
+
this.pump();
|
|
37613
|
+
}
|
|
37614
|
+
destroy() {
|
|
37615
|
+
if (this.isDestroyed) {
|
|
37616
|
+
return;
|
|
37617
|
+
}
|
|
37618
|
+
this.isDestroyed = true;
|
|
37619
|
+
this.inFlight.forEach(({
|
|
37620
|
+
task
|
|
37621
|
+
}) => task.cancel());
|
|
37622
|
+
this.inFlight.clear();
|
|
37623
|
+
this.cache.clear();
|
|
37624
|
+
this.failed.clear();
|
|
37625
|
+
this.queue = [];
|
|
37626
|
+
this.retained.clear();
|
|
37627
|
+
this.currentBytes = 0;
|
|
37628
|
+
this.onChange = null;
|
|
37629
|
+
this.render = null;
|
|
37630
|
+
}
|
|
37631
|
+
emit() {
|
|
37632
|
+
if (!this.onChange) {
|
|
37633
|
+
return;
|
|
37634
|
+
}
|
|
37635
|
+
const images = {};
|
|
37636
|
+
this.cache.forEach((entry, pageNum) => {
|
|
37637
|
+
images[pageNum] = entry.dataUrl;
|
|
37638
|
+
});
|
|
37639
|
+
this.onChange(images);
|
|
37640
|
+
}
|
|
37641
|
+
pump() {
|
|
37642
|
+
if (this.isDestroyed || !this.render) {
|
|
37643
|
+
return;
|
|
37644
|
+
}
|
|
37645
|
+
while (this.activeCount < this.maxConcurrent && this.queue.length > 0) {
|
|
37646
|
+
const pageNum = this.queue.shift();
|
|
37647
|
+
if (pageNum && this.retained.has(pageNum)) {
|
|
37648
|
+
this.startRender(pageNum);
|
|
37649
|
+
}
|
|
37650
|
+
}
|
|
37651
|
+
}
|
|
37652
|
+
startRender(pageNum) {
|
|
37653
|
+
if (!this.render) {
|
|
37654
|
+
return;
|
|
37655
|
+
}
|
|
37656
|
+
const width = this.targetWidth;
|
|
37657
|
+
let task;
|
|
37658
|
+
try {
|
|
37659
|
+
task = this.render(pageNum, width);
|
|
37660
|
+
} catch {
|
|
37661
|
+
this.failed.add(pageNum);
|
|
37662
|
+
return;
|
|
37663
|
+
}
|
|
37664
|
+
const pending = {
|
|
37665
|
+
task,
|
|
37666
|
+
width
|
|
37667
|
+
};
|
|
37668
|
+
this.activeCount += 1;
|
|
37669
|
+
this.inFlight.set(pageNum, pending);
|
|
37670
|
+
task.promise.then(result => this.handleRenderResult(pageNum, pending, result), () => this.handleRenderFailure(pageNum, pending)).then(() => this.finishRender(), () => this.finishRender());
|
|
37671
|
+
}
|
|
37672
|
+
clearInFlight(pageNum, pending) {
|
|
37673
|
+
if (this.inFlight.get(pageNum) !== pending) {
|
|
37674
|
+
return false;
|
|
37675
|
+
}
|
|
37676
|
+
this.inFlight.delete(pageNum);
|
|
37677
|
+
return true;
|
|
37678
|
+
}
|
|
37679
|
+
finishRender() {
|
|
37680
|
+
this.activeCount -= 1;
|
|
37681
|
+
this.pump();
|
|
37682
|
+
}
|
|
37683
|
+
handleRenderFailure(pageNum, pending) {
|
|
37684
|
+
if (this.clearInFlight(pageNum, pending) && this.isStillWanted(pageNum, pending)) {
|
|
37685
|
+
this.failed.add(pageNum);
|
|
37686
|
+
}
|
|
37687
|
+
}
|
|
37688
|
+
handleRenderResult(pageNum, pending, result) {
|
|
37689
|
+
if (!this.clearInFlight(pageNum, pending) || !result || !this.isStillWanted(pageNum, pending)) {
|
|
37690
|
+
return;
|
|
37691
|
+
}
|
|
37692
|
+
const {
|
|
37693
|
+
height,
|
|
37694
|
+
width
|
|
37695
|
+
} = result;
|
|
37696
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
|
|
37697
|
+
this.failed.add(pageNum);
|
|
37698
|
+
return;
|
|
37699
|
+
}
|
|
37700
|
+
const bytes = width * height * 4;
|
|
37701
|
+
const existing = this.cache.get(pageNum);
|
|
37702
|
+
const nextBytes = this.currentBytes - (existing?.bytes || 0) + bytes;
|
|
37703
|
+
if (nextBytes > this.maxBytes) {
|
|
37704
|
+
this.failed.add(pageNum);
|
|
37705
|
+
return;
|
|
37706
|
+
}
|
|
37707
|
+
this.cache.set(pageNum, HighResThumbnailStore_objectSpread(HighResThumbnailStore_objectSpread({}, result), {}, {
|
|
37708
|
+
bytes,
|
|
37709
|
+
requestedWidth: pending.width
|
|
37710
|
+
}));
|
|
37711
|
+
this.currentBytes = nextBytes;
|
|
37712
|
+
this.emit();
|
|
37713
|
+
}
|
|
37714
|
+
isStillWanted(pageNum, pending) {
|
|
37715
|
+
return !this.isDestroyed && this.targetWidth === pending.width && this.retained.has(pageNum);
|
|
37716
|
+
}
|
|
37717
|
+
}
|
|
37482
37718
|
;// ./src/lib/viewers/gallery/useGalleryPinch.ts
|
|
37483
37719
|
|
|
37484
37720
|
|
|
@@ -37613,12 +37849,20 @@ function GalleryGrid_toPrimitive(t, r) { if ("object" != typeof t || !t) return
|
|
|
37613
37849
|
|
|
37614
37850
|
|
|
37615
37851
|
|
|
37852
|
+
|
|
37616
37853
|
const GALLERY_THUMB_MAX_WIDTH = 440;
|
|
37617
37854
|
const CONCURRENT_LOADS = 4;
|
|
37618
37855
|
const SCROLL_THROTTLE_MS = 200;
|
|
37619
37856
|
// Keep in sync with the 100% grid rule in GalleryGrid.scss
|
|
37620
37857
|
const GALLERY_TILE_GAP = 16;
|
|
37621
37858
|
const GALLERY_TILE_MIN_WIDTH = 220;
|
|
37859
|
+
const GALLERY_THUMB_WIDTH_TIERS = [GALLERY_THUMB_MAX_WIDTH, GALLERY_THUMB_MAX_WIDTH * 2, GALLERY_THUMB_MAX_WIDTH * 3];
|
|
37860
|
+
const GALLERY_THUMB_MAX_TIER = GALLERY_THUMB_WIDTH_TIERS[GALLERY_THUMB_WIDTH_TIERS.length - 1];
|
|
37861
|
+
const GALLERY_THUMB_MAX_DPR = 2;
|
|
37862
|
+
const GALLERY_HIGH_RES_MAX_BYTES = 64 * 1024 * 1024;
|
|
37863
|
+
const GALLERY_HIGH_RES_MAX_PAGES = 16;
|
|
37864
|
+
const GALLERY_HIGH_RES_CONCURRENCY = 2;
|
|
37865
|
+
const GALLERY_DEFAULT_PAGE_RATIO = 0.775;
|
|
37622
37866
|
const GalleryTile = /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.memo(function GalleryTile({
|
|
37623
37867
|
pageNum,
|
|
37624
37868
|
isFocused,
|
|
@@ -37678,6 +37922,7 @@ function GalleryGrid({
|
|
|
37678
37922
|
thumbnail
|
|
37679
37923
|
}) {
|
|
37680
37924
|
const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
|
|
37925
|
+
const [highResImages, setHighResImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
|
|
37681
37926
|
const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
|
|
37682
37927
|
const [pageRatio, setPageRatio] = __WEBPACK_EXTERNAL_MODULE_react_useState__(null);
|
|
37683
37928
|
// Topmost visible page — the scroll anchor used to restore the viewed area after a reflow.
|
|
@@ -37690,37 +37935,56 @@ function GalleryGrid({
|
|
|
37690
37935
|
const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
|
|
37691
37936
|
const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
|
|
37692
37937
|
const inFlightRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(new Set());
|
|
37938
|
+
const highResStoreRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
|
|
37693
37939
|
const byDistanceFromAnchor = (a, b) => Math.abs(a - anchorPageRef.current) - Math.abs(b - anchorPageRef.current);
|
|
37940
|
+
function getNeededThumbWidth() {
|
|
37941
|
+
if (scaleRef.current === 1) {
|
|
37942
|
+
return GALLERY_THUMB_MAX_WIDTH;
|
|
37943
|
+
}
|
|
37944
|
+
const tile = gridRef.current?.querySelector('[data-page]');
|
|
37945
|
+
const neededWidth = (tile?.offsetWidth || 0) * Math.min(window.devicePixelRatio || 1, GALLERY_THUMB_MAX_DPR);
|
|
37946
|
+
return GALLERY_THUMB_WIDTH_TIERS.find(tier => tier >= neededWidth) || GALLERY_THUMB_MAX_TIER;
|
|
37947
|
+
}
|
|
37694
37948
|
|
|
37695
|
-
//
|
|
37696
|
-
|
|
37697
|
-
// (in flight) are excluded so re-derives can't waste loader slots on them.
|
|
37698
|
-
function getUnloadedNearViewport() {
|
|
37949
|
+
// Prioritize visible pages before spending work on the surrounding buffer.
|
|
37950
|
+
function getPagesNearViewport(marginRatio, isEligible) {
|
|
37699
37951
|
const grid = gridRef.current;
|
|
37700
37952
|
if (!grid) return [];
|
|
37701
37953
|
const {
|
|
37702
37954
|
scrollTop,
|
|
37703
37955
|
clientHeight
|
|
37704
37956
|
} = grid;
|
|
37705
|
-
const bufferZone = clientHeight * 3;
|
|
37706
37957
|
const viewportBottom = scrollTop + clientHeight;
|
|
37707
|
-
const
|
|
37708
|
-
const
|
|
37709
|
-
const
|
|
37710
|
-
|
|
37711
|
-
|
|
37712
|
-
|
|
37713
|
-
|
|
37714
|
-
|
|
37715
|
-
const
|
|
37716
|
-
const tileBottom = tileTop + el.offsetHeight;
|
|
37958
|
+
const margin = clientHeight * marginRatio;
|
|
37959
|
+
const visible = [];
|
|
37960
|
+
const nearby = [];
|
|
37961
|
+
grid.querySelectorAll('[data-page]').forEach(tile => {
|
|
37962
|
+
if (!tile.dataset.page) return;
|
|
37963
|
+
const pageNum = parseInt(tile.dataset.page, 10);
|
|
37964
|
+
if (isEligible && !isEligible(tile, pageNum)) return;
|
|
37965
|
+
const tileTop = tile.offsetTop;
|
|
37966
|
+
const tileBottom = tileTop + tile.offsetHeight;
|
|
37717
37967
|
if (tileBottom > scrollTop && tileTop < viewportBottom) {
|
|
37718
|
-
|
|
37719
|
-
} else if (tileBottom > scrollTop -
|
|
37720
|
-
|
|
37968
|
+
visible.push(pageNum);
|
|
37969
|
+
} else if (tileBottom > scrollTop - margin && tileTop < viewportBottom + margin) {
|
|
37970
|
+
nearby.push(pageNum);
|
|
37721
37971
|
}
|
|
37722
37972
|
});
|
|
37723
|
-
return [...
|
|
37973
|
+
return [...visible.sort(byDistanceFromAnchor), ...nearby.sort(byDistanceFromAnchor)];
|
|
37974
|
+
}
|
|
37975
|
+
function syncHighRes() {
|
|
37976
|
+
const store = highResStoreRef.current;
|
|
37977
|
+
if (!store) return;
|
|
37978
|
+
const width = getNeededThumbWidth();
|
|
37979
|
+
const ratio = thumbnail.pageRatio || GALLERY_DEFAULT_PAGE_RATIO;
|
|
37980
|
+
if (width === GALLERY_THUMB_MAX_WIDTH) {
|
|
37981
|
+
store.setRetained([], width, ratio);
|
|
37982
|
+
} else if (!isProcessingRef.current) {
|
|
37983
|
+
store.setRetained(getPagesNearViewport(0.5), width, ratio);
|
|
37984
|
+
}
|
|
37985
|
+
}
|
|
37986
|
+
function getUnloadedNearViewport() {
|
|
37987
|
+
return getPagesNearViewport(3, (tile, pageNum) => !inFlightRef.current.has(pageNum) && !tile.querySelector('img'));
|
|
37724
37988
|
}
|
|
37725
37989
|
function processQueue() {
|
|
37726
37990
|
if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
|
|
@@ -37750,6 +38014,7 @@ function GalleryGrid({
|
|
|
37750
38014
|
queueRef.current = getUnloadedNearViewport().filter(p => remaining.has(p));
|
|
37751
38015
|
if (queueRef.current.length === 0) {
|
|
37752
38016
|
isProcessingRef.current = false;
|
|
38017
|
+
syncHighRes();
|
|
37753
38018
|
return;
|
|
37754
38019
|
}
|
|
37755
38020
|
processQueue();
|
|
@@ -37788,6 +38053,7 @@ function GalleryGrid({
|
|
|
37788
38053
|
queueRef.current = [...toAdd, ...queueRef.current];
|
|
37789
38054
|
startProcessing();
|
|
37790
38055
|
}
|
|
38056
|
+
syncHighRes();
|
|
37791
38057
|
}, SCROLL_THROTTLE_MS));
|
|
37792
38058
|
|
|
37793
38059
|
// Unthrottled so the anchor is accurate the instant a reflow (e.g. fullscreen) happens.
|
|
@@ -37860,6 +38126,20 @@ function GalleryGrid({
|
|
|
37860
38126
|
}, [applyZoomLayout, scale]);
|
|
37861
38127
|
__WEBPACK_EXTERNAL_MODULE_react_useEffect__(() => {
|
|
37862
38128
|
const throttledScroll = handleScrollRef.current;
|
|
38129
|
+
const highResStore = new HighResThumbnailStore({
|
|
38130
|
+
maxBytes: GALLERY_HIGH_RES_MAX_BYTES,
|
|
38131
|
+
maxConcurrent: GALLERY_HIGH_RES_CONCURRENCY,
|
|
38132
|
+
maxPages: GALLERY_HIGH_RES_MAX_PAGES,
|
|
38133
|
+
onChange: images => {
|
|
38134
|
+
if (isMountedRef.current) {
|
|
38135
|
+
setHighResImages(images);
|
|
38136
|
+
}
|
|
38137
|
+
},
|
|
38138
|
+
render: (pageNum, width) => thumbnail.renderPageImage(pageNum, {
|
|
38139
|
+
thumbMaxWidth: width
|
|
38140
|
+
})
|
|
38141
|
+
});
|
|
38142
|
+
highResStoreRef.current = highResStore;
|
|
37863
38143
|
if (gridRef.current) {
|
|
37864
38144
|
const tile = gridRef.current.querySelector(`[data-page="${currentPage}"]`);
|
|
37865
38145
|
if (tile) {
|
|
@@ -37892,11 +38172,14 @@ function GalleryGrid({
|
|
|
37892
38172
|
// Guarded start: the mount scrollIntoView can fire the scroll handler first, and a
|
|
37893
38173
|
// second unguarded pump would double the concurrent thumbnail renders.
|
|
37894
38174
|
startProcessing();
|
|
38175
|
+
syncHighRes();
|
|
37895
38176
|
});
|
|
37896
38177
|
return () => {
|
|
37897
38178
|
isMountedRef.current = false;
|
|
37898
38179
|
queueRef.current = [];
|
|
37899
38180
|
isProcessingRef.current = false;
|
|
38181
|
+
highResStore.destroy();
|
|
38182
|
+
highResStoreRef.current = null;
|
|
37900
38183
|
throttledScroll.cancel();
|
|
37901
38184
|
};
|
|
37902
38185
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -37927,12 +38210,12 @@ function GalleryGrid({
|
|
|
37927
38210
|
observer.observe(grid);
|
|
37928
38211
|
return () => observer.disconnect();
|
|
37929
38212
|
}, [applyZoomLayout]);
|
|
37930
|
-
const focusTile = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(pageNum => {
|
|
38213
|
+
const focusTile = __WEBPACK_EXTERNAL_MODULE_react_useCallback__((pageNum, options) => {
|
|
37931
38214
|
const grid = gridRef.current;
|
|
37932
38215
|
if (!grid) return;
|
|
37933
38216
|
const tile = grid.querySelector(`[data-page="${pageNum}"]`);
|
|
37934
38217
|
if (tile) {
|
|
37935
|
-
tile.focus();
|
|
38218
|
+
tile.focus(options);
|
|
37936
38219
|
}
|
|
37937
38220
|
}, []);
|
|
37938
38221
|
const handleTileFocus = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(pageNum => {
|
|
@@ -37946,7 +38229,9 @@ function GalleryGrid({
|
|
|
37946
38229
|
}, [onPageNavigate]);
|
|
37947
38230
|
const handleGridFocus = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(event => {
|
|
37948
38231
|
if (event.target === gridRef.current) {
|
|
37949
|
-
focusTile(focusedPage
|
|
38232
|
+
focusTile(focusedPage, {
|
|
38233
|
+
preventScroll: true
|
|
38234
|
+
});
|
|
37950
38235
|
}
|
|
37951
38236
|
}, [focusedPage, focusTile]);
|
|
37952
38237
|
const handleGridKeyDown = __WEBPACK_EXTERNAL_MODULE_react_useCallback__(event => {
|
|
@@ -37997,7 +38282,7 @@ function GalleryGrid({
|
|
|
37997
38282
|
for (let i = 1; i <= pageCount; i += 1) {
|
|
37998
38283
|
tiles.push(/*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryTile, {
|
|
37999
38284
|
key: i,
|
|
38000
|
-
imageSrc: loadedImages[i],
|
|
38285
|
+
imageSrc: highResImages[i] || loadedImages[i],
|
|
38001
38286
|
isFocused: i === focusedPage,
|
|
38002
38287
|
onClick: handleTileClick,
|
|
38003
38288
|
onFocus: handleTileFocus,
|