box-content-preview 3.51.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.51.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 = {};
@@ -9611,14 +9611,21 @@ function appendAuthParamsV2(url) {
9611
9611
  * @public
9612
9612
  * @param {string} template - URL template to attach param to
9613
9613
  * @param {string|void} [asset] - Optional asset name needed to access file
9614
+ * @param {boolean} [resolveCacheBuster] - Re-resolve the _cache_buster marker per request
9615
+ * (needed only when auth is header-based; the in-URL token otherwise varies the cache key).
9614
9616
  * @return {string} Content url
9615
9617
  */
9616
9618
  function createContentUrl(template, asset) {
9619
+ let resolveCacheBuster = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
9617
9620
  if (lib_DownloadReachability.isDownloadHostBlocked()) {
9618
9621
  // eslint-disable-next-line
9619
9622
  template = lib_DownloadReachability.replaceDownloadHostWithDefault(template);
9620
9623
  }
9621
- return template.replace('{+asset_path}', asset || '');
9624
+ const url = template.replace('{+asset_path}', asset || '');
9625
+ if (!resolveCacheBuster) {
9626
+ return url;
9627
+ }
9628
+ return url.replace(/([?&]_cache_buster=)[^&]*/, `$1${Date.now().toString(36)}`);
9622
9629
  }
9623
9630
 
9624
9631
  /**
@@ -11058,7 +11065,7 @@ class Browser {
11058
11065
  ;// ./src/lib/Logger.js
11059
11066
  /* eslint-disable no-undef */
11060
11067
  const Logger_CLIENT_NAME = "box-content-preview";
11061
- const Logger_CLIENT_VERSION = "3.51.0";
11068
+ const Logger_CLIENT_VERSION = "3.53.0";
11062
11069
  /* eslint-enable no-undef */
11063
11070
 
11064
11071
  class Logger {
@@ -12553,11 +12560,15 @@ class BaseViewer extends (events_default()) {
12553
12560
  template = this.api.reachability.constructor.replaceDownloadHostWithDefault(template);
12554
12561
  }
12555
12562
 
12563
+ // Cache-buster only needed when auth is header-based; the in-URL token otherwise
12564
+ // varies the cache key on its own.
12565
+ const resolveCacheBuster = this.featureEnabled('migrateAccessTokenToHeader');
12566
+
12556
12567
  // Append optional query params
12557
12568
  const {
12558
12569
  queryParams
12559
12570
  } = this.options;
12560
- return appendQueryParams(createContentUrl(template, asset), queryParams);
12571
+ return appendQueryParams(createContentUrl(template, asset, resolveCacheBuster), queryParams);
12561
12572
  }
12562
12573
 
12563
12574
  /**
@@ -19173,7 +19184,10 @@ function addOriginalRepresentation(file) {
19173
19184
  return;
19174
19185
  }
19175
19186
  const queryParams = {
19176
- preview: 'true'
19187
+ preview: 'true',
19188
+ // Cache-buster marker; createContentUrl() re-resolves it per request when auth is
19189
+ // header-based. Stamped unconditionally since the file is cached before that flag is known.
19190
+ _cache_buster: Date.now().toString(36)
19177
19191
  };
19178
19192
  if (file.file_version) {
19179
19193
  queryParams.version = file.file_version.id;
@@ -30937,156 +30951,597 @@ class DocFindBar extends (events_default()) {
30937
30951
  }
30938
30952
  }
30939
30953
  /* harmony default export */ const doc_DocFindBar = (DocFindBar);
30940
- ;// ./src/lib/viewers/gallery/GalleryGrid.scss
30941
- // extracted by mini-css-extract-plugin
30942
-
30943
- ;// ./src/lib/viewers/gallery/GalleryGrid.tsx
30944
- function GalleryGrid_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; }
30945
- function GalleryGrid_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? GalleryGrid_ownKeys(Object(t), !0).forEach(function (r) { GalleryGrid_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : GalleryGrid_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
30946
- function GalleryGrid_defineProperty(e, r, t) { return (r = GalleryGrid_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
30947
- function GalleryGrid_toPropertyKey(t) { var i = GalleryGrid_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
30948
- function GalleryGrid_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); }
30954
+ ;// ./src/lib/Cache.js
30949
30955
 
30956
+ class Cache {
30957
+ //--------------------------------------------------------------------------
30958
+ // Public
30959
+ //--------------------------------------------------------------------------
30950
30960
 
30961
+ /**
30962
+ * [constructor]
30963
+ *
30964
+ * @return {Cache} Cache instance
30965
+ */
30966
+ constructor() {
30967
+ this.cache = {};
30968
+ }
30951
30969
 
30952
- const GALLERY_THUMB_MAX_WIDTH = 440;
30953
- const INITIAL_LOAD_BUFFER = 40;
30954
- const CONCURRENT_LOADS = 4;
30955
- const SCROLL_THROTTLE_MS = 200;
30956
- function GalleryGrid(_ref) {
30957
- let {
30958
- pageCount,
30959
- currentPage,
30960
- onClose,
30961
- onFocusChange,
30962
- onPageNavigate,
30963
- thumbnail
30964
- } = _ref;
30965
- const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
30966
- const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
30967
- const gridRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
30968
- const queueRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__([]);
30969
- const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
30970
- const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
30971
- const initialLoadDoneRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
30972
- const initialLoadCountRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(0);
30973
- function processQueue() {
30974
- if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
30975
- isProcessingRef.current = false;
30976
- return;
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));
30977
30984
  }
30978
- const batchSize = initialLoadDoneRef.current ? CONCURRENT_LOADS : 1;
30979
- const batch = queueRef.current.slice(0, batchSize);
30980
- queueRef.current = queueRef.current.slice(batchSize);
30981
- requestAnimationFrame(() => {
30982
- if (!isMountedRef.current || !thumbnail) {
30983
- isProcessingRef.current = false;
30984
- return;
30985
- }
30986
- let completed = 0;
30987
- const onComplete = () => {
30988
- completed += 1;
30989
- if (completed < batch.length) return;
30990
- if (!isMountedRef.current) {
30991
- isProcessingRef.current = false;
30992
- return;
30993
- }
30994
- if (!initialLoadDoneRef.current) {
30995
- initialLoadCountRef.current += batch.length;
30996
- if (initialLoadCountRef.current >= INITIAL_LOAD_BUFFER) {
30997
- initialLoadDoneRef.current = true;
30998
- isProcessingRef.current = false;
30999
- return;
31000
- }
31001
- }
31002
- processQueue();
31003
- };
31004
- batch.forEach(pageNum => {
31005
- thumbnail.createThumbnailImage(pageNum - 1, {
31006
- createImgTag: true,
31007
- thumbMaxWidth: GALLERY_THUMB_MAX_WIDTH
31008
- }).then(imageEl => {
31009
- if (isMountedRef.current && imageEl && imageEl.src) {
31010
- setLoadedImages(prev => GalleryGrid_objectSpread(GalleryGrid_objectSpread({}, prev), {}, {
31011
- [pageNum]: imageEl.src
31012
- }));
31013
- }
31014
- onComplete();
31015
- }).catch(() => {
31016
- onComplete();
31017
- });
31018
- });
31019
- });
31020
30985
  }
31021
- function startProcessing() {
31022
- if (!isProcessingRef.current && queueRef.current.length > 0) {
31023
- isProcessingRef.current = true;
31024
- processQueue();
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));
31025
30997
  }
30998
+ delete this.cache[key];
31026
30999
  }
31027
- function getUnloadedNearViewport() {
31028
- const grid = gridRef.current;
31029
- if (!grid) return [];
31030
- const {
31031
- scrollTop,
31032
- clientHeight
31033
- } = grid;
31034
- const bufferZone = clientHeight * 3;
31035
- const viewportTop = scrollTop - bufferZone;
31036
- const viewportBottom = scrollTop + clientHeight + bufferZone;
31037
- const nearbyUnloaded = [];
31038
- const tiles = grid.querySelectorAll('[data-page]');
31039
- tiles.forEach(tile => {
31040
- const el = tile;
31041
- if (!el.dataset.page) return;
31042
- const pageNum = parseInt(el.dataset.page, 10);
31043
- const tileTop = el.offsetTop;
31044
- const tileBottom = tileTop + el.offsetHeight;
31045
- if (tileBottom > viewportTop && tileTop < viewportBottom && !el.querySelector('img')) {
31046
- nearbyUnloaded.push(pageNum);
31047
- }
31048
- });
31049
- return nearbyUnloaded;
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);
31050
31010
  }
31051
- const handleScrollRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(throttle_default()(() => {
31052
- const nearbyUnloaded = getUnloadedNearViewport();
31053
- if (nearbyUnloaded.length > 0) {
31054
- const currentQueue = queueRef.current;
31055
- const toAdd = nearbyUnloaded.filter(p => !currentQueue.includes(p));
31056
- queueRef.current = [...toAdd, ...currentQueue];
31057
- startProcessing();
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];
31058
31024
  }
31059
- }, SCROLL_THROTTLE_MS));
31060
- __WEBPACK_EXTERNAL_MODULE_react_useEffect__(() => {
31061
- const throttledScroll = handleScrollRef.current;
31062
- if (gridRef.current) {
31063
- const tile = gridRef.current.querySelector(`[data-page="${currentPage}"]`);
31064
- if (tile) {
31065
- tile.scrollIntoView({
31066
- block: 'center'
31067
- });
31068
- tile.focus();
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;
31069
31034
  }
31070
31035
  }
31071
- const initialImages = {};
31072
- const uncachedPages = [];
31073
- for (let i = 1; i <= pageCount; i += 1) {
31074
- const cached = thumbnail.getImageFromCache(i - 1);
31075
- if (cached && cached.image && cached.image.src) {
31076
- initialImages[i] = cached.image.src;
31077
- initialLoadCountRef.current += 1;
31078
- } else {
31079
- uncachedPages.push(i);
31080
- }
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;
31081
31064
  }
31082
- if (Object.keys(initialImages).length > 0) {
31083
- setLoadedImages(initialImages);
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();
31084
31082
  }
31085
- uncachedPages.sort((a, b) => Math.abs(a - currentPage) - Math.abs(b - currentPage));
31086
- queueRef.current = uncachedPages;
31087
- thumbnail.init().then(() => {
31088
- if (!isMountedRef.current) return;
31089
- isProcessingRef.current = true;
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);
31395
+ ;// ./src/lib/viewers/gallery/GalleryGrid.scss
31396
+ // extracted by mini-css-extract-plugin
31397
+
31398
+ ;// ./src/lib/viewers/gallery/GalleryGrid.tsx
31399
+ function GalleryGrid_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; }
31400
+ function GalleryGrid_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? GalleryGrid_ownKeys(Object(t), !0).forEach(function (r) { GalleryGrid_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : GalleryGrid_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
31401
+ function GalleryGrid_defineProperty(e, r, t) { return (r = GalleryGrid_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
31402
+ function GalleryGrid_toPropertyKey(t) { var i = GalleryGrid_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31403
+ function GalleryGrid_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); }
31404
+
31405
+
31406
+
31407
+ const GALLERY_THUMB_MAX_WIDTH = 440;
31408
+ const INITIAL_LOAD_BUFFER = 40;
31409
+ const CONCURRENT_LOADS = 4;
31410
+ const SCROLL_THROTTLE_MS = 200;
31411
+ function GalleryGrid(_ref) {
31412
+ let {
31413
+ pageCount,
31414
+ currentPage,
31415
+ onClose,
31416
+ onFocusChange,
31417
+ onPageNavigate,
31418
+ thumbnail
31419
+ } = _ref;
31420
+ const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
31421
+ const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
31422
+ const gridRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
31423
+ const queueRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__([]);
31424
+ const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
31425
+ const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
31426
+ const initialLoadDoneRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
31427
+ const initialLoadCountRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(0);
31428
+ function processQueue() {
31429
+ if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
31430
+ isProcessingRef.current = false;
31431
+ return;
31432
+ }
31433
+ const batchSize = initialLoadDoneRef.current ? CONCURRENT_LOADS : 1;
31434
+ const batch = queueRef.current.slice(0, batchSize);
31435
+ queueRef.current = queueRef.current.slice(batchSize);
31436
+ requestAnimationFrame(() => {
31437
+ if (!isMountedRef.current || !thumbnail) {
31438
+ isProcessingRef.current = false;
31439
+ return;
31440
+ }
31441
+ let completed = 0;
31442
+ const onComplete = () => {
31443
+ completed += 1;
31444
+ if (completed < batch.length) return;
31445
+ if (!isMountedRef.current) {
31446
+ isProcessingRef.current = false;
31447
+ return;
31448
+ }
31449
+ if (!initialLoadDoneRef.current) {
31450
+ initialLoadCountRef.current += batch.length;
31451
+ if (initialLoadCountRef.current >= INITIAL_LOAD_BUFFER) {
31452
+ initialLoadDoneRef.current = true;
31453
+ isProcessingRef.current = false;
31454
+ return;
31455
+ }
31456
+ }
31457
+ processQueue();
31458
+ };
31459
+ batch.forEach(pageNum => {
31460
+ thumbnail.createThumbnailImage(pageNum - 1, {
31461
+ createImgTag: true,
31462
+ thumbMaxWidth: GALLERY_THUMB_MAX_WIDTH
31463
+ }).then(imageEl => {
31464
+ if (isMountedRef.current && imageEl && imageEl.src) {
31465
+ setLoadedImages(prev => GalleryGrid_objectSpread(GalleryGrid_objectSpread({}, prev), {}, {
31466
+ [pageNum]: imageEl.src
31467
+ }));
31468
+ }
31469
+ onComplete();
31470
+ }).catch(() => {
31471
+ onComplete();
31472
+ });
31473
+ });
31474
+ });
31475
+ }
31476
+ function startProcessing() {
31477
+ if (!isProcessingRef.current && queueRef.current.length > 0) {
31478
+ isProcessingRef.current = true;
31479
+ processQueue();
31480
+ }
31481
+ }
31482
+ function getUnloadedNearViewport() {
31483
+ const grid = gridRef.current;
31484
+ if (!grid) return [];
31485
+ const {
31486
+ scrollTop,
31487
+ clientHeight
31488
+ } = grid;
31489
+ const bufferZone = clientHeight * 3;
31490
+ const viewportTop = scrollTop - bufferZone;
31491
+ const viewportBottom = scrollTop + clientHeight + bufferZone;
31492
+ const nearbyUnloaded = [];
31493
+ const tiles = grid.querySelectorAll('[data-page]');
31494
+ tiles.forEach(tile => {
31495
+ const el = tile;
31496
+ if (!el.dataset.page) return;
31497
+ const pageNum = parseInt(el.dataset.page, 10);
31498
+ const tileTop = el.offsetTop;
31499
+ const tileBottom = tileTop + el.offsetHeight;
31500
+ if (tileBottom > viewportTop && tileTop < viewportBottom && !el.querySelector('img')) {
31501
+ nearbyUnloaded.push(pageNum);
31502
+ }
31503
+ });
31504
+ return nearbyUnloaded;
31505
+ }
31506
+ const handleScrollRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(throttle_default()(() => {
31507
+ const nearbyUnloaded = getUnloadedNearViewport();
31508
+ if (nearbyUnloaded.length > 0) {
31509
+ const currentQueue = queueRef.current;
31510
+ const toAdd = nearbyUnloaded.filter(p => !currentQueue.includes(p));
31511
+ queueRef.current = [...toAdd, ...currentQueue];
31512
+ startProcessing();
31513
+ }
31514
+ }, SCROLL_THROTTLE_MS));
31515
+ __WEBPACK_EXTERNAL_MODULE_react_useEffect__(() => {
31516
+ const throttledScroll = handleScrollRef.current;
31517
+ if (gridRef.current) {
31518
+ const tile = gridRef.current.querySelector(`[data-page="${currentPage}"]`);
31519
+ if (tile) {
31520
+ tile.scrollIntoView({
31521
+ block: 'center'
31522
+ });
31523
+ tile.focus();
31524
+ }
31525
+ }
31526
+ const initialImages = {};
31527
+ const uncachedPages = [];
31528
+ for (let i = 1; i <= pageCount; i += 1) {
31529
+ const cached = thumbnail.getImageFromCache(i - 1);
31530
+ if (cached && cached.image && cached.image.src) {
31531
+ initialImages[i] = cached.image.src;
31532
+ initialLoadCountRef.current += 1;
31533
+ } else {
31534
+ uncachedPages.push(i);
31535
+ }
31536
+ }
31537
+ if (Object.keys(initialImages).length > 0) {
31538
+ setLoadedImages(initialImages);
31539
+ }
31540
+ uncachedPages.sort((a, b) => Math.abs(a - currentPage) - Math.abs(b - currentPage));
31541
+ queueRef.current = uncachedPages;
31542
+ thumbnail.init().then(() => {
31543
+ if (!isMountedRef.current) return;
31544
+ isProcessingRef.current = true;
31090
31545
  processQueue();
31091
31546
  });
31092
31547
  return () => {
@@ -31118,51 +31573,229 @@ function GalleryGrid(_ref) {
31118
31573
  onClose();
31119
31574
  return;
31120
31575
  }
31121
- if (event.key === 'Tab' && gridRef.current) {
31122
- const buttons = gridRef.current.querySelectorAll('button');
31123
- const first = buttons[0];
31124
- const last = buttons[buttons.length - 1];
31125
- if (event.shiftKey && document.activeElement === first) {
31126
- event.preventDefault();
31127
- last.focus();
31128
- } else if (!event.shiftKey && document.activeElement === last) {
31129
- event.preventDefault();
31130
- first.focus();
31131
- }
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());
31132
31784
  }
31133
- }, [onClose]);
31134
- const tiles = [];
31135
- for (let i = 1; i <= pageCount; i += 1) {
31136
- const isFocused = i === focusedPage;
31137
- tiles.push( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
31138
- key: i,
31139
- "aria-label": `Page ${i}${isFocused ? ', current page' : ''}`,
31140
- className: `bp-gallery-tile${isFocused ? ' bp-gallery-tile--selected' : ''}`,
31141
- "data-page": i,
31142
- onClick: () => onPageNavigate(i),
31143
- onFocus: () => handleTileFocus(i),
31144
- type: "button"
31145
- }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31146
- className: "bp-gallery-tile-badge"
31147
- }, i), loadedImages[i] ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("img", {
31148
- alt: `Page ${i}`,
31149
- src: loadedImages[i]
31150
- }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31151
- className: "bp-gallery-tile-placeholder"
31152
- })));
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
+ }));
31153
31798
  }
31154
- return (
31155
- /*#__PURE__*/
31156
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
31157
- __WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
31158
- ref: gridRef,
31159
- className: "bp-gallery-grid",
31160
- onFocus: handleGridFocus,
31161
- onKeyDown: handleGridKeyDown,
31162
- onScroll: handleScrollRef.current,
31163
- tabIndex: -1
31164
- }, tiles)
31165
- );
31166
31799
  }
31167
31800
  ;// ./src/lib/logUtils.js
31168
31801
 
@@ -31589,232 +32222,27 @@ class PageTracker extends (events_default()) {
31589
32222
  /**
31590
32223
  * Update content insights options
31591
32224
  *
31592
- * @private
31593
- * @param {Object} options - Content Insights options
31594
- * @return {void}
31595
- */
31596
- updateOptions() {
31597
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
31598
- // Set User and file information
31599
- const prevActiveState = this.isAdvancedInsightsActive;
31600
- this.setOptions(options);
31601
- if (prevActiveState !== this.isAdvancedInsightsActive) {
31602
- // If ACI was deactivated, stop tracking user events
31603
- if (!this.isAdvancedInsightsActive) {
31604
- this.stopTracking();
31605
- this.unbindIdleUserEvents();
31606
- } else {
31607
- this.init();
31608
- }
31609
- }
31610
- }
31611
- }
31612
- /* harmony default export */ const lib_PageTracker = (PageTracker);
31613
- ;// ./src/lib/Cache.js
31614
-
31615
- class Cache {
31616
- //--------------------------------------------------------------------------
31617
- // Public
31618
- //--------------------------------------------------------------------------
31619
-
31620
- /**
31621
- * [constructor]
31622
- *
31623
- * @return {Cache} Cache instance
31624
- */
31625
- constructor() {
31626
- this.cache = {};
31627
- }
31628
-
31629
- /**
31630
- * Caches a simple object in memory and in localStorage if specified.
31631
- * Note that objects cached in localStorage will be stringified.
31632
- *
31633
- * @public
31634
- * @param {string} key - The cache key
31635
- * @param {*} value - The cache value
31636
- * @param {boolean} useLocalStorage - Whether or not to use localStorage
31637
- * @return {void}
31638
- */
31639
- set(key, value, useLocalStorage) {
31640
- this.cache[key] = value;
31641
- if (useLocalStorage && this.isLocalStorageAvailable()) {
31642
- localStorage.setItem(this.generateKey(key), JSON.stringify(value));
31643
- }
31644
- }
31645
-
31646
- /**
31647
- * Deletes object from in-memory cache and localStorage.
31648
- *
31649
- * @public
31650
- * @param {string} key - The cache key
31651
- * @return {void}
31652
- */
31653
- unset(key) {
31654
- if (this.isLocalStorageAvailable()) {
31655
- localStorage.removeItem(this.generateKey(key));
31656
- }
31657
- delete this.cache[key];
31658
- }
31659
-
31660
- /**
31661
- * Checks if cache has provided key.
31662
- *
31663
- * @public
31664
- * @param {string} key - The cache key
31665
- * @return {boolean} Whether the cache has key
31666
- */
31667
- has(key) {
31668
- return this.inCache(key) || this.inLocalStorage(key);
31669
- }
31670
-
31671
- /**
31672
- * Fetches a cached object from in-memory cache if available. Otherwise
31673
- * tries to fetch from localStorage. If fetched from localStorage, object
31674
- * will be a JSON parsed object.
31675
- *
31676
- * @public
31677
- * @param {string} key - Key of cached object
31678
- * @return {Object} Cached object
31679
- */
31680
- get(key) {
31681
- if (this.inCache(key)) {
31682
- return this.cache[key];
31683
- }
31684
-
31685
- // If localStorage is available, try to fetch from there and set it
31686
- // in in-memory cache if found
31687
- if (this.inLocalStorage(key)) {
31688
- let value = localStorage.getItem(this.generateKey(key));
31689
- if (value) {
31690
- value = JSON.parse(value);
31691
- this.cache[key] = value;
31692
- return value;
31693
- }
31694
- }
31695
- return undefined;
31696
- }
31697
-
31698
- //--------------------------------------------------------------------------
31699
- // Private
31700
- //--------------------------------------------------------------------------
31701
-
31702
- /**
31703
- * Checks if memory cache has provided key.
31704
- *
31705
- * @private
31706
- * @param {string} key - The cache key
31707
- * @return {boolean} Whether the cache has key
31708
- */
31709
- inCache(key) {
31710
- return {}.hasOwnProperty.call(this.cache, key);
31711
- }
31712
-
31713
- /**
31714
- * Checks if memory cache has provided key.
31715
- *
31716
- * @private
31717
- * @param {string} key - The cache key
31718
- * @return {boolean} Whether the cache has key
31719
- */
31720
- inLocalStorage(key) {
31721
- if (!this.isLocalStorageAvailable()) {
31722
- return false;
31723
- }
31724
- return !!localStorage.getItem(this.generateKey(key));
31725
- }
31726
-
31727
- /**
31728
- * Checks whether localStorage is available.
31729
- *
31730
- * @NOTE(tjin): This check is cached to not have to write/read from disk
31731
- * every time this check is needed, but this will not catch instances where
31732
- * localStorage was available the first time this is called, but becomes
31733
- * unavailable at a later time.
31734
- *
31735
- * @private
31736
- * @return {boolean} Whether or not localStorage is available or not.
31737
- */
31738
- isLocalStorageAvailable() {
31739
- if (this.available === undefined) {
31740
- this.available = isLocalStorageAvailable();
31741
- }
31742
- return this.available;
31743
- }
31744
-
31745
- /**
31746
- * Generates a key to use for localStorage from the provided key. This
31747
- * should prevent name collisions.
31748
- *
31749
- * @private
31750
- * @param {string} key - Generate key from this key
31751
- * @return {string} Generated key for localStorage
31752
- */
31753
- generateKey(key) {
31754
- return `bp-${key}`;
31755
- }
31756
- }
31757
- /* harmony default export */ const lib_Cache = (Cache);
31758
- ;// ./src/lib/BoundedCache.js
31759
- 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; }
31760
- function BoundedCache_toPropertyKey(t) { var i = BoundedCache_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31761
- 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); }
31762
-
31763
- class BoundedCache extends lib_Cache {
31764
- /**
31765
- * [constructor]
31766
- *
31767
- * @param {number} [maxEntries] - Override the maximum number of cache entries
31768
- */
31769
- constructor(maxEntries) {
31770
- super();
31771
- /** @property {Array} - Maintains the list of cache keys in order in which they were added to the cache */
31772
- BoundedCache_defineProperty(this, "cacheQueue", void 0);
31773
- /** @property {number} - The maximum number of entries in the cache */
31774
- BoundedCache_defineProperty(this, "maxEntries", void 0);
31775
- this.maxEntries = maxEntries || 500;
31776
- this.cache = {};
31777
- this.cacheQueue = [];
31778
- }
31779
-
31780
- /**
31781
- * Destroys the bounded cache
31782
- *
31783
- * @return {void}
31784
- */
31785
- destroy() {
31786
- this.cache = null;
31787
- this.cacheQueue = null;
31788
- }
31789
-
31790
- /**
31791
- * Caches a simple object in memory. If the number of cache entries
31792
- * then exceeds the maxEntries value, then the earliest key in cacheQueue
31793
- * will be removed from the cache.
31794
- *
31795
- * @param {string} key - The cache key
31796
- * @param {*} value - The cache value
32225
+ * @private
32226
+ * @param {Object} options - Content Insights options
31797
32227
  * @return {void}
31798
32228
  */
31799
- set(key, value) {
31800
- // If this key is not already in the cache, then add it
31801
- // to the cacheQueue. This avoids adding the same key to
31802
- // the cacheQueue multiple times if the cache entry gets updated
31803
- if (!this.inCache(key)) {
31804
- this.cacheQueue.push(key);
31805
- }
31806
- super.set(key, value);
31807
-
31808
- // If the cacheQueue exceeds the maxEntries then remove the first
31809
- // key from the front of the cacheQueue and unset that entry
31810
- // from the cache
31811
- if (this.cacheQueue.length > this.maxEntries) {
31812
- const deleteKey = this.cacheQueue.shift();
31813
- 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
+ }
31814
32242
  }
31815
32243
  }
31816
32244
  }
31817
- /* harmony default export */ const lib_BoundedCache = (BoundedCache);
32245
+ /* harmony default export */ const lib_PageTracker = (PageTracker);
31818
32246
  // EXTERNAL MODULE: ./node_modules/lodash/isFunction.js
31819
32247
  var isFunction = __webpack_require__(1882);
31820
32248
  var isFunction_default = /*#__PURE__*/__webpack_require__.n(isFunction);
@@ -32150,365 +32578,129 @@ class VirtualScroller {
32150
32578
  if (!listEl || start < 0 || end < 0) {
32151
32579
  return;
32152
32580
  }
32153
- const listItems = Array.prototype.slice.call(listEl.children, start, end);
32154
- listItems.forEach(listItem => listEl.removeChild(listItem));
32155
- }
32156
-
32157
- /**
32158
- * Render a single item
32159
- *
32160
- * @param {number} rowIndex - The index of the item to be rendered
32161
- * @return {HTMLElement} The newly created row item
32162
- */
32163
- renderItem(rowIndex) {
32164
- const rowEl = document.createElement('li');
32165
- const topPosition = (this.itemHeight + this.margin) * rowIndex + this.margin;
32166
- let renderedThumbnail;
32167
- try {
32168
- renderedThumbnail = this.renderItemFn.call(this, rowIndex);
32169
- } catch (err) {
32170
- // eslint-disable-next-line
32171
- console.error(`Error rendering thumbnail - ${err}`);
32172
- }
32173
- rowEl.style.top = `${topPosition}px`;
32174
- rowEl.style.height = `${this.itemHeight}px`;
32175
- rowEl.classList.add('bp-vs-list-item');
32176
- rowEl.dataset.bpVsRowIndex = rowIndex;
32177
- if (renderedThumbnail) {
32178
- rowEl.appendChild(renderedThumbnail);
32179
- }
32180
- return rowEl;
32181
- }
32182
-
32183
- /**
32184
- * Utility to create the list element
32185
- *
32186
- * @return {HTMLElement} The list element
32187
- */
32188
- createListElement() {
32189
- const newListEl = document.createElement('ol');
32190
- newListEl.className = 'bp-vs-list';
32191
- newListEl.style.height = `${this.totalItems * (this.itemHeight + this.margin) + this.margin}px`;
32192
- return newListEl;
32193
- }
32194
-
32195
- /**
32196
- * Scrolls the provided row index into view.
32197
- * @param {number} rowIndex - the index of the row in the overall list
32198
- * @return {void}
32199
- */
32200
- scrollIntoView(rowIndex) {
32201
- if (!this.scrollingEl || rowIndex < 0 || rowIndex >= this.totalItems) {
32202
- return;
32203
- }
32204
-
32205
- // See if the list item indexed by `rowIndex` is already present
32206
- const foundItem = this.getListItems().find(listItem => {
32207
- const {
32208
- bpVsRowIndex
32209
- } = listItem.dataset;
32210
- const parsedRowIndex = parseInt(bpVsRowIndex, 10);
32211
- return parsedRowIndex === rowIndex;
32212
- });
32213
- if (foundItem) {
32214
- // If it is already present and visible, do nothing, but if not visible
32215
- // then scroll it into view
32216
- if (!this.isVisible(foundItem)) {
32217
- foundItem.scrollIntoView({
32218
- block: 'nearest'
32219
- });
32220
- }
32221
- } else {
32222
- // If it is not present, then adjust the scrollTop so that the list item
32223
- // will get rendered.
32224
- const topPosition = (this.itemHeight + this.margin) * rowIndex;
32225
- this.scrollingEl.scrollTop = topPosition;
32226
- // Some browsers don't fire the scroll event when setting scrollTop
32227
- // (IE11 & Firefox) so we need to manually dispatch the event
32228
- // in order to trigger `onScrollHandler` to render the items
32229
- this.scrollingEl.dispatchEvent(new Event('scroll'));
32230
- }
32231
- }
32232
-
32233
- /**
32234
- * Checks to see whether the provided list item element is currently visible
32235
- * @param {HTMLElement} listItemEl - the list item elment
32236
- * @return {boolean} Returns true if the list item is visible, false otherwise
32237
- */
32238
- isVisible(listItemEl) {
32239
- if (!this.scrollingEl || !listItemEl) {
32240
- return false;
32241
- }
32242
- const {
32243
- scrollTop
32244
- } = this.scrollingEl;
32245
- const {
32246
- offsetTop
32247
- } = listItemEl;
32248
-
32249
- // Ensure that the offsetTop and entire height of the listItemEl are inside the visible window
32250
- return scrollTop <= offsetTop && offsetTop + this.itemHeight <= scrollTop + this.containerHeight;
32251
- }
32252
-
32253
- /**
32254
- * Gets the currently visible list items
32255
- * @return {Array<HTMLElement>} - the list of current visible list items
32256
- */
32257
- getVisibleItems() {
32258
- if (!this.listEl) {
32259
- return [];
32260
- }
32261
- return this.getListItems().filter(itemEl => this.isVisible(itemEl)).map(itemEl => itemEl && itemEl.children && itemEl.children[0]);
32262
- }
32263
-
32264
- /**
32265
- * Gets the list items of this.listEl as an array
32266
- * @return {Array<HTMLElement>} - the list items
32267
- */
32268
- getListItems() {
32269
- if (!this.listEl) {
32270
- return [];
32271
- }
32272
- return Array.prototype.slice.call(this.listEl.children);
32273
- }
32274
- }
32275
- /* harmony default export */ const lib_VirtualScroller = (VirtualScroller);
32276
- ;// ./src/lib/Thumbnail.js
32277
- 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; }
32278
- 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; }
32279
- 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; }
32280
- function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
32281
- 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); }
32282
-
32283
-
32284
- const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
32285
- const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
32286
- const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
32287
-
32288
- class Thumbnail {
32289
- /**
32290
- * [constructor]
32291
- *
32292
- * @param {PDFViewer} pdfViewer - the PDFJS viewer
32293
- */
32294
- constructor(pdfViewer, preloader) {
32295
- /** @property {PDfViewer} - The PDFJS viewer instance */
32296
- Thumbnail_defineProperty(this, "pdfViewer", void 0);
32297
- /** @property {Object} - Cache for the thumbnail image elements */
32298
- Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
32299
- Thumbnail_defineProperty(this, "preloader", void 0);
32300
- this.preloader = preloader;
32301
- this.createImageEl = this.createImageEl.bind(this);
32302
- this.createThumbnailImage = this.createThumbnailImage.bind(this);
32303
- this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
32304
- this.pdfViewer = pdfViewer;
32305
- this.thumbnailImageCache = new lib_BoundedCache();
32306
- }
32307
-
32308
- /**
32309
- * Destroys the thumbnails sidebar
32310
- *
32311
- * @return {void}
32312
- */
32313
- destroy() {
32314
- if (this.thumbnailImageCache) {
32315
- this.thumbnailImageCache.destroy();
32316
- this.thumbnailImageCache = null;
32317
- }
32318
- this.pdfViewer = null;
32319
- this.preloader = null;
32320
- }
32321
-
32322
- /**
32323
- * Initializes the Thumbnails Sidebar
32324
- *
32325
- * @return {Promise}
32326
- */
32327
- init() {
32328
- // Get the first page of the document, and use its dimensions
32329
- // to set the thumbnails size of the thumbnails sidebar
32330
-
32331
- if (this.preloader?.imageDimensions) {
32332
- const {
32333
- width,
32334
- height
32335
- } = this.preloader.imageDimensions;
32336
- this.scale = THUMBNAIL_TOTAL_WIDTH / width;
32337
- this.pageRatio = width / height;
32338
- this.thumbnailHeight = Math.ceil(height * this.scale);
32339
- return Promise.resolve(this.thumbnailHeight);
32340
- }
32341
- const pdfDocument = this.pdfViewer?.pdfDocument;
32342
- if (!pdfDocument) {
32343
- return Promise.resolve(null);
32344
- }
32345
- return pdfDocument.getPage(1).then(page => {
32346
- const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
32347
- const viewport = page.getViewport({
32348
- scale: 1,
32349
- rotation
32350
- });
32351
- if (!viewport) {
32352
- return Promise.resolve(null);
32353
- }
32354
- const {
32355
- width,
32356
- height
32357
- } = viewport;
32358
-
32359
- // If the dimensions of the page are invalid then don't proceed further
32360
- if (!(isFinite_default()(width) && width > 0 && isFinite_default()(height) && height > 0)) {
32361
- // eslint-disable-next-line
32362
- console.error('Page dimensions invalid when initializing the thumbnails sidebar');
32363
- return Promise.resolve(null);
32364
- }
32365
-
32366
- // Amount to scale down from full-size to thumbnail size
32367
- this.scale = THUMBNAIL_TOTAL_WIDTH / width;
32368
- // Width : Height ratio of the page
32369
- this.pageRatio = width / height;
32370
- const scaledViewport = page.getViewport({
32371
- scale: this.scale,
32372
- rotation
32373
- });
32374
- this.thumbnailHeight = Math.ceil(scaledViewport.height);
32375
- return Promise.resolve(this.thumbnailHeight);
32376
- });
32581
+ const listItems = Array.prototype.slice.call(listEl.children, start, end);
32582
+ listItems.forEach(listItem => listEl.removeChild(listItem));
32377
32583
  }
32378
32584
 
32379
32585
  /**
32380
- * Creates the image element
32381
- * @param {string} dataUrl - The image data URL for the thumbnail
32382
- * @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
32383
32590
  */
32384
- createImageEl(dataUrl, thumbOptions) {
32385
- const imageEl = thumbOptions && thumbOptions.createImgTag ? document.createElement('img') : document.createElement('div');
32386
- if (thumbOptions && thumbOptions.createImgTag) {
32387
- imageEl.src = `${dataUrl}`;
32388
- 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}`);
32389
32600
  }
32390
- imageEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE);
32391
- imageEl.style.backgroundImage = `url('${dataUrl}')`;
32392
-
32393
- // Add the height and width to the image to be the same as the thumbnail
32394
- // so that the css `background-image` rules will work
32395
- imageEl.style.width = `${THUMBNAIL_TOTAL_WIDTH}px`;
32396
- imageEl.style.height = `${this.thumbnailHeight}px`;
32397
- 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;
32398
32609
  }
32399
32610
 
32400
32611
  /**
32401
- * Make a thumbnail image element
32612
+ * Utility to create the list element
32402
32613
  *
32403
- * @param {number} itemIndex - the item index for the overall list (0 indexed)
32404
- * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
32614
+ * @return {HTMLElement} The list element
32405
32615
  */
32406
- createThumbnailImage(itemIndex, thumbOptions) {
32407
- const cacheEntry = this.getImageFromCache(itemIndex);
32408
- // If this thumbnail has already been cached, use it
32409
- if (cacheEntry && cacheEntry.image) {
32410
- return Promise.resolve(cacheEntry.image);
32411
- }
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
+ }
32412
32622
 
32413
- // If this thumbnail has already been requested, resolve with null
32414
- if (cacheEntry && cacheEntry.inProgress) {
32415
- 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;
32416
32631
  }
32417
32632
 
32418
- // Update the cache entry to be in progress
32419
- this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
32420
- inProgress: true
32421
- }));
32422
- return this.getThumbnailDataURL(itemIndex + 1, thumbOptions).then(dataUrl => {
32423
- return this.createImageEl(dataUrl, thumbOptions);
32424
- }).then(imageEl => {
32425
- // Cache this image element for future use
32426
- this.thumbnailImageCache.set(itemIndex, {
32427
- inProgress: false,
32428
- image: imageEl
32429
- });
32430
- return imageEl;
32431
- }).catch(() => {
32432
- this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, this.getImageFromCache(itemIndex)), {}, {
32433
- inProgress: false
32434
- }));
32435
- 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;
32436
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
+ }
32437
32659
  }
32438
32660
 
32439
32661
  /**
32440
- * Make a thumbnail image element
32441
- *
32442
- * @param {number} itemIndex - the item index for the overall list (0 indexed)
32443
- * @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
32444
32665
  */
32445
- getImageFromCache(itemIndex) {
32446
- 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;
32447
32679
  }
32448
32680
 
32449
32681
  /**
32450
- * Given a page number, generates the image data URL for the image of the page
32451
- * @param {number} pageNum - The page number of the document
32452
- * @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
32453
32684
  */
32454
- getThumbnailDataURL(pageNum, thumbOptions) {
32455
- if (this.preloader?.preloadedImages?.[pageNum]) {
32456
- return Promise.resolve(this.preloader.preloadedImages[pageNum]);
32457
- }
32458
- const pdfDocument = this.pdfViewer?.pdfDocument;
32459
- if (!pdfDocument) {
32460
- return Promise.reject(new Error('PDF document not ready'));
32685
+ getVisibleItems() {
32686
+ if (!this.listEl) {
32687
+ return [];
32461
32688
  }
32462
- const canvas = document.createElement('canvas');
32463
- const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
32464
- return pdfDocument.getPage(pageNum).then(page => {
32465
- const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
32466
- const viewport = page.getViewport({
32467
- scale: 1,
32468
- rotation
32469
- });
32470
- if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
32471
- return Promise.reject(new Error('Invalid page viewport'));
32472
- }
32473
- const {
32474
- width,
32475
- height
32476
- } = viewport;
32477
- // Get the current page w:h ratio in case it differs from the first page
32478
- const curPageRatio = width / height;
32689
+ return this.getListItems().filter(itemEl => this.isVisible(itemEl)).map(itemEl => itemEl && itemEl.children && itemEl.children[0]);
32690
+ }
32479
32691
 
32480
- // Handle the case where the current page's w:h ratio is less than the
32481
- // `pageRatio` which means that this page is probably more portrait than
32482
- // landscape
32483
- if (curPageRatio < this.pageRatio) {
32484
- // Set the canvas height to that of the thumbnail max height
32485
- canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
32486
- // Find the canvas width based on the current page ratio
32487
- canvas.width = canvas.height * curPageRatio;
32488
- } else {
32489
- // In case the current page ratio is same as the first page
32490
- // or in case it's larger (which means that it's wider), keep
32491
- // the width at the max thumbnail width
32492
- canvas.width = thumbnailImageWidth;
32493
- // Find the height based on the current page ratio
32494
- canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
32495
- }
32496
- // The amount for which to scale down the current page
32497
- const {
32498
- width: canvasWidth
32499
- } = canvas;
32500
- const scale = canvasWidth / width;
32501
- return page.render({
32502
- canvasContext: canvas.getContext('2d'),
32503
- viewport: page.getViewport({
32504
- scale,
32505
- rotation
32506
- })
32507
- }).promise;
32508
- }).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);
32509
32701
  }
32510
32702
  }
32511
- /* harmony default export */ const lib_Thumbnail = (Thumbnail);
32703
+ /* harmony default export */ const lib_VirtualScroller = (VirtualScroller);
32512
32704
  ;// ./src/lib/ThumbnailsSidebar.js
32513
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; }
32514
32706
  function ThumbnailsSidebar_toPropertyKey(t) { var i = ThumbnailsSidebar_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -32977,7 +33169,6 @@ function DocBaseViewer_toPrimitive(t, r) { if ("object" != typeof t || !t) retur
32977
33169
 
32978
33170
 
32979
33171
 
32980
-
32981
33172
 
32982
33173
 
32983
33174
  const DOC_FIRST_PAGES_ENABLED = 'docFirstPages.enabled';
@@ -33012,8 +33203,7 @@ const RANGE_CHUNK_SIZE_US = 1048576; // 1MB
33012
33203
  const RANGE_REQUEST_MINIMUM_SIZE = 26214400; // 25MB
33013
33204
  const SAFARI_PRINT_TIMEOUT_MS = 1000; // Wait 1s before trying to print
33014
33205
  const SCROLL_EVENT_THROTTLE_INTERVAL = 200;
33015
- const GALLERY_MAX_PAGES = 200; // Hide gallery toggle for files above this page count, will increase in V2
33016
- const THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // 301ms
33206
+ const DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // 301ms
33017
33207
  const THUMBNAILS_SIDEBAR_TOGGLED_MAP_KEY = 'doc-thumbnails-toggled-map';
33018
33208
  const MAX_OPERATIONS = 320000; // Block PDFs with more than 320,000 drawing operations
33019
33209
  const MAX_OPERATION_PAGES = 5; // Check only the first 5 pages
@@ -33042,18 +33232,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33042
33232
  //--------------------------------------------------------------------------
33043
33233
  /** @property {Thumbnail} - Thumbnail reference */
33044
33234
  DocBaseViewer_defineProperty(this, "advancedInsightsThumbs", void 0);
33045
- /** @property {number} - Page focused in gallery via Tab */
33046
- DocBaseViewer_defineProperty(this, "galleryFocusedPage", null);
33047
- /** @property {number} - Pending setTimeout ID for delayed gallery mount */
33048
- DocBaseViewer_defineProperty(this, "galleryMountTimeoutId", null);
33049
- /** @property {number} - Pending setTimeout ID for delayed sidebar setCurrentPage after gallery exit */
33050
- DocBaseViewer_defineProperty(this, "gallerySidebarTimeoutId", null);
33051
- /** @property {Thumbnail} - Dedicated gallery thumbnail instance (persists between opens) */
33052
- DocBaseViewer_defineProperty(this, "galleryThumbnail", void 0);
33053
- /** @property {boolean} - Whether gallery mode is active */
33054
- DocBaseViewer_defineProperty(this, "isGalleryOpen", false);
33055
- /** @property {boolean} - Whether sidebar was open before entering gallery */
33056
- DocBaseViewer_defineProperty(this, "sidebarWasOpen", false);
33235
+ /** @property {GalleryController} - Owns gallery-view state, lifecycle, and toolbar gating */
33236
+ DocBaseViewer_defineProperty(this, "galleryController", void 0);
33057
33237
  /** @property {PageTracker} - PageTracker instance */
33058
33238
  DocBaseViewer_defineProperty(this, "pageTracker", void 0);
33059
33239
  DocBaseViewer_defineProperty(this, "doc", void 0);
@@ -33074,7 +33254,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33074
33254
  this.handleAnnotationCreateEvent = this.handleAnnotationCreateEvent.bind(this);
33075
33255
  this.handleAnnotationCreatorChangeEvent = this.handleAnnotationCreatorChangeEvent.bind(this);
33076
33256
  this.handleDocElKeydown = this.handleDocElKeydown.bind(this);
33077
- this.handleGalleryNavigate = this.handleGalleryNavigate.bind(this);
33078
33257
  this.handlePageSubmit = this.handlePageSubmit.bind(this);
33079
33258
  this.onThumbnailSelectHandler = this.onThumbnailSelectHandler.bind(this);
33080
33259
  this.pagechangingHandler = this.pagechangingHandler.bind(this);
@@ -33089,7 +33268,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33089
33268
  this.setPage = this.setPage.bind(this);
33090
33269
  this.throttledScrollHandler = this.getScrollHandler().bind(this);
33091
33270
  this.toggleFindBar = this.toggleFindBar.bind(this);
33092
- this.toggleGallery = this.toggleGallery.bind(this);
33093
33271
  this.toggleThumbnails = this.toggleThumbnails.bind(this);
33094
33272
  this.updateExperiences = this.updateExperiences.bind(this);
33095
33273
  this.updateDiscoverabilityResinTag = this.updateDiscoverabilityResinTag.bind(this);
@@ -33144,6 +33322,16 @@ class DocBaseViewer extends viewers_BaseViewer {
33144
33322
  if (isFeatureEnabled(this.options.features, 'advancedContentInsights.enabled')) {
33145
33323
  this.pageTracker = new lib_PageTracker(advancedContentInsightsConfig, this.options.file);
33146
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
+ });
33147
33335
  }
33148
33336
 
33149
33337
  /**
@@ -33169,26 +33357,9 @@ class DocBaseViewer extends viewers_BaseViewer {
33169
33357
  this.findBar.destroy();
33170
33358
  }
33171
33359
 
33172
- // Cancel any pending gallery setTimeouts so they don't fire after teardown
33173
- if (this.galleryMountTimeoutId !== null) {
33174
- clearTimeout(this.galleryMountTimeoutId);
33175
- this.galleryMountTimeoutId = null;
33176
- }
33177
- if (this.gallerySidebarTimeoutId !== null) {
33178
- clearTimeout(this.gallerySidebarTimeoutId);
33179
- this.gallerySidebarTimeoutId = null;
33180
- }
33181
- if (this.galleryRoot) {
33182
- this.galleryRoot.unmount();
33183
- this.galleryRoot = null;
33184
- }
33185
- if (this.galleryEl) {
33186
- this.galleryEl.remove();
33187
- this.galleryEl = null;
33188
- }
33189
- if (this.galleryThumbnail) {
33190
- this.galleryThumbnail.destroy();
33191
- this.galleryThumbnail = null;
33360
+ // Must run before pdfViewer teardown galleryController holds Thumbnail render promises against pdfViewer
33361
+ if (this.galleryController) {
33362
+ this.galleryController.destroy();
33192
33363
  }
33193
33364
 
33194
33365
  // Clean up PDF network requests
@@ -33796,9 +33967,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33796
33967
  if (this.thumbnailsSidebar) {
33797
33968
  this.thumbnailsSidebar.refresh();
33798
33969
  }
33799
- if (this.galleryThumbnail) {
33800
- this.galleryThumbnail.destroy();
33801
- this.galleryThumbnail = null;
33970
+ if (this.galleryController) {
33971
+ this.galleryController.handleRotate();
33802
33972
  }
33803
33973
  this.renderUI();
33804
33974
 
@@ -34364,7 +34534,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34364
34534
  const canDownload = checkPermission(this.options.file, PERMISSION_DOWNLOAD);
34365
34535
  const isAnnotationsMode = this.currentAnnotatorViewMode === ANNOTATOR_VIEW_MODES.ANNOTATIONS;
34366
34536
  const canRotate = this.featureEnabled('rotate.enabled');
34367
- 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);
34368
34538
  this.controls.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(DocControls, {
34369
34539
  annotationColor: this.annotationModule.getColor(),
34370
34540
  annotationMode: this.annotationControlsFSM.getMode(),
@@ -34372,7 +34542,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34372
34542
  hasDrawing: canAnnotate && showAnnotationsDrawingCreate && isAnnotationsMode,
34373
34543
  hasHighlight: canAnnotate && canDownload && isAnnotationsMode,
34374
34544
  hasRegion: canAnnotate && isAnnotationsMode,
34375
- isGalleryOpen: this.isGalleryOpen,
34545
+ isGalleryOpen: this.galleryController.isOpen,
34376
34546
  isThumbnailsOpen: this.thumbnailsSidebar && this.thumbnailsSidebar.isOpen,
34377
34547
  maxScale: DocBaseViewer_MAX_SCALE,
34378
34548
  minScale: DocBaseViewer_MIN_SCALE,
@@ -34381,7 +34551,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34381
34551
  onAnnotationModeEscape: this.handleAnnotationControlsEscape,
34382
34552
  onFindBarToggle: !this.isFindDisabled() ? this.toggleFindBar : undefined,
34383
34553
  onFullscreenToggle: this.toggleFullscreen,
34384
- onGalleryToggle: canGallery ? this.toggleGallery : undefined,
34554
+ onGalleryToggle: canGallery ? this.galleryController.toggle : undefined,
34385
34555
  onPageChange: this.setPage,
34386
34556
  onPageSubmit: this.handlePageSubmit,
34387
34557
  onRotateLeft: canRotate ? this.rotateLeft : undefined,
@@ -34615,8 +34785,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34615
34785
  */
34616
34786
  handleDocElKeydown(event) {
34617
34787
  const key = decodeKeydown(event);
34618
- if (key === 'Escape' && this.isGalleryOpen) {
34619
- this.toggleGallery();
34788
+ if (key === 'Escape' && this.galleryController.handleEscape()) {
34620
34789
  return;
34621
34790
  }
34622
34791
  if (event.altKey && key.includes('Arrow')) {
@@ -34867,80 +35036,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34867
35036
  // Remove the active classes to allow the container to be transitioned properly
34868
35037
  this.rootEl.classList.remove(CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE);
34869
35038
  this.rootEl.classList.remove(CLASS_BOX_PREVIEW_THUMBNAILS_OPEN_ACTIVE);
34870
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34871
- }
34872
- mountGalleryGrid() {
34873
- if (this.galleryRoot) {
34874
- return;
34875
- }
34876
- if (!this.galleryThumbnail) {
34877
- this.galleryThumbnail = new lib_Thumbnail(this.pdfViewer, this.preloader);
34878
- }
34879
- this.galleryEl = document.createElement('div');
34880
- this.containerEl.appendChild(this.galleryEl);
34881
- this.galleryRoot = __WEBPACK_EXTERNAL_MODULE_react_dom_client_4cb20cd7_createRoot__(this.galleryEl);
34882
- this.galleryFocusedPage = this.pdfViewer.currentPageNumber;
34883
- this.galleryRoot.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryGrid, {
34884
- currentPage: this.pdfViewer.currentPageNumber,
34885
- onClose: this.toggleGallery,
34886
- onFocusChange: pageNum => {
34887
- this.galleryFocusedPage = pageNum;
34888
- },
34889
- onPageNavigate: this.handleGalleryNavigate,
34890
- pageCount: this.pdfViewer.pagesCount,
34891
- thumbnail: this.galleryThumbnail
34892
- }));
34893
- }
34894
- toggleGallery() {
34895
- this.isGalleryOpen = !this.isGalleryOpen;
34896
- if (this.isGalleryOpen) {
34897
- if (this.gallerySidebarTimeoutId !== null) {
34898
- clearTimeout(this.gallerySidebarTimeoutId);
34899
- this.gallerySidebarTimeoutId = null;
34900
- }
34901
- this.sidebarWasOpen = !!(this.thumbnailsSidebar && this.thumbnailsSidebar.isOpen);
34902
- if (this.sidebarWasOpen) {
34903
- this.toggleThumbnails();
34904
- this.galleryMountTimeoutId = setTimeout(() => {
34905
- this.galleryMountTimeoutId = null;
34906
- this.mountGalleryGrid();
34907
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME / 2);
34908
- } else {
34909
- this.mountGalleryGrid();
34910
- }
34911
- } else {
34912
- if (this.galleryMountTimeoutId !== null) {
34913
- clearTimeout(this.galleryMountTimeoutId);
34914
- this.galleryMountTimeoutId = null;
34915
- }
34916
- const navigateToPage = this.galleryFocusedPage && this.galleryFocusedPage !== this.pdfViewer.currentPageNumber ? this.galleryFocusedPage : null;
34917
- if (this.galleryRoot) {
34918
- this.galleryRoot.unmount();
34919
- this.galleryRoot = null;
34920
- }
34921
- if (this.galleryEl) {
34922
- this.galleryEl.remove();
34923
- this.galleryEl = null;
34924
- }
34925
- this.galleryFocusedPage = null;
34926
- if (this.sidebarWasOpen && this.thumbnailsSidebar && !this.thumbnailsSidebar.isOpen) {
34927
- this.toggleThumbnails();
34928
- }
34929
- if (navigateToPage) {
34930
- this.setPage(navigateToPage);
34931
- if (this.sidebarWasOpen && this.thumbnailsSidebar) {
34932
- this.gallerySidebarTimeoutId = setTimeout(() => {
34933
- this.gallerySidebarTimeoutId = null;
34934
- this.thumbnailsSidebar.setCurrentPage(navigateToPage);
34935
- }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34936
- }
34937
- }
34938
- }
34939
- this.renderUI();
34940
- }
34941
- handleGalleryNavigate(pageNum) {
34942
- this.galleryFocusedPage = pageNum;
34943
- this.toggleGallery();
35039
+ }, DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34944
35040
  }
34945
35041
 
34946
35042
  /**