box-content-preview 3.52.0 → 3.53.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/dist/lib/index.js CHANGED
@@ -9340,7 +9340,7 @@ function util_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var
9340
9340
  const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
9341
9341
  const CLIENT_NAME_KEY = 'box_client_name';
9342
9342
  const CLIENT_VERSION_KEY = 'box_client_version';
9343
- const CLIENT_VERSION = "3.52.0"; // eslint-disable-line no-undef
9343
+ const CLIENT_VERSION = "3.53.0"; // eslint-disable-line no-undef
9344
9344
  const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
9345
9345
  const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
9346
9346
  const PROMISE_MAP = {};
@@ -11065,7 +11065,7 @@ class Browser {
11065
11065
  ;// ./src/lib/Logger.js
11066
11066
  /* eslint-disable no-undef */
11067
11067
  const Logger_CLIENT_NAME = "box-content-preview";
11068
- const Logger_CLIENT_VERSION = "3.52.0";
11068
+ const Logger_CLIENT_VERSION = "3.53.0";
11069
11069
  /* eslint-enable no-undef */
11070
11070
 
11071
11071
  class Logger {
@@ -30951,6 +30951,447 @@ class DocFindBar extends (events_default()) {
30951
30951
  }
30952
30952
  }
30953
30953
  /* harmony default export */ const doc_DocFindBar = (DocFindBar);
30954
+ ;// ./src/lib/Cache.js
30955
+
30956
+ class Cache {
30957
+ //--------------------------------------------------------------------------
30958
+ // Public
30959
+ //--------------------------------------------------------------------------
30960
+
30961
+ /**
30962
+ * [constructor]
30963
+ *
30964
+ * @return {Cache} Cache instance
30965
+ */
30966
+ constructor() {
30967
+ this.cache = {};
30968
+ }
30969
+
30970
+ /**
30971
+ * Caches a simple object in memory and in localStorage if specified.
30972
+ * Note that objects cached in localStorage will be stringified.
30973
+ *
30974
+ * @public
30975
+ * @param {string} key - The cache key
30976
+ * @param {*} value - The cache value
30977
+ * @param {boolean} useLocalStorage - Whether or not to use localStorage
30978
+ * @return {void}
30979
+ */
30980
+ set(key, value, useLocalStorage) {
30981
+ this.cache[key] = value;
30982
+ if (useLocalStorage && this.isLocalStorageAvailable()) {
30983
+ localStorage.setItem(this.generateKey(key), JSON.stringify(value));
30984
+ }
30985
+ }
30986
+
30987
+ /**
30988
+ * Deletes object from in-memory cache and localStorage.
30989
+ *
30990
+ * @public
30991
+ * @param {string} key - The cache key
30992
+ * @return {void}
30993
+ */
30994
+ unset(key) {
30995
+ if (this.isLocalStorageAvailable()) {
30996
+ localStorage.removeItem(this.generateKey(key));
30997
+ }
30998
+ delete this.cache[key];
30999
+ }
31000
+
31001
+ /**
31002
+ * Checks if cache has provided key.
31003
+ *
31004
+ * @public
31005
+ * @param {string} key - The cache key
31006
+ * @return {boolean} Whether the cache has key
31007
+ */
31008
+ has(key) {
31009
+ return this.inCache(key) || this.inLocalStorage(key);
31010
+ }
31011
+
31012
+ /**
31013
+ * Fetches a cached object from in-memory cache if available. Otherwise
31014
+ * tries to fetch from localStorage. If fetched from localStorage, object
31015
+ * will be a JSON parsed object.
31016
+ *
31017
+ * @public
31018
+ * @param {string} key - Key of cached object
31019
+ * @return {Object} Cached object
31020
+ */
31021
+ get(key) {
31022
+ if (this.inCache(key)) {
31023
+ return this.cache[key];
31024
+ }
31025
+
31026
+ // If localStorage is available, try to fetch from there and set it
31027
+ // in in-memory cache if found
31028
+ if (this.inLocalStorage(key)) {
31029
+ let value = localStorage.getItem(this.generateKey(key));
31030
+ if (value) {
31031
+ value = JSON.parse(value);
31032
+ this.cache[key] = value;
31033
+ return value;
31034
+ }
31035
+ }
31036
+ return undefined;
31037
+ }
31038
+
31039
+ //--------------------------------------------------------------------------
31040
+ // Private
31041
+ //--------------------------------------------------------------------------
31042
+
31043
+ /**
31044
+ * Checks if memory cache has provided key.
31045
+ *
31046
+ * @private
31047
+ * @param {string} key - The cache key
31048
+ * @return {boolean} Whether the cache has key
31049
+ */
31050
+ inCache(key) {
31051
+ return {}.hasOwnProperty.call(this.cache, key);
31052
+ }
31053
+
31054
+ /**
31055
+ * Checks if memory cache has provided key.
31056
+ *
31057
+ * @private
31058
+ * @param {string} key - The cache key
31059
+ * @return {boolean} Whether the cache has key
31060
+ */
31061
+ inLocalStorage(key) {
31062
+ if (!this.isLocalStorageAvailable()) {
31063
+ return false;
31064
+ }
31065
+ return !!localStorage.getItem(this.generateKey(key));
31066
+ }
31067
+
31068
+ /**
31069
+ * Checks whether localStorage is available.
31070
+ *
31071
+ * @NOTE(tjin): This check is cached to not have to write/read from disk
31072
+ * every time this check is needed, but this will not catch instances where
31073
+ * localStorage was available the first time this is called, but becomes
31074
+ * unavailable at a later time.
31075
+ *
31076
+ * @private
31077
+ * @return {boolean} Whether or not localStorage is available or not.
31078
+ */
31079
+ isLocalStorageAvailable() {
31080
+ if (this.available === undefined) {
31081
+ this.available = isLocalStorageAvailable();
31082
+ }
31083
+ return this.available;
31084
+ }
31085
+
31086
+ /**
31087
+ * Generates a key to use for localStorage from the provided key. This
31088
+ * should prevent name collisions.
31089
+ *
31090
+ * @private
31091
+ * @param {string} key - Generate key from this key
31092
+ * @return {string} Generated key for localStorage
31093
+ */
31094
+ generateKey(key) {
31095
+ return `bp-${key}`;
31096
+ }
31097
+ }
31098
+ /* harmony default export */ const lib_Cache = (Cache);
31099
+ ;// ./src/lib/BoundedCache.js
31100
+ function BoundedCache_defineProperty(e, r, t) { return (r = BoundedCache_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
31101
+ function BoundedCache_toPropertyKey(t) { var i = BoundedCache_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31102
+ function BoundedCache_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); }
31103
+
31104
+ class BoundedCache extends lib_Cache {
31105
+ /**
31106
+ * [constructor]
31107
+ *
31108
+ * @param {number} [maxEntries] - Override the maximum number of cache entries
31109
+ */
31110
+ constructor(maxEntries) {
31111
+ super();
31112
+ /** @property {Array} - Maintains the list of cache keys in order in which they were added to the cache */
31113
+ BoundedCache_defineProperty(this, "cacheQueue", void 0);
31114
+ /** @property {number} - The maximum number of entries in the cache */
31115
+ BoundedCache_defineProperty(this, "maxEntries", void 0);
31116
+ this.maxEntries = maxEntries || 500;
31117
+ this.cache = {};
31118
+ this.cacheQueue = [];
31119
+ }
31120
+
31121
+ /**
31122
+ * Destroys the bounded cache
31123
+ *
31124
+ * @return {void}
31125
+ */
31126
+ destroy() {
31127
+ this.cache = null;
31128
+ this.cacheQueue = null;
31129
+ }
31130
+
31131
+ /**
31132
+ * Caches a simple object in memory. If the number of cache entries
31133
+ * then exceeds the maxEntries value, then the earliest key in cacheQueue
31134
+ * will be removed from the cache.
31135
+ *
31136
+ * @param {string} key - The cache key
31137
+ * @param {*} value - The cache value
31138
+ * @return {void}
31139
+ */
31140
+ set(key, value) {
31141
+ // If this key is not already in the cache, then add it
31142
+ // to the cacheQueue. This avoids adding the same key to
31143
+ // the cacheQueue multiple times if the cache entry gets updated
31144
+ if (!this.inCache(key)) {
31145
+ this.cacheQueue.push(key);
31146
+ }
31147
+ super.set(key, value);
31148
+
31149
+ // If the cacheQueue exceeds the maxEntries then remove the first
31150
+ // key from the front of the cacheQueue and unset that entry
31151
+ // from the cache
31152
+ if (this.cacheQueue.length > this.maxEntries) {
31153
+ const deleteKey = this.cacheQueue.shift();
31154
+ this.unset(deleteKey);
31155
+ }
31156
+ }
31157
+ }
31158
+ /* harmony default export */ const lib_BoundedCache = (BoundedCache);
31159
+ ;// ./src/lib/Thumbnail.js
31160
+ function Thumbnail_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; }
31161
+ function Thumbnail_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? Thumbnail_ownKeys(Object(t), !0).forEach(function (r) { Thumbnail_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : Thumbnail_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
31162
+ function Thumbnail_defineProperty(e, r, t) { return (r = Thumbnail_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
31163
+ function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31164
+ 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); }
31165
+
31166
+
31167
+ const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
31168
+ const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
31169
+ const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
31170
+
31171
+ class Thumbnail {
31172
+ /**
31173
+ * [constructor]
31174
+ *
31175
+ * @param {PDFViewer} pdfViewer - the PDFJS viewer
31176
+ */
31177
+ constructor(pdfViewer, preloader) {
31178
+ /** @property {PDfViewer} - The PDFJS viewer instance */
31179
+ Thumbnail_defineProperty(this, "pdfViewer", void 0);
31180
+ /** @property {Object} - Cache for the thumbnail image elements */
31181
+ Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
31182
+ Thumbnail_defineProperty(this, "preloader", void 0);
31183
+ this.preloader = preloader;
31184
+ this.createImageEl = this.createImageEl.bind(this);
31185
+ this.createThumbnailImage = this.createThumbnailImage.bind(this);
31186
+ this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
31187
+ this.pdfViewer = pdfViewer;
31188
+ this.thumbnailImageCache = new lib_BoundedCache();
31189
+ }
31190
+
31191
+ /**
31192
+ * Destroys the thumbnails sidebar
31193
+ *
31194
+ * @return {void}
31195
+ */
31196
+ destroy() {
31197
+ if (this.thumbnailImageCache) {
31198
+ this.thumbnailImageCache.destroy();
31199
+ this.thumbnailImageCache = null;
31200
+ }
31201
+ this.pdfViewer = null;
31202
+ this.preloader = null;
31203
+ }
31204
+
31205
+ /**
31206
+ * Initializes the Thumbnails Sidebar
31207
+ *
31208
+ * @return {Promise}
31209
+ */
31210
+ init() {
31211
+ // Get the first page of the document, and use its dimensions
31212
+ // to set the thumbnails size of the thumbnails sidebar
31213
+
31214
+ if (this.preloader?.imageDimensions) {
31215
+ const {
31216
+ width,
31217
+ height
31218
+ } = this.preloader.imageDimensions;
31219
+ this.scale = THUMBNAIL_TOTAL_WIDTH / width;
31220
+ this.pageRatio = width / height;
31221
+ this.thumbnailHeight = Math.ceil(height * this.scale);
31222
+ return Promise.resolve(this.thumbnailHeight);
31223
+ }
31224
+ const pdfDocument = this.pdfViewer?.pdfDocument;
31225
+ if (!pdfDocument) {
31226
+ return Promise.resolve(null);
31227
+ }
31228
+ return pdfDocument.getPage(1).then(page => {
31229
+ const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
31230
+ const viewport = page.getViewport({
31231
+ scale: 1,
31232
+ rotation
31233
+ });
31234
+ if (!viewport) {
31235
+ return Promise.resolve(null);
31236
+ }
31237
+ const {
31238
+ width,
31239
+ height
31240
+ } = viewport;
31241
+
31242
+ // If the dimensions of the page are invalid then don't proceed further
31243
+ if (!(isFinite_default()(width) && width > 0 && isFinite_default()(height) && height > 0)) {
31244
+ // eslint-disable-next-line
31245
+ console.error('Page dimensions invalid when initializing the thumbnails sidebar');
31246
+ return Promise.resolve(null);
31247
+ }
31248
+
31249
+ // Amount to scale down from full-size to thumbnail size
31250
+ this.scale = THUMBNAIL_TOTAL_WIDTH / width;
31251
+ // Width : Height ratio of the page
31252
+ this.pageRatio = width / height;
31253
+ const scaledViewport = page.getViewport({
31254
+ scale: this.scale,
31255
+ rotation
31256
+ });
31257
+ this.thumbnailHeight = Math.ceil(scaledViewport.height);
31258
+ return Promise.resolve(this.thumbnailHeight);
31259
+ });
31260
+ }
31261
+
31262
+ /**
31263
+ * Creates the image element
31264
+ * @param {string} dataUrl - The image data URL for the thumbnail
31265
+ * @return {HTMLElement} - The image element
31266
+ */
31267
+ createImageEl(dataUrl, thumbOptions) {
31268
+ const imageEl = thumbOptions && thumbOptions.createImgTag ? document.createElement('img') : document.createElement('div');
31269
+ if (thumbOptions && thumbOptions.createImgTag) {
31270
+ imageEl.src = `${dataUrl}`;
31271
+ return imageEl;
31272
+ }
31273
+ imageEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE);
31274
+ imageEl.style.backgroundImage = `url('${dataUrl}')`;
31275
+
31276
+ // Add the height and width to the image to be the same as the thumbnail
31277
+ // so that the css `background-image` rules will work
31278
+ imageEl.style.width = `${THUMBNAIL_TOTAL_WIDTH}px`;
31279
+ imageEl.style.height = `${this.thumbnailHeight}px`;
31280
+ return imageEl;
31281
+ }
31282
+
31283
+ /**
31284
+ * Make a thumbnail image element
31285
+ *
31286
+ * @param {number} itemIndex - the item index for the overall list (0 indexed)
31287
+ * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
31288
+ */
31289
+ createThumbnailImage(itemIndex, thumbOptions) {
31290
+ const cacheEntry = this.getImageFromCache(itemIndex);
31291
+ // If this thumbnail has already been cached, use it
31292
+ if (cacheEntry && cacheEntry.image) {
31293
+ return Promise.resolve(cacheEntry.image);
31294
+ }
31295
+
31296
+ // If this thumbnail has already been requested, resolve with null
31297
+ if (cacheEntry && cacheEntry.inProgress) {
31298
+ return Promise.resolve(null);
31299
+ }
31300
+
31301
+ // Update the cache entry to be in progress
31302
+ this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
31303
+ inProgress: true
31304
+ }));
31305
+ return this.getThumbnailDataURL(itemIndex + 1, thumbOptions).then(dataUrl => {
31306
+ return this.createImageEl(dataUrl, thumbOptions);
31307
+ }).then(imageEl => {
31308
+ // Cache this image element for future use
31309
+ this.thumbnailImageCache.set(itemIndex, {
31310
+ inProgress: false,
31311
+ image: imageEl
31312
+ });
31313
+ return imageEl;
31314
+ }).catch(() => {
31315
+ this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, this.getImageFromCache(itemIndex)), {}, {
31316
+ inProgress: false
31317
+ }));
31318
+ throw new Error('Thumbnail generation failed');
31319
+ });
31320
+ }
31321
+
31322
+ /**
31323
+ * Make a thumbnail image element
31324
+ *
31325
+ * @param {number} itemIndex - the item index for the overall list (0 indexed)
31326
+ * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
31327
+ */
31328
+ getImageFromCache(itemIndex) {
31329
+ return this.thumbnailImageCache.get(itemIndex);
31330
+ }
31331
+
31332
+ /**
31333
+ * Given a page number, generates the image data URL for the image of the page
31334
+ * @param {number} pageNum - The page number of the document
31335
+ * @return {string} The data URL of the page image
31336
+ */
31337
+ getThumbnailDataURL(pageNum, thumbOptions) {
31338
+ if (this.preloader?.preloadedImages?.[pageNum]) {
31339
+ return Promise.resolve(this.preloader.preloadedImages[pageNum]);
31340
+ }
31341
+ const pdfDocument = this.pdfViewer?.pdfDocument;
31342
+ if (!pdfDocument) {
31343
+ return Promise.reject(new Error('PDF document not ready'));
31344
+ }
31345
+ const canvas = document.createElement('canvas');
31346
+ const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
31347
+ return pdfDocument.getPage(pageNum).then(page => {
31348
+ const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
31349
+ const viewport = page.getViewport({
31350
+ scale: 1,
31351
+ rotation
31352
+ });
31353
+ if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
31354
+ return Promise.reject(new Error('Invalid page viewport'));
31355
+ }
31356
+ const {
31357
+ width,
31358
+ height
31359
+ } = viewport;
31360
+ // Get the current page w:h ratio in case it differs from the first page
31361
+ const curPageRatio = width / height;
31362
+
31363
+ // Handle the case where the current page's w:h ratio is less than the
31364
+ // `pageRatio` which means that this page is probably more portrait than
31365
+ // landscape
31366
+ if (curPageRatio < this.pageRatio) {
31367
+ // Set the canvas height to that of the thumbnail max height
31368
+ canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
31369
+ // Find the canvas width based on the current page ratio
31370
+ canvas.width = canvas.height * curPageRatio;
31371
+ } else {
31372
+ // In case the current page ratio is same as the first page
31373
+ // or in case it's larger (which means that it's wider), keep
31374
+ // the width at the max thumbnail width
31375
+ canvas.width = thumbnailImageWidth;
31376
+ // Find the height based on the current page ratio
31377
+ canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
31378
+ }
31379
+ // The amount for which to scale down the current page
31380
+ const {
31381
+ width: canvasWidth
31382
+ } = canvas;
31383
+ const scale = canvasWidth / width;
31384
+ return page.render({
31385
+ canvasContext: canvas.getContext('2d'),
31386
+ viewport: page.getViewport({
31387
+ scale,
31388
+ rotation
31389
+ })
31390
+ }).promise;
31391
+ }).then(() => canvas.toDataURL());
31392
+ }
31393
+ }
31394
+ /* harmony default export */ const lib_Thumbnail = (Thumbnail);
30954
31395
  ;// ./src/lib/viewers/gallery/GalleryGrid.scss
30955
31396
  // extracted by mini-css-extract-plugin
30956
31397
 
@@ -31132,51 +31573,229 @@ function GalleryGrid(_ref) {
31132
31573
  onClose();
31133
31574
  return;
31134
31575
  }
31135
- if (event.key === 'Tab' && gridRef.current) {
31136
- const buttons = gridRef.current.querySelectorAll('button');
31137
- const first = buttons[0];
31138
- const last = buttons[buttons.length - 1];
31139
- if (event.shiftKey && document.activeElement === first) {
31140
- event.preventDefault();
31141
- last.focus();
31142
- } else if (!event.shiftKey && document.activeElement === last) {
31143
- event.preventDefault();
31144
- first.focus();
31145
- }
31576
+ if (event.key === 'Tab' && gridRef.current) {
31577
+ const buttons = gridRef.current.querySelectorAll('button');
31578
+ const first = buttons[0];
31579
+ const last = buttons[buttons.length - 1];
31580
+ if (event.shiftKey && document.activeElement === first) {
31581
+ event.preventDefault();
31582
+ last.focus();
31583
+ } else if (!event.shiftKey && document.activeElement === last) {
31584
+ event.preventDefault();
31585
+ first.focus();
31586
+ }
31587
+ }
31588
+ }, [onClose]);
31589
+ const tiles = [];
31590
+ for (let i = 1; i <= pageCount; i += 1) {
31591
+ const isFocused = i === focusedPage;
31592
+ tiles.push( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
31593
+ key: i,
31594
+ "aria-label": `Page ${i}${isFocused ? ', current page' : ''}`,
31595
+ className: `bp-gallery-tile${isFocused ? ' bp-gallery-tile--selected' : ''}`,
31596
+ "data-page": i,
31597
+ onClick: () => onPageNavigate(i),
31598
+ onFocus: () => handleTileFocus(i),
31599
+ type: "button"
31600
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31601
+ className: "bp-gallery-tile-badge"
31602
+ }, i), loadedImages[i] ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("img", {
31603
+ alt: `Page ${i}`,
31604
+ src: loadedImages[i]
31605
+ }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31606
+ className: "bp-gallery-tile-placeholder"
31607
+ })));
31608
+ }
31609
+ return (
31610
+ /*#__PURE__*/
31611
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
31612
+ __WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
31613
+ ref: gridRef,
31614
+ className: "bp-gallery-grid",
31615
+ onFocus: handleGridFocus,
31616
+ onKeyDown: handleGridKeyDown,
31617
+ onScroll: handleScrollRef.current,
31618
+ tabIndex: -1
31619
+ }, tiles)
31620
+ );
31621
+ }
31622
+ ;// ./src/lib/viewers/gallery/GalleryController.tsx
31623
+ function GalleryController_defineProperty(e, r, t) { return (r = GalleryController_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
31624
+ function GalleryController_toPropertyKey(t) { var i = GalleryController_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31625
+ function GalleryController_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); }
31626
+ // Doc-viewer-bound: this controller talks to PDF.js (pdfViewer, Thumbnail) and
31627
+ // the doc-specific ThumbnailsSidebar. If a non-doc viewer ever needs gallery,
31628
+ // the dependencies below must be abstracted first.
31629
+
31630
+
31631
+
31632
+
31633
+
31634
+
31635
+
31636
+ // Controller-owned shape: GalleryGrid only sees the read surface (GalleryThumbnail),
31637
+ // but the controller also needs destroy() to invalidate the cache on rotate/teardown.
31638
+
31639
+ const GALLERY_MAX_PAGES = 200; // Hide gallery toggle for files above this page count, will increase in V2
31640
+ const THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // ms
31641
+
31642
+ // Minimal local shapes for untyped peer modules (pdfjs is JS-only, sidebar is JS-only).
31643
+ // Only the members the controller actually uses are declared — extend as needed.
31644
+
31645
+ // The preloader is opaque to the controller; we only forward it into Thumbnail's constructor.
31646
+ // Type-alias what the Thumbnail constructor expects so the two sides stay in sync.
31647
+
31648
+ class GalleryController {
31649
+ constructor(opts) {
31650
+ GalleryController_defineProperty(this, "containerEl", void 0);
31651
+ GalleryController_defineProperty(this, "features", void 0);
31652
+ GalleryController_defineProperty(this, "getPdfViewer", void 0);
31653
+ GalleryController_defineProperty(this, "getPreloader", void 0);
31654
+ GalleryController_defineProperty(this, "getThumbnailsSidebar", void 0);
31655
+ GalleryController_defineProperty(this, "setPage", void 0);
31656
+ GalleryController_defineProperty(this, "toggleThumbnails", void 0);
31657
+ GalleryController_defineProperty(this, "requestUiUpdate", void 0);
31658
+ GalleryController_defineProperty(this, "galleryRoot", null);
31659
+ GalleryController_defineProperty(this, "galleryEl", null);
31660
+ GalleryController_defineProperty(this, "galleryThumbnail", null);
31661
+ GalleryController_defineProperty(this, "galleryFocusedPage", null);
31662
+ GalleryController_defineProperty(this, "galleryMountTimeoutId", null);
31663
+ GalleryController_defineProperty(this, "gallerySidebarTimeoutId", null);
31664
+ GalleryController_defineProperty(this, "sidebarWasOpen", false);
31665
+ GalleryController_defineProperty(this, "isGalleryOpen", false);
31666
+ GalleryController_defineProperty(this, "toggle", () => {
31667
+ this.isGalleryOpen = !this.isGalleryOpen;
31668
+ if (this.isGalleryOpen) {
31669
+ if (this.gallerySidebarTimeoutId !== null) {
31670
+ clearTimeout(this.gallerySidebarTimeoutId);
31671
+ this.gallerySidebarTimeoutId = null;
31672
+ }
31673
+ const sidebar = this.getThumbnailsSidebar();
31674
+ this.sidebarWasOpen = !!(sidebar && sidebar.isOpen);
31675
+ if (this.sidebarWasOpen) {
31676
+ this.toggleThumbnails();
31677
+ this.galleryMountTimeoutId = setTimeout(() => {
31678
+ this.galleryMountTimeoutId = null;
31679
+ this.mountGrid();
31680
+ }, THUMBNAILS_SIDEBAR_TRANSITION_TIME / 2);
31681
+ } else {
31682
+ this.mountGrid();
31683
+ }
31684
+ } else {
31685
+ if (this.galleryMountTimeoutId !== null) {
31686
+ clearTimeout(this.galleryMountTimeoutId);
31687
+ this.galleryMountTimeoutId = null;
31688
+ }
31689
+ const pdfViewer = this.getPdfViewer();
31690
+ const navigateToPage = this.galleryFocusedPage && this.galleryFocusedPage !== pdfViewer.currentPageNumber ? this.galleryFocusedPage : null;
31691
+ if (this.galleryRoot) {
31692
+ this.galleryRoot.unmount();
31693
+ this.galleryRoot = null;
31694
+ }
31695
+ if (this.galleryEl) {
31696
+ this.galleryEl.remove();
31697
+ this.galleryEl = null;
31698
+ }
31699
+ this.galleryFocusedPage = null;
31700
+ const sidebar = this.getThumbnailsSidebar();
31701
+ if (this.sidebarWasOpen && sidebar && !sidebar.isOpen) {
31702
+ this.toggleThumbnails();
31703
+ }
31704
+ if (navigateToPage) {
31705
+ this.setPage(navigateToPage);
31706
+ if (this.sidebarWasOpen && sidebar) {
31707
+ this.gallerySidebarTimeoutId = setTimeout(() => {
31708
+ this.gallerySidebarTimeoutId = null;
31709
+ sidebar.setCurrentPage(navigateToPage);
31710
+ }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
31711
+ }
31712
+ }
31713
+ }
31714
+ this.requestUiUpdate();
31715
+ });
31716
+ GalleryController_defineProperty(this, "handleGalleryNavigate", pageNum => {
31717
+ this.galleryFocusedPage = pageNum;
31718
+ this.toggle();
31719
+ });
31720
+ GalleryController_defineProperty(this, "handleFocusChange", pageNum => {
31721
+ this.galleryFocusedPage = pageNum;
31722
+ });
31723
+ this.containerEl = opts.containerEl;
31724
+ this.features = opts.features;
31725
+ this.getPdfViewer = opts.getPdfViewer;
31726
+ this.getPreloader = opts.getPreloader;
31727
+ this.getThumbnailsSidebar = opts.getThumbnailsSidebar;
31728
+ this.setPage = opts.setPage;
31729
+ this.toggleThumbnails = opts.toggleThumbnails;
31730
+ this.requestUiUpdate = opts.requestUiUpdate;
31731
+ }
31732
+ get isOpen() {
31733
+ return this.isGalleryOpen;
31734
+ }
31735
+ canRender(pageCount) {
31736
+ return isFeatureEnabled(this.features, 'galleryView.enabled') && pageCount > 1 && pageCount <= GALLERY_MAX_PAGES;
31737
+ }
31738
+ handleEscape() {
31739
+ if (!this.isGalleryOpen) return false;
31740
+ this.toggle();
31741
+ return true;
31742
+ }
31743
+ handleRotate() {
31744
+ if (this.galleryThumbnail) {
31745
+ this.galleryThumbnail.destroy();
31746
+ this.galleryThumbnail = null;
31747
+ }
31748
+ }
31749
+ destroy() {
31750
+ if (this.galleryMountTimeoutId !== null) {
31751
+ clearTimeout(this.galleryMountTimeoutId);
31752
+ this.galleryMountTimeoutId = null;
31753
+ }
31754
+ if (this.gallerySidebarTimeoutId !== null) {
31755
+ clearTimeout(this.gallerySidebarTimeoutId);
31756
+ this.gallerySidebarTimeoutId = null;
31757
+ }
31758
+ if (this.galleryRoot) {
31759
+ this.galleryRoot.unmount();
31760
+ this.galleryRoot = null;
31761
+ }
31762
+ if (this.galleryEl) {
31763
+ this.galleryEl.remove();
31764
+ this.galleryEl = null;
31765
+ }
31766
+ if (this.galleryThumbnail) {
31767
+ this.galleryThumbnail.destroy();
31768
+ this.galleryThumbnail = null;
31769
+ }
31770
+
31771
+ // Reset state so isOpen is honest even after teardown.
31772
+ this.isGalleryOpen = false;
31773
+ this.sidebarWasOpen = false;
31774
+ this.galleryFocusedPage = null;
31775
+ }
31776
+ mountGrid() {
31777
+ if (this.galleryRoot) {
31778
+ return;
31779
+ }
31780
+ const pdfViewer = this.getPdfViewer();
31781
+ if (!this.galleryThumbnail) {
31782
+ // Thumbnail is a JS class; cast to the typed interface used by the controller + grid.
31783
+ this.galleryThumbnail = new lib_Thumbnail(pdfViewer, this.getPreloader());
31146
31784
  }
31147
- }, [onClose]);
31148
- const tiles = [];
31149
- for (let i = 1; i <= pageCount; i += 1) {
31150
- const isFocused = i === focusedPage;
31151
- tiles.push( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
31152
- key: i,
31153
- "aria-label": `Page ${i}${isFocused ? ', current page' : ''}`,
31154
- className: `bp-gallery-tile${isFocused ? ' bp-gallery-tile--selected' : ''}`,
31155
- "data-page": i,
31156
- onClick: () => onPageNavigate(i),
31157
- onFocus: () => handleTileFocus(i),
31158
- type: "button"
31159
- }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31160
- className: "bp-gallery-tile-badge"
31161
- }, i), loadedImages[i] ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("img", {
31162
- alt: `Page ${i}`,
31163
- src: loadedImages[i]
31164
- }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31165
- className: "bp-gallery-tile-placeholder"
31166
- })));
31785
+ const thumbnail = this.galleryThumbnail;
31786
+ this.galleryEl = document.createElement('div');
31787
+ this.containerEl.appendChild(this.galleryEl);
31788
+ this.galleryRoot = __WEBPACK_EXTERNAL_MODULE_react_dom_client_4cb20cd7_createRoot__(this.galleryEl);
31789
+ this.galleryFocusedPage = pdfViewer.currentPageNumber;
31790
+ this.galleryRoot.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryGrid, {
31791
+ currentPage: pdfViewer.currentPageNumber,
31792
+ onClose: this.toggle,
31793
+ onFocusChange: this.handleFocusChange,
31794
+ onPageNavigate: this.handleGalleryNavigate,
31795
+ pageCount: pdfViewer.pagesCount,
31796
+ thumbnail: thumbnail
31797
+ }));
31167
31798
  }
31168
- return (
31169
- /*#__PURE__*/
31170
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
31171
- __WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
31172
- ref: gridRef,
31173
- className: "bp-gallery-grid",
31174
- onFocus: handleGridFocus,
31175
- onKeyDown: handleGridKeyDown,
31176
- onScroll: handleScrollRef.current,
31177
- tabIndex: -1
31178
- }, tiles)
31179
- );
31180
31799
  }
31181
31800
  ;// ./src/lib/logUtils.js
31182
31801
 
@@ -31603,232 +32222,27 @@ class PageTracker extends (events_default()) {
31603
32222
  /**
31604
32223
  * Update content insights options
31605
32224
  *
31606
- * @private
31607
- * @param {Object} options - Content Insights options
31608
- * @return {void}
31609
- */
31610
- updateOptions() {
31611
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
31612
- // Set User and file information
31613
- const prevActiveState = this.isAdvancedInsightsActive;
31614
- this.setOptions(options);
31615
- if (prevActiveState !== this.isAdvancedInsightsActive) {
31616
- // If ACI was deactivated, stop tracking user events
31617
- if (!this.isAdvancedInsightsActive) {
31618
- this.stopTracking();
31619
- this.unbindIdleUserEvents();
31620
- } else {
31621
- this.init();
31622
- }
31623
- }
31624
- }
31625
- }
31626
- /* harmony default export */ const lib_PageTracker = (PageTracker);
31627
- ;// ./src/lib/Cache.js
31628
-
31629
- class Cache {
31630
- //--------------------------------------------------------------------------
31631
- // Public
31632
- //--------------------------------------------------------------------------
31633
-
31634
- /**
31635
- * [constructor]
31636
- *
31637
- * @return {Cache} Cache instance
31638
- */
31639
- constructor() {
31640
- this.cache = {};
31641
- }
31642
-
31643
- /**
31644
- * Caches a simple object in memory and in localStorage if specified.
31645
- * Note that objects cached in localStorage will be stringified.
31646
- *
31647
- * @public
31648
- * @param {string} key - The cache key
31649
- * @param {*} value - The cache value
31650
- * @param {boolean} useLocalStorage - Whether or not to use localStorage
31651
- * @return {void}
31652
- */
31653
- set(key, value, useLocalStorage) {
31654
- this.cache[key] = value;
31655
- if (useLocalStorage && this.isLocalStorageAvailable()) {
31656
- localStorage.setItem(this.generateKey(key), JSON.stringify(value));
31657
- }
31658
- }
31659
-
31660
- /**
31661
- * Deletes object from in-memory cache and localStorage.
31662
- *
31663
- * @public
31664
- * @param {string} key - The cache key
31665
- * @return {void}
31666
- */
31667
- unset(key) {
31668
- if (this.isLocalStorageAvailable()) {
31669
- localStorage.removeItem(this.generateKey(key));
31670
- }
31671
- delete this.cache[key];
31672
- }
31673
-
31674
- /**
31675
- * Checks if cache has provided key.
31676
- *
31677
- * @public
31678
- * @param {string} key - The cache key
31679
- * @return {boolean} Whether the cache has key
31680
- */
31681
- has(key) {
31682
- return this.inCache(key) || this.inLocalStorage(key);
31683
- }
31684
-
31685
- /**
31686
- * Fetches a cached object from in-memory cache if available. Otherwise
31687
- * tries to fetch from localStorage. If fetched from localStorage, object
31688
- * will be a JSON parsed object.
31689
- *
31690
- * @public
31691
- * @param {string} key - Key of cached object
31692
- * @return {Object} Cached object
31693
- */
31694
- get(key) {
31695
- if (this.inCache(key)) {
31696
- return this.cache[key];
31697
- }
31698
-
31699
- // If localStorage is available, try to fetch from there and set it
31700
- // in in-memory cache if found
31701
- if (this.inLocalStorage(key)) {
31702
- let value = localStorage.getItem(this.generateKey(key));
31703
- if (value) {
31704
- value = JSON.parse(value);
31705
- this.cache[key] = value;
31706
- return value;
31707
- }
31708
- }
31709
- return undefined;
31710
- }
31711
-
31712
- //--------------------------------------------------------------------------
31713
- // Private
31714
- //--------------------------------------------------------------------------
31715
-
31716
- /**
31717
- * Checks if memory cache has provided key.
31718
- *
31719
- * @private
31720
- * @param {string} key - The cache key
31721
- * @return {boolean} Whether the cache has key
31722
- */
31723
- inCache(key) {
31724
- return {}.hasOwnProperty.call(this.cache, key);
31725
- }
31726
-
31727
- /**
31728
- * Checks if memory cache has provided key.
31729
- *
31730
- * @private
31731
- * @param {string} key - The cache key
31732
- * @return {boolean} Whether the cache has key
31733
- */
31734
- inLocalStorage(key) {
31735
- if (!this.isLocalStorageAvailable()) {
31736
- return false;
31737
- }
31738
- return !!localStorage.getItem(this.generateKey(key));
31739
- }
31740
-
31741
- /**
31742
- * Checks whether localStorage is available.
31743
- *
31744
- * @NOTE(tjin): This check is cached to not have to write/read from disk
31745
- * every time this check is needed, but this will not catch instances where
31746
- * localStorage was available the first time this is called, but becomes
31747
- * unavailable at a later time.
31748
- *
31749
- * @private
31750
- * @return {boolean} Whether or not localStorage is available or not.
31751
- */
31752
- isLocalStorageAvailable() {
31753
- if (this.available === undefined) {
31754
- this.available = isLocalStorageAvailable();
31755
- }
31756
- return this.available;
31757
- }
31758
-
31759
- /**
31760
- * Generates a key to use for localStorage from the provided key. This
31761
- * should prevent name collisions.
31762
- *
31763
- * @private
31764
- * @param {string} key - Generate key from this key
31765
- * @return {string} Generated key for localStorage
31766
- */
31767
- generateKey(key) {
31768
- return `bp-${key}`;
31769
- }
31770
- }
31771
- /* harmony default export */ const lib_Cache = (Cache);
31772
- ;// ./src/lib/BoundedCache.js
31773
- function BoundedCache_defineProperty(e, r, t) { return (r = BoundedCache_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
31774
- function BoundedCache_toPropertyKey(t) { var i = BoundedCache_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31775
- function BoundedCache_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); }
31776
-
31777
- class BoundedCache extends lib_Cache {
31778
- /**
31779
- * [constructor]
31780
- *
31781
- * @param {number} [maxEntries] - Override the maximum number of cache entries
31782
- */
31783
- constructor(maxEntries) {
31784
- super();
31785
- /** @property {Array} - Maintains the list of cache keys in order in which they were added to the cache */
31786
- BoundedCache_defineProperty(this, "cacheQueue", void 0);
31787
- /** @property {number} - The maximum number of entries in the cache */
31788
- BoundedCache_defineProperty(this, "maxEntries", void 0);
31789
- this.maxEntries = maxEntries || 500;
31790
- this.cache = {};
31791
- this.cacheQueue = [];
31792
- }
31793
-
31794
- /**
31795
- * Destroys the bounded cache
31796
- *
31797
- * @return {void}
31798
- */
31799
- destroy() {
31800
- this.cache = null;
31801
- this.cacheQueue = null;
31802
- }
31803
-
31804
- /**
31805
- * Caches a simple object in memory. If the number of cache entries
31806
- * then exceeds the maxEntries value, then the earliest key in cacheQueue
31807
- * will be removed from the cache.
31808
- *
31809
- * @param {string} key - The cache key
31810
- * @param {*} value - The cache value
32225
+ * @private
32226
+ * @param {Object} options - Content Insights options
31811
32227
  * @return {void}
31812
32228
  */
31813
- set(key, value) {
31814
- // If this key is not already in the cache, then add it
31815
- // to the cacheQueue. This avoids adding the same key to
31816
- // the cacheQueue multiple times if the cache entry gets updated
31817
- if (!this.inCache(key)) {
31818
- this.cacheQueue.push(key);
31819
- }
31820
- super.set(key, value);
31821
-
31822
- // If the cacheQueue exceeds the maxEntries then remove the first
31823
- // key from the front of the cacheQueue and unset that entry
31824
- // from the cache
31825
- if (this.cacheQueue.length > this.maxEntries) {
31826
- const deleteKey = this.cacheQueue.shift();
31827
- this.unset(deleteKey);
32229
+ updateOptions() {
32230
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
32231
+ // Set User and file information
32232
+ const prevActiveState = this.isAdvancedInsightsActive;
32233
+ this.setOptions(options);
32234
+ if (prevActiveState !== this.isAdvancedInsightsActive) {
32235
+ // If ACI was deactivated, stop tracking user events
32236
+ if (!this.isAdvancedInsightsActive) {
32237
+ this.stopTracking();
32238
+ this.unbindIdleUserEvents();
32239
+ } else {
32240
+ this.init();
32241
+ }
31828
32242
  }
31829
32243
  }
31830
32244
  }
31831
- /* harmony default export */ const lib_BoundedCache = (BoundedCache);
32245
+ /* harmony default export */ const lib_PageTracker = (PageTracker);
31832
32246
  // EXTERNAL MODULE: ./node_modules/lodash/isFunction.js
31833
32247
  var isFunction = __webpack_require__(1882);
31834
32248
  var isFunction_default = /*#__PURE__*/__webpack_require__.n(isFunction);
@@ -32164,365 +32578,129 @@ class VirtualScroller {
32164
32578
  if (!listEl || start < 0 || end < 0) {
32165
32579
  return;
32166
32580
  }
32167
- const listItems = Array.prototype.slice.call(listEl.children, start, end);
32168
- listItems.forEach(listItem => listEl.removeChild(listItem));
32169
- }
32170
-
32171
- /**
32172
- * Render a single item
32173
- *
32174
- * @param {number} rowIndex - The index of the item to be rendered
32175
- * @return {HTMLElement} The newly created row item
32176
- */
32177
- renderItem(rowIndex) {
32178
- const rowEl = document.createElement('li');
32179
- const topPosition = (this.itemHeight + this.margin) * rowIndex + this.margin;
32180
- let renderedThumbnail;
32181
- try {
32182
- renderedThumbnail = this.renderItemFn.call(this, rowIndex);
32183
- } catch (err) {
32184
- // eslint-disable-next-line
32185
- console.error(`Error rendering thumbnail - ${err}`);
32186
- }
32187
- rowEl.style.top = `${topPosition}px`;
32188
- rowEl.style.height = `${this.itemHeight}px`;
32189
- rowEl.classList.add('bp-vs-list-item');
32190
- rowEl.dataset.bpVsRowIndex = rowIndex;
32191
- if (renderedThumbnail) {
32192
- rowEl.appendChild(renderedThumbnail);
32193
- }
32194
- return rowEl;
32195
- }
32196
-
32197
- /**
32198
- * Utility to create the list element
32199
- *
32200
- * @return {HTMLElement} The list element
32201
- */
32202
- createListElement() {
32203
- const newListEl = document.createElement('ol');
32204
- newListEl.className = 'bp-vs-list';
32205
- newListEl.style.height = `${this.totalItems * (this.itemHeight + this.margin) + this.margin}px`;
32206
- return newListEl;
32207
- }
32208
-
32209
- /**
32210
- * Scrolls the provided row index into view.
32211
- * @param {number} rowIndex - the index of the row in the overall list
32212
- * @return {void}
32213
- */
32214
- scrollIntoView(rowIndex) {
32215
- if (!this.scrollingEl || rowIndex < 0 || rowIndex >= this.totalItems) {
32216
- return;
32217
- }
32218
-
32219
- // See if the list item indexed by `rowIndex` is already present
32220
- const foundItem = this.getListItems().find(listItem => {
32221
- const {
32222
- bpVsRowIndex
32223
- } = listItem.dataset;
32224
- const parsedRowIndex = parseInt(bpVsRowIndex, 10);
32225
- return parsedRowIndex === rowIndex;
32226
- });
32227
- if (foundItem) {
32228
- // If it is already present and visible, do nothing, but if not visible
32229
- // then scroll it into view
32230
- if (!this.isVisible(foundItem)) {
32231
- foundItem.scrollIntoView({
32232
- block: 'nearest'
32233
- });
32234
- }
32235
- } else {
32236
- // If it is not present, then adjust the scrollTop so that the list item
32237
- // will get rendered.
32238
- const topPosition = (this.itemHeight + this.margin) * rowIndex;
32239
- this.scrollingEl.scrollTop = topPosition;
32240
- // Some browsers don't fire the scroll event when setting scrollTop
32241
- // (IE11 & Firefox) so we need to manually dispatch the event
32242
- // in order to trigger `onScrollHandler` to render the items
32243
- this.scrollingEl.dispatchEvent(new Event('scroll'));
32244
- }
32245
- }
32246
-
32247
- /**
32248
- * Checks to see whether the provided list item element is currently visible
32249
- * @param {HTMLElement} listItemEl - the list item elment
32250
- * @return {boolean} Returns true if the list item is visible, false otherwise
32251
- */
32252
- isVisible(listItemEl) {
32253
- if (!this.scrollingEl || !listItemEl) {
32254
- return false;
32255
- }
32256
- const {
32257
- scrollTop
32258
- } = this.scrollingEl;
32259
- const {
32260
- offsetTop
32261
- } = listItemEl;
32262
-
32263
- // Ensure that the offsetTop and entire height of the listItemEl are inside the visible window
32264
- return scrollTop <= offsetTop && offsetTop + this.itemHeight <= scrollTop + this.containerHeight;
32265
- }
32266
-
32267
- /**
32268
- * Gets the currently visible list items
32269
- * @return {Array<HTMLElement>} - the list of current visible list items
32270
- */
32271
- getVisibleItems() {
32272
- if (!this.listEl) {
32273
- return [];
32274
- }
32275
- return this.getListItems().filter(itemEl => this.isVisible(itemEl)).map(itemEl => itemEl && itemEl.children && itemEl.children[0]);
32276
- }
32277
-
32278
- /**
32279
- * Gets the list items of this.listEl as an array
32280
- * @return {Array<HTMLElement>} - the list items
32281
- */
32282
- getListItems() {
32283
- if (!this.listEl) {
32284
- return [];
32285
- }
32286
- return Array.prototype.slice.call(this.listEl.children);
32287
- }
32288
- }
32289
- /* harmony default export */ const lib_VirtualScroller = (VirtualScroller);
32290
- ;// ./src/lib/Thumbnail.js
32291
- function Thumbnail_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; }
32292
- function Thumbnail_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? Thumbnail_ownKeys(Object(t), !0).forEach(function (r) { Thumbnail_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : Thumbnail_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
32293
- function Thumbnail_defineProperty(e, r, t) { return (r = Thumbnail_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
32294
- function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
32295
- 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); }
32296
-
32297
-
32298
- const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
32299
- const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
32300
- const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
32301
-
32302
- class Thumbnail {
32303
- /**
32304
- * [constructor]
32305
- *
32306
- * @param {PDFViewer} pdfViewer - the PDFJS viewer
32307
- */
32308
- constructor(pdfViewer, preloader) {
32309
- /** @property {PDfViewer} - The PDFJS viewer instance */
32310
- Thumbnail_defineProperty(this, "pdfViewer", void 0);
32311
- /** @property {Object} - Cache for the thumbnail image elements */
32312
- Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
32313
- Thumbnail_defineProperty(this, "preloader", void 0);
32314
- this.preloader = preloader;
32315
- this.createImageEl = this.createImageEl.bind(this);
32316
- this.createThumbnailImage = this.createThumbnailImage.bind(this);
32317
- this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
32318
- this.pdfViewer = pdfViewer;
32319
- this.thumbnailImageCache = new lib_BoundedCache();
32320
- }
32321
-
32322
- /**
32323
- * Destroys the thumbnails sidebar
32324
- *
32325
- * @return {void}
32326
- */
32327
- destroy() {
32328
- if (this.thumbnailImageCache) {
32329
- this.thumbnailImageCache.destroy();
32330
- this.thumbnailImageCache = null;
32331
- }
32332
- this.pdfViewer = null;
32333
- this.preloader = null;
32334
- }
32335
-
32336
- /**
32337
- * Initializes the Thumbnails Sidebar
32338
- *
32339
- * @return {Promise}
32340
- */
32341
- init() {
32342
- // Get the first page of the document, and use its dimensions
32343
- // to set the thumbnails size of the thumbnails sidebar
32344
-
32345
- if (this.preloader?.imageDimensions) {
32346
- const {
32347
- width,
32348
- height
32349
- } = this.preloader.imageDimensions;
32350
- this.scale = THUMBNAIL_TOTAL_WIDTH / width;
32351
- this.pageRatio = width / height;
32352
- this.thumbnailHeight = Math.ceil(height * this.scale);
32353
- return Promise.resolve(this.thumbnailHeight);
32354
- }
32355
- const pdfDocument = this.pdfViewer?.pdfDocument;
32356
- if (!pdfDocument) {
32357
- return Promise.resolve(null);
32358
- }
32359
- return pdfDocument.getPage(1).then(page => {
32360
- const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
32361
- const viewport = page.getViewport({
32362
- scale: 1,
32363
- rotation
32364
- });
32365
- if (!viewport) {
32366
- return Promise.resolve(null);
32367
- }
32368
- const {
32369
- width,
32370
- height
32371
- } = viewport;
32372
-
32373
- // If the dimensions of the page are invalid then don't proceed further
32374
- if (!(isFinite_default()(width) && width > 0 && isFinite_default()(height) && height > 0)) {
32375
- // eslint-disable-next-line
32376
- console.error('Page dimensions invalid when initializing the thumbnails sidebar');
32377
- return Promise.resolve(null);
32378
- }
32379
-
32380
- // Amount to scale down from full-size to thumbnail size
32381
- this.scale = THUMBNAIL_TOTAL_WIDTH / width;
32382
- // Width : Height ratio of the page
32383
- this.pageRatio = width / height;
32384
- const scaledViewport = page.getViewport({
32385
- scale: this.scale,
32386
- rotation
32387
- });
32388
- this.thumbnailHeight = Math.ceil(scaledViewport.height);
32389
- return Promise.resolve(this.thumbnailHeight);
32390
- });
32581
+ const listItems = Array.prototype.slice.call(listEl.children, start, end);
32582
+ listItems.forEach(listItem => listEl.removeChild(listItem));
32391
32583
  }
32392
32584
 
32393
32585
  /**
32394
- * Creates the image element
32395
- * @param {string} dataUrl - The image data URL for the thumbnail
32396
- * @return {HTMLElement} - The image element
32586
+ * Render a single item
32587
+ *
32588
+ * @param {number} rowIndex - The index of the item to be rendered
32589
+ * @return {HTMLElement} The newly created row item
32397
32590
  */
32398
- createImageEl(dataUrl, thumbOptions) {
32399
- const imageEl = thumbOptions && thumbOptions.createImgTag ? document.createElement('img') : document.createElement('div');
32400
- if (thumbOptions && thumbOptions.createImgTag) {
32401
- imageEl.src = `${dataUrl}`;
32402
- return imageEl;
32591
+ renderItem(rowIndex) {
32592
+ const rowEl = document.createElement('li');
32593
+ const topPosition = (this.itemHeight + this.margin) * rowIndex + this.margin;
32594
+ let renderedThumbnail;
32595
+ try {
32596
+ renderedThumbnail = this.renderItemFn.call(this, rowIndex);
32597
+ } catch (err) {
32598
+ // eslint-disable-next-line
32599
+ console.error(`Error rendering thumbnail - ${err}`);
32403
32600
  }
32404
- imageEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE);
32405
- imageEl.style.backgroundImage = `url('${dataUrl}')`;
32406
-
32407
- // Add the height and width to the image to be the same as the thumbnail
32408
- // so that the css `background-image` rules will work
32409
- imageEl.style.width = `${THUMBNAIL_TOTAL_WIDTH}px`;
32410
- imageEl.style.height = `${this.thumbnailHeight}px`;
32411
- return imageEl;
32601
+ rowEl.style.top = `${topPosition}px`;
32602
+ rowEl.style.height = `${this.itemHeight}px`;
32603
+ rowEl.classList.add('bp-vs-list-item');
32604
+ rowEl.dataset.bpVsRowIndex = rowIndex;
32605
+ if (renderedThumbnail) {
32606
+ rowEl.appendChild(renderedThumbnail);
32607
+ }
32608
+ return rowEl;
32412
32609
  }
32413
32610
 
32414
32611
  /**
32415
- * Make a thumbnail image element
32612
+ * Utility to create the list element
32416
32613
  *
32417
- * @param {number} itemIndex - the item index for the overall list (0 indexed)
32418
- * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
32614
+ * @return {HTMLElement} The list element
32419
32615
  */
32420
- createThumbnailImage(itemIndex, thumbOptions) {
32421
- const cacheEntry = this.getImageFromCache(itemIndex);
32422
- // If this thumbnail has already been cached, use it
32423
- if (cacheEntry && cacheEntry.image) {
32424
- return Promise.resolve(cacheEntry.image);
32425
- }
32616
+ createListElement() {
32617
+ const newListEl = document.createElement('ol');
32618
+ newListEl.className = 'bp-vs-list';
32619
+ newListEl.style.height = `${this.totalItems * (this.itemHeight + this.margin) + this.margin}px`;
32620
+ return newListEl;
32621
+ }
32426
32622
 
32427
- // If this thumbnail has already been requested, resolve with null
32428
- if (cacheEntry && cacheEntry.inProgress) {
32429
- return Promise.resolve(null);
32623
+ /**
32624
+ * Scrolls the provided row index into view.
32625
+ * @param {number} rowIndex - the index of the row in the overall list
32626
+ * @return {void}
32627
+ */
32628
+ scrollIntoView(rowIndex) {
32629
+ if (!this.scrollingEl || rowIndex < 0 || rowIndex >= this.totalItems) {
32630
+ return;
32430
32631
  }
32431
32632
 
32432
- // Update the cache entry to be in progress
32433
- this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
32434
- inProgress: true
32435
- }));
32436
- return this.getThumbnailDataURL(itemIndex + 1, thumbOptions).then(dataUrl => {
32437
- return this.createImageEl(dataUrl, thumbOptions);
32438
- }).then(imageEl => {
32439
- // Cache this image element for future use
32440
- this.thumbnailImageCache.set(itemIndex, {
32441
- inProgress: false,
32442
- image: imageEl
32443
- });
32444
- return imageEl;
32445
- }).catch(() => {
32446
- this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, this.getImageFromCache(itemIndex)), {}, {
32447
- inProgress: false
32448
- }));
32449
- throw new Error('Thumbnail generation failed');
32633
+ // See if the list item indexed by `rowIndex` is already present
32634
+ const foundItem = this.getListItems().find(listItem => {
32635
+ const {
32636
+ bpVsRowIndex
32637
+ } = listItem.dataset;
32638
+ const parsedRowIndex = parseInt(bpVsRowIndex, 10);
32639
+ return parsedRowIndex === rowIndex;
32450
32640
  });
32641
+ if (foundItem) {
32642
+ // If it is already present and visible, do nothing, but if not visible
32643
+ // then scroll it into view
32644
+ if (!this.isVisible(foundItem)) {
32645
+ foundItem.scrollIntoView({
32646
+ block: 'nearest'
32647
+ });
32648
+ }
32649
+ } else {
32650
+ // If it is not present, then adjust the scrollTop so that the list item
32651
+ // will get rendered.
32652
+ const topPosition = (this.itemHeight + this.margin) * rowIndex;
32653
+ this.scrollingEl.scrollTop = topPosition;
32654
+ // Some browsers don't fire the scroll event when setting scrollTop
32655
+ // (IE11 & Firefox) so we need to manually dispatch the event
32656
+ // in order to trigger `onScrollHandler` to render the items
32657
+ this.scrollingEl.dispatchEvent(new Event('scroll'));
32658
+ }
32451
32659
  }
32452
32660
 
32453
32661
  /**
32454
- * Make a thumbnail image element
32455
- *
32456
- * @param {number} itemIndex - the item index for the overall list (0 indexed)
32457
- * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
32662
+ * Checks to see whether the provided list item element is currently visible
32663
+ * @param {HTMLElement} listItemEl - the list item elment
32664
+ * @return {boolean} Returns true if the list item is visible, false otherwise
32458
32665
  */
32459
- getImageFromCache(itemIndex) {
32460
- return this.thumbnailImageCache.get(itemIndex);
32666
+ isVisible(listItemEl) {
32667
+ if (!this.scrollingEl || !listItemEl) {
32668
+ return false;
32669
+ }
32670
+ const {
32671
+ scrollTop
32672
+ } = this.scrollingEl;
32673
+ const {
32674
+ offsetTop
32675
+ } = listItemEl;
32676
+
32677
+ // Ensure that the offsetTop and entire height of the listItemEl are inside the visible window
32678
+ return scrollTop <= offsetTop && offsetTop + this.itemHeight <= scrollTop + this.containerHeight;
32461
32679
  }
32462
32680
 
32463
32681
  /**
32464
- * Given a page number, generates the image data URL for the image of the page
32465
- * @param {number} pageNum - The page number of the document
32466
- * @return {string} The data URL of the page image
32682
+ * Gets the currently visible list items
32683
+ * @return {Array<HTMLElement>} - the list of current visible list items
32467
32684
  */
32468
- getThumbnailDataURL(pageNum, thumbOptions) {
32469
- if (this.preloader?.preloadedImages?.[pageNum]) {
32470
- return Promise.resolve(this.preloader.preloadedImages[pageNum]);
32471
- }
32472
- const pdfDocument = this.pdfViewer?.pdfDocument;
32473
- if (!pdfDocument) {
32474
- return Promise.reject(new Error('PDF document not ready'));
32685
+ getVisibleItems() {
32686
+ if (!this.listEl) {
32687
+ return [];
32475
32688
  }
32476
- const canvas = document.createElement('canvas');
32477
- const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
32478
- return pdfDocument.getPage(pageNum).then(page => {
32479
- const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
32480
- const viewport = page.getViewport({
32481
- scale: 1,
32482
- rotation
32483
- });
32484
- if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
32485
- return Promise.reject(new Error('Invalid page viewport'));
32486
- }
32487
- const {
32488
- width,
32489
- height
32490
- } = viewport;
32491
- // Get the current page w:h ratio in case it differs from the first page
32492
- const curPageRatio = width / height;
32689
+ return this.getListItems().filter(itemEl => this.isVisible(itemEl)).map(itemEl => itemEl && itemEl.children && itemEl.children[0]);
32690
+ }
32493
32691
 
32494
- // Handle the case where the current page's w:h ratio is less than the
32495
- // `pageRatio` which means that this page is probably more portrait than
32496
- // landscape
32497
- if (curPageRatio < this.pageRatio) {
32498
- // Set the canvas height to that of the thumbnail max height
32499
- canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
32500
- // Find the canvas width based on the current page ratio
32501
- canvas.width = canvas.height * curPageRatio;
32502
- } else {
32503
- // In case the current page ratio is same as the first page
32504
- // or in case it's larger (which means that it's wider), keep
32505
- // the width at the max thumbnail width
32506
- canvas.width = thumbnailImageWidth;
32507
- // Find the height based on the current page ratio
32508
- canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
32509
- }
32510
- // The amount for which to scale down the current page
32511
- const {
32512
- width: canvasWidth
32513
- } = canvas;
32514
- const scale = canvasWidth / width;
32515
- return page.render({
32516
- canvasContext: canvas.getContext('2d'),
32517
- viewport: page.getViewport({
32518
- scale,
32519
- rotation
32520
- })
32521
- }).promise;
32522
- }).then(() => canvas.toDataURL());
32692
+ /**
32693
+ * Gets the list items of this.listEl as an array
32694
+ * @return {Array<HTMLElement>} - the list items
32695
+ */
32696
+ getListItems() {
32697
+ if (!this.listEl) {
32698
+ return [];
32699
+ }
32700
+ return Array.prototype.slice.call(this.listEl.children);
32523
32701
  }
32524
32702
  }
32525
- /* harmony default export */ const lib_Thumbnail = (Thumbnail);
32703
+ /* harmony default export */ const lib_VirtualScroller = (VirtualScroller);
32526
32704
  ;// ./src/lib/ThumbnailsSidebar.js
32527
32705
  function ThumbnailsSidebar_defineProperty(e, r, t) { return (r = ThumbnailsSidebar_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
32528
32706
  function ThumbnailsSidebar_toPropertyKey(t) { var i = ThumbnailsSidebar_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -32991,7 +33169,6 @@ function DocBaseViewer_toPrimitive(t, r) { if ("object" != typeof t || !t) retur
32991
33169
 
32992
33170
 
32993
33171
 
32994
-
32995
33172
 
32996
33173
 
32997
33174
  const DOC_FIRST_PAGES_ENABLED = 'docFirstPages.enabled';
@@ -33026,8 +33203,7 @@ const RANGE_CHUNK_SIZE_US = 1048576; // 1MB
33026
33203
  const RANGE_REQUEST_MINIMUM_SIZE = 26214400; // 25MB
33027
33204
  const SAFARI_PRINT_TIMEOUT_MS = 1000; // Wait 1s before trying to print
33028
33205
  const SCROLL_EVENT_THROTTLE_INTERVAL = 200;
33029
- const GALLERY_MAX_PAGES = 200; // Hide gallery toggle for files above this page count, will increase in V2
33030
- const THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // 301ms
33206
+ const DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // 301ms
33031
33207
  const THUMBNAILS_SIDEBAR_TOGGLED_MAP_KEY = 'doc-thumbnails-toggled-map';
33032
33208
  const MAX_OPERATIONS = 320000; // Block PDFs with more than 320,000 drawing operations
33033
33209
  const MAX_OPERATION_PAGES = 5; // Check only the first 5 pages
@@ -33056,18 +33232,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33056
33232
  //--------------------------------------------------------------------------
33057
33233
  /** @property {Thumbnail} - Thumbnail reference */
33058
33234
  DocBaseViewer_defineProperty(this, "advancedInsightsThumbs", void 0);
33059
- /** @property {number} - Page focused in gallery via Tab */
33060
- DocBaseViewer_defineProperty(this, "galleryFocusedPage", null);
33061
- /** @property {number} - Pending setTimeout ID for delayed gallery mount */
33062
- DocBaseViewer_defineProperty(this, "galleryMountTimeoutId", null);
33063
- /** @property {number} - Pending setTimeout ID for delayed sidebar setCurrentPage after gallery exit */
33064
- DocBaseViewer_defineProperty(this, "gallerySidebarTimeoutId", null);
33065
- /** @property {Thumbnail} - Dedicated gallery thumbnail instance (persists between opens) */
33066
- DocBaseViewer_defineProperty(this, "galleryThumbnail", void 0);
33067
- /** @property {boolean} - Whether gallery mode is active */
33068
- DocBaseViewer_defineProperty(this, "isGalleryOpen", false);
33069
- /** @property {boolean} - Whether sidebar was open before entering gallery */
33070
- DocBaseViewer_defineProperty(this, "sidebarWasOpen", false);
33235
+ /** @property {GalleryController} - Owns gallery-view state, lifecycle, and toolbar gating */
33236
+ DocBaseViewer_defineProperty(this, "galleryController", void 0);
33071
33237
  /** @property {PageTracker} - PageTracker instance */
33072
33238
  DocBaseViewer_defineProperty(this, "pageTracker", void 0);
33073
33239
  DocBaseViewer_defineProperty(this, "doc", void 0);
@@ -33088,7 +33254,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33088
33254
  this.handleAnnotationCreateEvent = this.handleAnnotationCreateEvent.bind(this);
33089
33255
  this.handleAnnotationCreatorChangeEvent = this.handleAnnotationCreatorChangeEvent.bind(this);
33090
33256
  this.handleDocElKeydown = this.handleDocElKeydown.bind(this);
33091
- this.handleGalleryNavigate = this.handleGalleryNavigate.bind(this);
33092
33257
  this.handlePageSubmit = this.handlePageSubmit.bind(this);
33093
33258
  this.onThumbnailSelectHandler = this.onThumbnailSelectHandler.bind(this);
33094
33259
  this.pagechangingHandler = this.pagechangingHandler.bind(this);
@@ -33103,7 +33268,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33103
33268
  this.setPage = this.setPage.bind(this);
33104
33269
  this.throttledScrollHandler = this.getScrollHandler().bind(this);
33105
33270
  this.toggleFindBar = this.toggleFindBar.bind(this);
33106
- this.toggleGallery = this.toggleGallery.bind(this);
33107
33271
  this.toggleThumbnails = this.toggleThumbnails.bind(this);
33108
33272
  this.updateExperiences = this.updateExperiences.bind(this);
33109
33273
  this.updateDiscoverabilityResinTag = this.updateDiscoverabilityResinTag.bind(this);
@@ -33158,6 +33322,16 @@ class DocBaseViewer extends viewers_BaseViewer {
33158
33322
  if (isFeatureEnabled(this.options.features, 'advancedContentInsights.enabled')) {
33159
33323
  this.pageTracker = new lib_PageTracker(advancedContentInsightsConfig, this.options.file);
33160
33324
  }
33325
+ this.galleryController = new GalleryController({
33326
+ containerEl: this.containerEl,
33327
+ features: this.options.features,
33328
+ getPdfViewer: () => this.pdfViewer,
33329
+ getPreloader: () => this.preloader,
33330
+ getThumbnailsSidebar: () => this.thumbnailsSidebar,
33331
+ setPage: n => this.setPage(n),
33332
+ toggleThumbnails: () => this.toggleThumbnails(),
33333
+ requestUiUpdate: () => this.renderUI()
33334
+ });
33161
33335
  }
33162
33336
 
33163
33337
  /**
@@ -33183,26 +33357,9 @@ class DocBaseViewer extends viewers_BaseViewer {
33183
33357
  this.findBar.destroy();
33184
33358
  }
33185
33359
 
33186
- // Cancel any pending gallery setTimeouts so they don't fire after teardown
33187
- if (this.galleryMountTimeoutId !== null) {
33188
- clearTimeout(this.galleryMountTimeoutId);
33189
- this.galleryMountTimeoutId = null;
33190
- }
33191
- if (this.gallerySidebarTimeoutId !== null) {
33192
- clearTimeout(this.gallerySidebarTimeoutId);
33193
- this.gallerySidebarTimeoutId = null;
33194
- }
33195
- if (this.galleryRoot) {
33196
- this.galleryRoot.unmount();
33197
- this.galleryRoot = null;
33198
- }
33199
- if (this.galleryEl) {
33200
- this.galleryEl.remove();
33201
- this.galleryEl = null;
33202
- }
33203
- if (this.galleryThumbnail) {
33204
- this.galleryThumbnail.destroy();
33205
- this.galleryThumbnail = null;
33360
+ // Must run before pdfViewer teardown galleryController holds Thumbnail render promises against pdfViewer
33361
+ if (this.galleryController) {
33362
+ this.galleryController.destroy();
33206
33363
  }
33207
33364
 
33208
33365
  // Clean up PDF network requests
@@ -33810,9 +33967,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33810
33967
  if (this.thumbnailsSidebar) {
33811
33968
  this.thumbnailsSidebar.refresh();
33812
33969
  }
33813
- if (this.galleryThumbnail) {
33814
- this.galleryThumbnail.destroy();
33815
- this.galleryThumbnail = null;
33970
+ if (this.galleryController) {
33971
+ this.galleryController.handleRotate();
33816
33972
  }
33817
33973
  this.renderUI();
33818
33974
 
@@ -34378,7 +34534,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34378
34534
  const canDownload = checkPermission(this.options.file, PERMISSION_DOWNLOAD);
34379
34535
  const isAnnotationsMode = this.currentAnnotatorViewMode === ANNOTATOR_VIEW_MODES.ANNOTATIONS;
34380
34536
  const canRotate = this.featureEnabled('rotate.enabled');
34381
- const canGallery = isFeatureEnabled(this.options.features, 'galleryView.enabled') && this.pdfViewer.pagesCount > 1 && this.pdfViewer.pagesCount <= GALLERY_MAX_PAGES;
34537
+ const canGallery = this.galleryController.canRender(this.pdfViewer.pagesCount);
34382
34538
  this.controls.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(DocControls, {
34383
34539
  annotationColor: this.annotationModule.getColor(),
34384
34540
  annotationMode: this.annotationControlsFSM.getMode(),
@@ -34386,7 +34542,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34386
34542
  hasDrawing: canAnnotate && showAnnotationsDrawingCreate && isAnnotationsMode,
34387
34543
  hasHighlight: canAnnotate && canDownload && isAnnotationsMode,
34388
34544
  hasRegion: canAnnotate && isAnnotationsMode,
34389
- isGalleryOpen: this.isGalleryOpen,
34545
+ isGalleryOpen: this.galleryController.isOpen,
34390
34546
  isThumbnailsOpen: this.thumbnailsSidebar && this.thumbnailsSidebar.isOpen,
34391
34547
  maxScale: DocBaseViewer_MAX_SCALE,
34392
34548
  minScale: DocBaseViewer_MIN_SCALE,
@@ -34395,7 +34551,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34395
34551
  onAnnotationModeEscape: this.handleAnnotationControlsEscape,
34396
34552
  onFindBarToggle: !this.isFindDisabled() ? this.toggleFindBar : undefined,
34397
34553
  onFullscreenToggle: this.toggleFullscreen,
34398
- onGalleryToggle: canGallery ? this.toggleGallery : undefined,
34554
+ onGalleryToggle: canGallery ? this.galleryController.toggle : undefined,
34399
34555
  onPageChange: this.setPage,
34400
34556
  onPageSubmit: this.handlePageSubmit,
34401
34557
  onRotateLeft: canRotate ? this.rotateLeft : undefined,
@@ -34629,8 +34785,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34629
34785
  */
34630
34786
  handleDocElKeydown(event) {
34631
34787
  const key = decodeKeydown(event);
34632
- if (key === 'Escape' && this.isGalleryOpen) {
34633
- this.toggleGallery();
34788
+ if (key === 'Escape' && this.galleryController.handleEscape()) {
34634
34789
  return;
34635
34790
  }
34636
34791
  if (event.altKey && key.includes('Arrow')) {
@@ -34881,80 +35036,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34881
35036
  // Remove the active classes to allow the container to be transitioned properly
34882
35037
  this.rootEl.classList.remove(CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE);
34883
35038
  this.rootEl.classList.remove(CLASS_BOX_PREVIEW_THUMBNAILS_OPEN_ACTIVE);
34884
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34885
- }
34886
- mountGalleryGrid() {
34887
- if (this.galleryRoot) {
34888
- return;
34889
- }
34890
- if (!this.galleryThumbnail) {
34891
- this.galleryThumbnail = new lib_Thumbnail(this.pdfViewer, this.preloader);
34892
- }
34893
- this.galleryEl = document.createElement('div');
34894
- this.containerEl.appendChild(this.galleryEl);
34895
- this.galleryRoot = __WEBPACK_EXTERNAL_MODULE_react_dom_client_4cb20cd7_createRoot__(this.galleryEl);
34896
- this.galleryFocusedPage = this.pdfViewer.currentPageNumber;
34897
- this.galleryRoot.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryGrid, {
34898
- currentPage: this.pdfViewer.currentPageNumber,
34899
- onClose: this.toggleGallery,
34900
- onFocusChange: pageNum => {
34901
- this.galleryFocusedPage = pageNum;
34902
- },
34903
- onPageNavigate: this.handleGalleryNavigate,
34904
- pageCount: this.pdfViewer.pagesCount,
34905
- thumbnail: this.galleryThumbnail
34906
- }));
34907
- }
34908
- toggleGallery() {
34909
- this.isGalleryOpen = !this.isGalleryOpen;
34910
- if (this.isGalleryOpen) {
34911
- if (this.gallerySidebarTimeoutId !== null) {
34912
- clearTimeout(this.gallerySidebarTimeoutId);
34913
- this.gallerySidebarTimeoutId = null;
34914
- }
34915
- this.sidebarWasOpen = !!(this.thumbnailsSidebar && this.thumbnailsSidebar.isOpen);
34916
- if (this.sidebarWasOpen) {
34917
- this.toggleThumbnails();
34918
- this.galleryMountTimeoutId = setTimeout(() => {
34919
- this.galleryMountTimeoutId = null;
34920
- this.mountGalleryGrid();
34921
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME / 2);
34922
- } else {
34923
- this.mountGalleryGrid();
34924
- }
34925
- } else {
34926
- if (this.galleryMountTimeoutId !== null) {
34927
- clearTimeout(this.galleryMountTimeoutId);
34928
- this.galleryMountTimeoutId = null;
34929
- }
34930
- const navigateToPage = this.galleryFocusedPage && this.galleryFocusedPage !== this.pdfViewer.currentPageNumber ? this.galleryFocusedPage : null;
34931
- if (this.galleryRoot) {
34932
- this.galleryRoot.unmount();
34933
- this.galleryRoot = null;
34934
- }
34935
- if (this.galleryEl) {
34936
- this.galleryEl.remove();
34937
- this.galleryEl = null;
34938
- }
34939
- this.galleryFocusedPage = null;
34940
- if (this.sidebarWasOpen && this.thumbnailsSidebar && !this.thumbnailsSidebar.isOpen) {
34941
- this.toggleThumbnails();
34942
- }
34943
- if (navigateToPage) {
34944
- this.setPage(navigateToPage);
34945
- if (this.sidebarWasOpen && this.thumbnailsSidebar) {
34946
- this.gallerySidebarTimeoutId = setTimeout(() => {
34947
- this.gallerySidebarTimeoutId = null;
34948
- this.thumbnailsSidebar.setCurrentPage(navigateToPage);
34949
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34950
- }
34951
- }
34952
- }
34953
- this.renderUI();
34954
- }
34955
- handleGalleryNavigate(pageNum) {
34956
- this.galleryFocusedPage = pageNum;
34957
- this.toggleGallery();
35039
+ }, DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34958
35040
  }
34959
35041
 
34960
35042
  /**