box-content-preview 3.52.0 → 3.54.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.54.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.54.0";
11069
11069
  /* eslint-enable no-undef */
11070
11070
 
11071
11071
  class Logger {
@@ -27650,6 +27650,57 @@ function TimestampControl(_ref) {
27650
27650
  }));
27651
27651
  })));
27652
27652
  }
27653
+ ;// ./src/lib/viewers/controls/media/utils.ts
27654
+ const utils_round = value => {
27655
+ return +value.toFixed(4);
27656
+ };
27657
+ const utils_percent = (value1, value2) => {
27658
+ return utils_round(value1 / value2 * 100);
27659
+ };
27660
+ ;// ./src/lib/viewers/controls/media/buildClusters.ts
27661
+
27662
+
27663
+ /** Max pixel distance between adjacent markers (sorted by time) for them to be grouped into a single cluster. */
27664
+ const CLUSTER_THRESHOLD_PX = 2;
27665
+
27666
+ /** Converts a group of markers into a ClusterData object with computed positions and metadata. */
27667
+ function finalizeCluster(group, durationValue) {
27668
+ const leftPercent = utils_percent(group[0].time, durationValue);
27669
+ const rightPercent = utils_percent(group[group.length - 1].time, durationValue);
27670
+ const isSinglePoint = leftPercent === rightPercent;
27671
+ return {
27672
+ id: group.map(m => m.id).join('|'),
27673
+ isSinglePoint,
27674
+ leftPercent,
27675
+ markers: group,
27676
+ rightPercent
27677
+ };
27678
+ }
27679
+
27680
+ /**
27681
+ * Groups comment markers into clusters based on their pixel proximity on the scrubber track.
27682
+ * Markers are sorted by time, then chained: each marker that is within CLUSTER_THRESHOLD_PX
27683
+ * of its neighbor joins the same cluster. This means distant markers can end up in one cluster
27684
+ * if intermediate markers bridge the gap.
27685
+ */
27686
+ function buildClusters(markers, durationValue, trackWidth) {
27687
+ if (durationValue <= 0 || markers.length === 0 || trackWidth <= 0) return [];
27688
+ const sorted = [...markers].sort((a, b) => a.time - b.time);
27689
+ const clusters = [];
27690
+ let currentGroup = [sorted[0]];
27691
+ for (let i = 1; i < sorted.length; i += 1) {
27692
+ const prevPx = sorted[i - 1].time / durationValue * trackWidth;
27693
+ const currPx = sorted[i].time / durationValue * trackWidth;
27694
+ if (currPx - prevPx <= CLUSTER_THRESHOLD_PX) {
27695
+ currentGroup.push(sorted[i]);
27696
+ } else {
27697
+ clusters.push(finalizeCluster(currentGroup, durationValue));
27698
+ currentGroup = [sorted[i]];
27699
+ }
27700
+ }
27701
+ clusters.push(finalizeCluster(currentGroup, durationValue));
27702
+ return clusters;
27703
+ }
27653
27704
  ;// ./src/lib/viewers/controls/media/FilmstripV2.scss
27654
27705
  // extracted by mini-css-extract-plugin
27655
27706
 
@@ -27805,6 +27856,118 @@ function MarkerAvatar(_ref) {
27805
27856
  } : undefined
27806
27857
  }, avatar);
27807
27858
  }
27859
+ ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.scss
27860
+ // extracted by mini-css-extract-plugin
27861
+
27862
+ ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.tsx
27863
+
27864
+
27865
+
27866
+ const MAX_VISIBLE_AVATARS = 4;
27867
+ function MarkerAvatarStack(_ref) {
27868
+ let {
27869
+ markers,
27870
+ onMarkerClick
27871
+ } = _ref;
27872
+ const hasOverflow = markers.length > MAX_VISIBLE_AVATARS;
27873
+ const visibleMarkers = hasOverflow ? markers.slice(0, MAX_VISIBLE_AVATARS - 1) : markers;
27874
+ return /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
27875
+ className: "bp-MarkerAvatarStack"
27876
+ }, visibleMarkers.map(marker => /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
27877
+ key: marker.id,
27878
+ className: "bp-MarkerAvatarStack-item",
27879
+ onClick: e => {
27880
+ e.stopPropagation();
27881
+ onMarkerClick?.(marker);
27882
+ },
27883
+ type: "button"
27884
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerAvatar, {
27885
+ avatarUrl: marker.avatarUrl,
27886
+ colorIndex: marker.colorIndex,
27887
+ initial: marker.initial
27888
+ }))), hasOverflow && /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
27889
+ className: "bp-MarkerAvatarStack-item bp-MarkerAvatarStack-overflow",
27890
+ onClick: e => {
27891
+ e.stopPropagation();
27892
+ onMarkerClick?.(markers[MAX_VISIBLE_AVATARS - 1]);
27893
+ },
27894
+ type: "button"
27895
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
27896
+ className: "bp-MarkerAvatar bp-MarkerAvatarStack-overflowBadge"
27897
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
27898
+ className: "bp-MarkerAvatar-initial"
27899
+ }, "+", markers.length - (MAX_VISIBLE_AVATARS - 1)))));
27900
+ }
27901
+ ;// ./src/lib/viewers/controls/media/MarkerCluster.scss
27902
+ // extracted by mini-css-extract-plugin
27903
+
27904
+ ;// ./src/lib/viewers/controls/media/MarkerCluster.tsx
27905
+
27906
+
27907
+
27908
+ function MarkerCluster(_ref) {
27909
+ let {
27910
+ cluster,
27911
+ onMarkerClick
27912
+ } = _ref;
27913
+ const {
27914
+ markers,
27915
+ leftPercent,
27916
+ rightPercent
27917
+ } = cluster;
27918
+ const style = {
27919
+ left: `${leftPercent}%`,
27920
+ width: `calc(${rightPercent - leftPercent}% + 4px)`
27921
+ };
27922
+ return /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
27923
+ className: "bp-MarkerCluster",
27924
+ "data-testid": "bp-marker-cluster",
27925
+ style: style
27926
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
27927
+ "aria-label": "Comment marker",
27928
+ className: "bp-MarkerCluster-tick",
27929
+ onClick: e => {
27930
+ e.stopPropagation();
27931
+ onMarkerClick?.(markers[0]);
27932
+ },
27933
+ type: "button"
27934
+ }), /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerAvatarStack, {
27935
+ markers: markers,
27936
+ onMarkerClick: onMarkerClick
27937
+ }));
27938
+ }
27939
+ ;// ./src/lib/viewers/controls/media/MarkerTick.tsx
27940
+
27941
+
27942
+
27943
+ function MarkerTick(_ref) {
27944
+ let {
27945
+ markers,
27946
+ onMarkerClick,
27947
+ position
27948
+ } = _ref;
27949
+ const isGroup = markers.length > 1;
27950
+ return /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
27951
+ "aria-label": "Comment marker",
27952
+ className: `bp-TimeControlsV2-marker${isGroup ? ' bp-TimeControlsV2-marker--group' : ''}`,
27953
+ "data-testid": "bp-time-controls-marker",
27954
+ onClick: e => {
27955
+ e.stopPropagation();
27956
+ onMarkerClick?.(markers[0]);
27957
+ },
27958
+ style: {
27959
+ left: `${position}%`
27960
+ },
27961
+ type: "button"
27962
+ }, isGroup ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerAvatarStack, {
27963
+ markers: markers,
27964
+ onMarkerClick: onMarkerClick
27965
+ }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerAvatar, {
27966
+ avatarUrl: markers[0].avatarUrl,
27967
+ colorIndex: markers[0].colorIndex,
27968
+ initial: markers[0].initial
27969
+ }));
27970
+ }
27808
27971
  ;// ./src/lib/viewers/controls/media/TimeControlsV2.scss
27809
27972
  // extracted by mini-css-extract-plugin
27810
27973
 
@@ -27817,12 +27980,9 @@ function MarkerAvatar(_ref) {
27817
27980
 
27818
27981
 
27819
27982
 
27820
- const TimeControlsV2_round = value => {
27821
- return +value.toFixed(4);
27822
- };
27823
- const TimeControlsV2_percent = (value1, value2) => {
27824
- return TimeControlsV2_round(value1 / value2 * 100);
27825
- };
27983
+
27984
+
27985
+
27826
27986
  function TimeControlsV2(_ref) {
27827
27987
  let {
27828
27988
  aspectRatio,
@@ -27832,7 +27992,6 @@ function TimeControlsV2(_ref) {
27832
27992
  filmstripInterval,
27833
27993
  filmstripUrl,
27834
27994
  fps,
27835
- mediaEl,
27836
27995
  onCommentMarkerClick,
27837
27996
  onTimeChange
27838
27997
  } = _ref;
@@ -27840,26 +27999,45 @@ function TimeControlsV2(_ref) {
27840
27999
  const [hoverPosition, setHoverPosition] = __WEBPACK_EXTERNAL_MODULE_react_default__.useState(0);
27841
28000
  const [hoverPositionMax, setHoverPositionMax] = __WEBPACK_EXTERNAL_MODULE_react_default__.useState(0);
27842
28001
  const [hoverTime, setHoverTime] = __WEBPACK_EXTERNAL_MODULE_react_default__.useState(0);
28002
+ const [trackWidth, setTrackWidth] = __WEBPACK_EXTERNAL_MODULE_react_default__.useState(0);
28003
+ const scrubberRef = __WEBPACK_EXTERNAL_MODULE_react_default__.useRef(null);
27843
28004
  const currentValue = isFinite_default()(currentTime) ? currentTime : 0;
27844
28005
  const durationValue = isFinite_default()(durationTime) ? durationTime : 0;
27845
- const currentPercentage = TimeControlsV2_percent(currentValue, durationValue);
27846
- const markerTimesKey = commentMarkers.map(m => m.time).join('|');
28006
+ const currentPercentage = utils_percent(currentValue, durationValue);
28007
+ __WEBPACK_EXTERNAL_MODULE_react_default__.useLayoutEffect(() => {
28008
+ const el = scrubberRef.current;
28009
+ if (!el) return undefined;
28010
+ setTrackWidth(el.clientWidth);
28011
+ const observer = new ResizeObserver(entries => {
28012
+ entries.forEach(entry => {
28013
+ setTrackWidth(entry.contentRect.width);
28014
+ });
28015
+ });
28016
+ observer.observe(el);
28017
+ return () => observer.disconnect();
28018
+ }, []);
28019
+ const clusters = __WEBPACK_EXTERNAL_MODULE_react_default__.useMemo(() => buildClusters(commentMarkers, durationValue, trackWidth), [commentMarkers, durationValue, trackWidth]);
27847
28020
  const trackMask = __WEBPACK_EXTERNAL_MODULE_react_default__.useMemo(() => {
27848
- if (durationValue <= 0 || commentMarkers.length === 0) return undefined;
28021
+ if (durationValue <= 0 || clusters.length === 0) return undefined;
27849
28022
  const HALF_GAP = 2;
27850
28023
  const stops = [];
27851
- const sorted = commentMarkers.map(m => TimeControlsV2_percent(m.time, durationValue)).sort((a, b) => a - b);
27852
28024
  stops.push('black 0%');
27853
- sorted.forEach(pos => {
27854
- stops.push(`black calc(${pos}% - ${HALF_GAP}px)`);
27855
- stops.push(`transparent calc(${pos}% - ${HALF_GAP}px)`);
27856
- stops.push(`transparent calc(${pos}% + ${HALF_GAP}px)`);
27857
- stops.push(`black calc(${pos}% + ${HALF_GAP}px)`);
28025
+ clusters.forEach(_ref2 => {
28026
+ let {
28027
+ leftPercent,
28028
+ rightPercent
28029
+ } = _ref2;
28030
+ const isRange = leftPercent !== rightPercent;
28031
+ const leftPad = isRange ? HALF_GAP + 1 : HALF_GAP;
28032
+ const rightPad = isRange ? HALF_GAP + 1 : HALF_GAP;
28033
+ stops.push(`black calc(${leftPercent}% - ${leftPad}px)`);
28034
+ stops.push(`transparent calc(${leftPercent}% - ${leftPad}px)`);
28035
+ stops.push(`transparent calc(${rightPercent}% + ${rightPad}px)`);
28036
+ stops.push(`black calc(${rightPercent}% + ${rightPad}px)`);
27858
28037
  });
27859
28038
  stops.push('black 100%');
27860
28039
  return `linear-gradient(to right, ${stops.join(', ')})`;
27861
- // eslint-disable-next-line react-hooks/exhaustive-deps
27862
- }, [markerTimesKey, durationValue]);
28040
+ }, [durationValue, clusters]);
27863
28041
  const handleMouseMove = (newTime, newPosition, width) => {
27864
28042
  setHoverPosition(newPosition);
27865
28043
  setHoverPositionMax(width);
@@ -27878,6 +28056,7 @@ function TimeControlsV2(_ref) {
27878
28056
  positionMax: hoverPositionMax,
27879
28057
  time: hoverTime
27880
28058
  }), /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
28059
+ ref: scrubberRef,
27881
28060
  className: "bp-TimeControlsV2-scrubber",
27882
28061
  style: trackMask ? {
27883
28062
  '--bp-track-mask': trackMask
@@ -27897,24 +28076,16 @@ function TimeControlsV2(_ref) {
27897
28076
  title: "Media Slider",
27898
28077
  track: `linear-gradient(to right, ${__WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_white__} calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% + 2.5px), ${__WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlGray65__} calc(${currentPercentage}% + 2.5px), ${__WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlGray65__} 100%)`,
27899
28078
  value: currentValue
27900
- }), durationValue > 0 && commentMarkers.map(marker => /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
27901
- key: marker.id,
27902
- "aria-label": "Comment marker",
27903
- className: "bp-TimeControlsV2-marker",
27904
- "data-testid": "bp-time-controls-marker",
27905
- onClick: e => {
27906
- e.stopPropagation();
27907
- onCommentMarkerClick?.(marker);
27908
- },
27909
- style: {
27910
- left: `${TimeControlsV2_percent(marker.time, durationValue)}%`
27911
- },
27912
- type: "button"
27913
- }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerAvatar, {
27914
- avatarUrl: marker.avatarUrl,
27915
- colorIndex: marker.colorIndex,
27916
- initial: marker.initial
27917
- })))));
28079
+ }), durationValue > 0 && clusters.map(cluster => cluster.isSinglePoint ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerTick, {
28080
+ key: cluster.id,
28081
+ markers: cluster.markers,
28082
+ onMarkerClick: onCommentMarkerClick,
28083
+ position: cluster.leftPercent
28084
+ }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(MarkerCluster, {
28085
+ key: cluster.id,
28086
+ cluster: cluster,
28087
+ onMarkerClick: onCommentMarkerClick
28088
+ }))));
27918
28089
  }
27919
28090
  ;// ./src/lib/viewers/controls/media/VideoFullscreenButton.scss
27920
28091
  // extracted by mini-css-extract-plugin
@@ -28068,7 +28239,6 @@ function VideoControlsV2(_ref) {
28068
28239
  filmstripInterval: filmstripInterval,
28069
28240
  filmstripUrl: filmstripUrl,
28070
28241
  fps: fps,
28071
- mediaEl: mediaEl,
28072
28242
  onCommentMarkerClick: onCommentMarkerClick,
28073
28243
  onTimeChange: onTimeChange
28074
28244
  }), /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
@@ -30951,116 +31121,557 @@ class DocFindBar extends (events_default()) {
30951
31121
  }
30952
31122
  }
30953
31123
  /* harmony default export */ const doc_DocFindBar = (DocFindBar);
30954
- ;// ./src/lib/viewers/gallery/GalleryGrid.scss
30955
- // extracted by mini-css-extract-plugin
30956
-
30957
- ;// ./src/lib/viewers/gallery/GalleryGrid.tsx
30958
- 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; }
30959
- 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; }
30960
- 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; }
30961
- function GalleryGrid_toPropertyKey(t) { var i = GalleryGrid_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
30962
- 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); }
31124
+ ;// ./src/lib/Cache.js
30963
31125
 
31126
+ class Cache {
31127
+ //--------------------------------------------------------------------------
31128
+ // Public
31129
+ //--------------------------------------------------------------------------
30964
31130
 
31131
+ /**
31132
+ * [constructor]
31133
+ *
31134
+ * @return {Cache} Cache instance
31135
+ */
31136
+ constructor() {
31137
+ this.cache = {};
31138
+ }
30965
31139
 
30966
- const GALLERY_THUMB_MAX_WIDTH = 440;
30967
- const INITIAL_LOAD_BUFFER = 40;
30968
- const CONCURRENT_LOADS = 4;
30969
- const SCROLL_THROTTLE_MS = 200;
30970
- function GalleryGrid(_ref) {
30971
- let {
30972
- pageCount,
30973
- currentPage,
30974
- onClose,
30975
- onFocusChange,
30976
- onPageNavigate,
30977
- thumbnail
30978
- } = _ref;
30979
- const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
30980
- const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
30981
- const gridRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
30982
- const queueRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__([]);
30983
- const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
30984
- const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
30985
- const initialLoadDoneRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
30986
- const initialLoadCountRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(0);
30987
- function processQueue() {
30988
- if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
30989
- isProcessingRef.current = false;
30990
- return;
31140
+ /**
31141
+ * Caches a simple object in memory and in localStorage if specified.
31142
+ * Note that objects cached in localStorage will be stringified.
31143
+ *
31144
+ * @public
31145
+ * @param {string} key - The cache key
31146
+ * @param {*} value - The cache value
31147
+ * @param {boolean} useLocalStorage - Whether or not to use localStorage
31148
+ * @return {void}
31149
+ */
31150
+ set(key, value, useLocalStorage) {
31151
+ this.cache[key] = value;
31152
+ if (useLocalStorage && this.isLocalStorageAvailable()) {
31153
+ localStorage.setItem(this.generateKey(key), JSON.stringify(value));
30991
31154
  }
30992
- const batchSize = initialLoadDoneRef.current ? CONCURRENT_LOADS : 1;
30993
- const batch = queueRef.current.slice(0, batchSize);
30994
- queueRef.current = queueRef.current.slice(batchSize);
30995
- requestAnimationFrame(() => {
30996
- if (!isMountedRef.current || !thumbnail) {
30997
- isProcessingRef.current = false;
30998
- return;
30999
- }
31000
- let completed = 0;
31001
- const onComplete = () => {
31002
- completed += 1;
31003
- if (completed < batch.length) return;
31004
- if (!isMountedRef.current) {
31005
- isProcessingRef.current = false;
31006
- return;
31007
- }
31008
- if (!initialLoadDoneRef.current) {
31009
- initialLoadCountRef.current += batch.length;
31010
- if (initialLoadCountRef.current >= INITIAL_LOAD_BUFFER) {
31011
- initialLoadDoneRef.current = true;
31012
- isProcessingRef.current = false;
31013
- return;
31014
- }
31015
- }
31016
- processQueue();
31017
- };
31018
- batch.forEach(pageNum => {
31019
- thumbnail.createThumbnailImage(pageNum - 1, {
31020
- createImgTag: true,
31021
- thumbMaxWidth: GALLERY_THUMB_MAX_WIDTH
31022
- }).then(imageEl => {
31023
- if (isMountedRef.current && imageEl && imageEl.src) {
31024
- setLoadedImages(prev => GalleryGrid_objectSpread(GalleryGrid_objectSpread({}, prev), {}, {
31025
- [pageNum]: imageEl.src
31026
- }));
31027
- }
31028
- onComplete();
31029
- }).catch(() => {
31030
- onComplete();
31031
- });
31032
- });
31033
- });
31034
31155
  }
31035
- function startProcessing() {
31036
- if (!isProcessingRef.current && queueRef.current.length > 0) {
31037
- isProcessingRef.current = true;
31038
- processQueue();
31156
+
31157
+ /**
31158
+ * Deletes object from in-memory cache and localStorage.
31159
+ *
31160
+ * @public
31161
+ * @param {string} key - The cache key
31162
+ * @return {void}
31163
+ */
31164
+ unset(key) {
31165
+ if (this.isLocalStorageAvailable()) {
31166
+ localStorage.removeItem(this.generateKey(key));
31039
31167
  }
31168
+ delete this.cache[key];
31040
31169
  }
31041
- function getUnloadedNearViewport() {
31042
- const grid = gridRef.current;
31043
- if (!grid) return [];
31044
- const {
31045
- scrollTop,
31046
- clientHeight
31047
- } = grid;
31048
- const bufferZone = clientHeight * 3;
31049
- const viewportTop = scrollTop - bufferZone;
31050
- const viewportBottom = scrollTop + clientHeight + bufferZone;
31051
- const nearbyUnloaded = [];
31052
- const tiles = grid.querySelectorAll('[data-page]');
31053
- tiles.forEach(tile => {
31054
- const el = tile;
31055
- if (!el.dataset.page) return;
31056
- const pageNum = parseInt(el.dataset.page, 10);
31057
- const tileTop = el.offsetTop;
31058
- const tileBottom = tileTop + el.offsetHeight;
31059
- if (tileBottom > viewportTop && tileTop < viewportBottom && !el.querySelector('img')) {
31060
- nearbyUnloaded.push(pageNum);
31061
- }
31062
- });
31063
- return nearbyUnloaded;
31170
+
31171
+ /**
31172
+ * Checks if cache has provided key.
31173
+ *
31174
+ * @public
31175
+ * @param {string} key - The cache key
31176
+ * @return {boolean} Whether the cache has key
31177
+ */
31178
+ has(key) {
31179
+ return this.inCache(key) || this.inLocalStorage(key);
31180
+ }
31181
+
31182
+ /**
31183
+ * Fetches a cached object from in-memory cache if available. Otherwise
31184
+ * tries to fetch from localStorage. If fetched from localStorage, object
31185
+ * will be a JSON parsed object.
31186
+ *
31187
+ * @public
31188
+ * @param {string} key - Key of cached object
31189
+ * @return {Object} Cached object
31190
+ */
31191
+ get(key) {
31192
+ if (this.inCache(key)) {
31193
+ return this.cache[key];
31194
+ }
31195
+
31196
+ // If localStorage is available, try to fetch from there and set it
31197
+ // in in-memory cache if found
31198
+ if (this.inLocalStorage(key)) {
31199
+ let value = localStorage.getItem(this.generateKey(key));
31200
+ if (value) {
31201
+ value = JSON.parse(value);
31202
+ this.cache[key] = value;
31203
+ return value;
31204
+ }
31205
+ }
31206
+ return undefined;
31207
+ }
31208
+
31209
+ //--------------------------------------------------------------------------
31210
+ // Private
31211
+ //--------------------------------------------------------------------------
31212
+
31213
+ /**
31214
+ * Checks if memory cache has provided key.
31215
+ *
31216
+ * @private
31217
+ * @param {string} key - The cache key
31218
+ * @return {boolean} Whether the cache has key
31219
+ */
31220
+ inCache(key) {
31221
+ return {}.hasOwnProperty.call(this.cache, key);
31222
+ }
31223
+
31224
+ /**
31225
+ * Checks if memory cache has provided key.
31226
+ *
31227
+ * @private
31228
+ * @param {string} key - The cache key
31229
+ * @return {boolean} Whether the cache has key
31230
+ */
31231
+ inLocalStorage(key) {
31232
+ if (!this.isLocalStorageAvailable()) {
31233
+ return false;
31234
+ }
31235
+ return !!localStorage.getItem(this.generateKey(key));
31236
+ }
31237
+
31238
+ /**
31239
+ * Checks whether localStorage is available.
31240
+ *
31241
+ * @NOTE(tjin): This check is cached to not have to write/read from disk
31242
+ * every time this check is needed, but this will not catch instances where
31243
+ * localStorage was available the first time this is called, but becomes
31244
+ * unavailable at a later time.
31245
+ *
31246
+ * @private
31247
+ * @return {boolean} Whether or not localStorage is available or not.
31248
+ */
31249
+ isLocalStorageAvailable() {
31250
+ if (this.available === undefined) {
31251
+ this.available = isLocalStorageAvailable();
31252
+ }
31253
+ return this.available;
31254
+ }
31255
+
31256
+ /**
31257
+ * Generates a key to use for localStorage from the provided key. This
31258
+ * should prevent name collisions.
31259
+ *
31260
+ * @private
31261
+ * @param {string} key - Generate key from this key
31262
+ * @return {string} Generated key for localStorage
31263
+ */
31264
+ generateKey(key) {
31265
+ return `bp-${key}`;
31266
+ }
31267
+ }
31268
+ /* harmony default export */ const lib_Cache = (Cache);
31269
+ ;// ./src/lib/BoundedCache.js
31270
+ 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; }
31271
+ function BoundedCache_toPropertyKey(t) { var i = BoundedCache_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31272
+ 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); }
31273
+
31274
+ class BoundedCache extends lib_Cache {
31275
+ /**
31276
+ * [constructor]
31277
+ *
31278
+ * @param {number} [maxEntries] - Override the maximum number of cache entries
31279
+ */
31280
+ constructor(maxEntries) {
31281
+ super();
31282
+ /** @property {Array} - Maintains the list of cache keys in order in which they were added to the cache */
31283
+ BoundedCache_defineProperty(this, "cacheQueue", void 0);
31284
+ /** @property {number} - The maximum number of entries in the cache */
31285
+ BoundedCache_defineProperty(this, "maxEntries", void 0);
31286
+ this.maxEntries = maxEntries || 500;
31287
+ this.cache = {};
31288
+ this.cacheQueue = [];
31289
+ }
31290
+
31291
+ /**
31292
+ * Destroys the bounded cache
31293
+ *
31294
+ * @return {void}
31295
+ */
31296
+ destroy() {
31297
+ this.cache = null;
31298
+ this.cacheQueue = null;
31299
+ }
31300
+
31301
+ /**
31302
+ * Caches a simple object in memory. If the number of cache entries
31303
+ * then exceeds the maxEntries value, then the earliest key in cacheQueue
31304
+ * will be removed from the cache.
31305
+ *
31306
+ * @param {string} key - The cache key
31307
+ * @param {*} value - The cache value
31308
+ * @return {void}
31309
+ */
31310
+ set(key, value) {
31311
+ // If this key is not already in the cache, then add it
31312
+ // to the cacheQueue. This avoids adding the same key to
31313
+ // the cacheQueue multiple times if the cache entry gets updated
31314
+ if (!this.inCache(key)) {
31315
+ this.cacheQueue.push(key);
31316
+ }
31317
+ super.set(key, value);
31318
+
31319
+ // If the cacheQueue exceeds the maxEntries then remove the first
31320
+ // key from the front of the cacheQueue and unset that entry
31321
+ // from the cache
31322
+ if (this.cacheQueue.length > this.maxEntries) {
31323
+ const deleteKey = this.cacheQueue.shift();
31324
+ this.unset(deleteKey);
31325
+ }
31326
+ }
31327
+ }
31328
+ /* harmony default export */ const lib_BoundedCache = (BoundedCache);
31329
+ ;// ./src/lib/Thumbnail.js
31330
+ 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; }
31331
+ 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; }
31332
+ 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; }
31333
+ function Thumbnail_toPropertyKey(t) { var i = Thumbnail_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31334
+ 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); }
31335
+
31336
+
31337
+ const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image';
31338
+ const THUMBNAIL_TOTAL_WIDTH = 150; // 190px sidebar width - 40px margins
31339
+ const THUMBNAIL_IMAGE_WIDTH = THUMBNAIL_TOTAL_WIDTH * 2; // Multiplied by a scaling factor so that we render the image at a higher resolution
31340
+
31341
+ class Thumbnail {
31342
+ /**
31343
+ * [constructor]
31344
+ *
31345
+ * @param {PDFViewer} pdfViewer - the PDFJS viewer
31346
+ */
31347
+ constructor(pdfViewer, preloader) {
31348
+ /** @property {PDfViewer} - The PDFJS viewer instance */
31349
+ Thumbnail_defineProperty(this, "pdfViewer", void 0);
31350
+ /** @property {Object} - Cache for the thumbnail image elements */
31351
+ Thumbnail_defineProperty(this, "thumbnailImageCache", void 0);
31352
+ Thumbnail_defineProperty(this, "preloader", void 0);
31353
+ this.preloader = preloader;
31354
+ this.createImageEl = this.createImageEl.bind(this);
31355
+ this.createThumbnailImage = this.createThumbnailImage.bind(this);
31356
+ this.getThumbnailDataURL = this.getThumbnailDataURL.bind(this);
31357
+ this.pdfViewer = pdfViewer;
31358
+ this.thumbnailImageCache = new lib_BoundedCache();
31359
+ }
31360
+
31361
+ /**
31362
+ * Destroys the thumbnails sidebar
31363
+ *
31364
+ * @return {void}
31365
+ */
31366
+ destroy() {
31367
+ if (this.thumbnailImageCache) {
31368
+ this.thumbnailImageCache.destroy();
31369
+ this.thumbnailImageCache = null;
31370
+ }
31371
+ this.pdfViewer = null;
31372
+ this.preloader = null;
31373
+ }
31374
+
31375
+ /**
31376
+ * Initializes the Thumbnails Sidebar
31377
+ *
31378
+ * @return {Promise}
31379
+ */
31380
+ init() {
31381
+ // Get the first page of the document, and use its dimensions
31382
+ // to set the thumbnails size of the thumbnails sidebar
31383
+
31384
+ if (this.preloader?.imageDimensions) {
31385
+ const {
31386
+ width,
31387
+ height
31388
+ } = this.preloader.imageDimensions;
31389
+ this.scale = THUMBNAIL_TOTAL_WIDTH / width;
31390
+ this.pageRatio = width / height;
31391
+ this.thumbnailHeight = Math.ceil(height * this.scale);
31392
+ return Promise.resolve(this.thumbnailHeight);
31393
+ }
31394
+ const pdfDocument = this.pdfViewer?.pdfDocument;
31395
+ if (!pdfDocument) {
31396
+ return Promise.resolve(null);
31397
+ }
31398
+ return pdfDocument.getPage(1).then(page => {
31399
+ const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
31400
+ const viewport = page.getViewport({
31401
+ scale: 1,
31402
+ rotation
31403
+ });
31404
+ if (!viewport) {
31405
+ return Promise.resolve(null);
31406
+ }
31407
+ const {
31408
+ width,
31409
+ height
31410
+ } = viewport;
31411
+
31412
+ // If the dimensions of the page are invalid then don't proceed further
31413
+ if (!(isFinite_default()(width) && width > 0 && isFinite_default()(height) && height > 0)) {
31414
+ // eslint-disable-next-line
31415
+ console.error('Page dimensions invalid when initializing the thumbnails sidebar');
31416
+ return Promise.resolve(null);
31417
+ }
31418
+
31419
+ // Amount to scale down from full-size to thumbnail size
31420
+ this.scale = THUMBNAIL_TOTAL_WIDTH / width;
31421
+ // Width : Height ratio of the page
31422
+ this.pageRatio = width / height;
31423
+ const scaledViewport = page.getViewport({
31424
+ scale: this.scale,
31425
+ rotation
31426
+ });
31427
+ this.thumbnailHeight = Math.ceil(scaledViewport.height);
31428
+ return Promise.resolve(this.thumbnailHeight);
31429
+ });
31430
+ }
31431
+
31432
+ /**
31433
+ * Creates the image element
31434
+ * @param {string} dataUrl - The image data URL for the thumbnail
31435
+ * @return {HTMLElement} - The image element
31436
+ */
31437
+ createImageEl(dataUrl, thumbOptions) {
31438
+ const imageEl = thumbOptions && thumbOptions.createImgTag ? document.createElement('img') : document.createElement('div');
31439
+ if (thumbOptions && thumbOptions.createImgTag) {
31440
+ imageEl.src = `${dataUrl}`;
31441
+ return imageEl;
31442
+ }
31443
+ imageEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE);
31444
+ imageEl.style.backgroundImage = `url('${dataUrl}')`;
31445
+
31446
+ // Add the height and width to the image to be the same as the thumbnail
31447
+ // so that the css `background-image` rules will work
31448
+ imageEl.style.width = `${THUMBNAIL_TOTAL_WIDTH}px`;
31449
+ imageEl.style.height = `${this.thumbnailHeight}px`;
31450
+ return imageEl;
31451
+ }
31452
+
31453
+ /**
31454
+ * Make a thumbnail image element
31455
+ *
31456
+ * @param {number} itemIndex - the item index for the overall list (0 indexed)
31457
+ * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
31458
+ */
31459
+ createThumbnailImage(itemIndex, thumbOptions) {
31460
+ const cacheEntry = this.getImageFromCache(itemIndex);
31461
+ // If this thumbnail has already been cached, use it
31462
+ if (cacheEntry && cacheEntry.image) {
31463
+ return Promise.resolve(cacheEntry.image);
31464
+ }
31465
+
31466
+ // If this thumbnail has already been requested, resolve with null
31467
+ if (cacheEntry && cacheEntry.inProgress) {
31468
+ return Promise.resolve(null);
31469
+ }
31470
+
31471
+ // Update the cache entry to be in progress
31472
+ this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, cacheEntry), {}, {
31473
+ inProgress: true
31474
+ }));
31475
+ return this.getThumbnailDataURL(itemIndex + 1, thumbOptions).then(dataUrl => {
31476
+ return this.createImageEl(dataUrl, thumbOptions);
31477
+ }).then(imageEl => {
31478
+ // Cache this image element for future use
31479
+ this.thumbnailImageCache.set(itemIndex, {
31480
+ inProgress: false,
31481
+ image: imageEl
31482
+ });
31483
+ return imageEl;
31484
+ }).catch(() => {
31485
+ this.thumbnailImageCache.set(itemIndex, Thumbnail_objectSpread(Thumbnail_objectSpread({}, this.getImageFromCache(itemIndex)), {}, {
31486
+ inProgress: false
31487
+ }));
31488
+ throw new Error('Thumbnail generation failed');
31489
+ });
31490
+ }
31491
+
31492
+ /**
31493
+ * Make a thumbnail image element
31494
+ *
31495
+ * @param {number} itemIndex - the item index for the overall list (0 indexed)
31496
+ * @return {Promise} - promise reolves with the image HTMLElement or null if generation is in progress
31497
+ */
31498
+ getImageFromCache(itemIndex) {
31499
+ return this.thumbnailImageCache.get(itemIndex);
31500
+ }
31501
+
31502
+ /**
31503
+ * Given a page number, generates the image data URL for the image of the page
31504
+ * @param {number} pageNum - The page number of the document
31505
+ * @return {string} The data URL of the page image
31506
+ */
31507
+ getThumbnailDataURL(pageNum, thumbOptions) {
31508
+ if (this.preloader?.preloadedImages?.[pageNum]) {
31509
+ return Promise.resolve(this.preloader.preloadedImages[pageNum]);
31510
+ }
31511
+ const pdfDocument = this.pdfViewer?.pdfDocument;
31512
+ if (!pdfDocument) {
31513
+ return Promise.reject(new Error('PDF document not ready'));
31514
+ }
31515
+ const canvas = document.createElement('canvas');
31516
+ const thumbnailImageWidth = thumbOptions && thumbOptions.thumbMaxWidth ? thumbOptions.thumbMaxWidth : THUMBNAIL_IMAGE_WIDTH;
31517
+ return pdfDocument.getPage(pageNum).then(page => {
31518
+ const rotation = ((this.pdfViewer.pagesRotation || 0) + page.rotate) % 360;
31519
+ const viewport = page.getViewport({
31520
+ scale: 1,
31521
+ rotation
31522
+ });
31523
+ if (!viewport || !isFinite_default()(viewport.width) || !isFinite_default()(viewport.height)) {
31524
+ return Promise.reject(new Error('Invalid page viewport'));
31525
+ }
31526
+ const {
31527
+ width,
31528
+ height
31529
+ } = viewport;
31530
+ // Get the current page w:h ratio in case it differs from the first page
31531
+ const curPageRatio = width / height;
31532
+
31533
+ // Handle the case where the current page's w:h ratio is less than the
31534
+ // `pageRatio` which means that this page is probably more portrait than
31535
+ // landscape
31536
+ if (curPageRatio < this.pageRatio) {
31537
+ // Set the canvas height to that of the thumbnail max height
31538
+ canvas.height = Math.ceil(thumbnailImageWidth / this.pageRatio);
31539
+ // Find the canvas width based on the current page ratio
31540
+ canvas.width = canvas.height * curPageRatio;
31541
+ } else {
31542
+ // In case the current page ratio is same as the first page
31543
+ // or in case it's larger (which means that it's wider), keep
31544
+ // the width at the max thumbnail width
31545
+ canvas.width = thumbnailImageWidth;
31546
+ // Find the height based on the current page ratio
31547
+ canvas.height = Math.ceil(thumbnailImageWidth / curPageRatio);
31548
+ }
31549
+ // The amount for which to scale down the current page
31550
+ const {
31551
+ width: canvasWidth
31552
+ } = canvas;
31553
+ const scale = canvasWidth / width;
31554
+ return page.render({
31555
+ canvasContext: canvas.getContext('2d'),
31556
+ viewport: page.getViewport({
31557
+ scale,
31558
+ rotation
31559
+ })
31560
+ }).promise;
31561
+ }).then(() => canvas.toDataURL());
31562
+ }
31563
+ }
31564
+ /* harmony default export */ const lib_Thumbnail = (Thumbnail);
31565
+ ;// ./src/lib/viewers/gallery/GalleryGrid.scss
31566
+ // extracted by mini-css-extract-plugin
31567
+
31568
+ ;// ./src/lib/viewers/gallery/GalleryGrid.tsx
31569
+ 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; }
31570
+ 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; }
31571
+ 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; }
31572
+ function GalleryGrid_toPropertyKey(t) { var i = GalleryGrid_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31573
+ 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); }
31574
+
31575
+
31576
+
31577
+ const GALLERY_THUMB_MAX_WIDTH = 440;
31578
+ const INITIAL_LOAD_BUFFER = 40;
31579
+ const CONCURRENT_LOADS = 4;
31580
+ const SCROLL_THROTTLE_MS = 200;
31581
+ function GalleryGrid(_ref) {
31582
+ let {
31583
+ pageCount,
31584
+ currentPage,
31585
+ onClose,
31586
+ onFocusChange,
31587
+ onPageNavigate,
31588
+ thumbnail
31589
+ } = _ref;
31590
+ const [loadedImages, setLoadedImages] = __WEBPACK_EXTERNAL_MODULE_react_useState__({});
31591
+ const [focusedPage, setFocusedPage] = __WEBPACK_EXTERNAL_MODULE_react_useState__(currentPage);
31592
+ const gridRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(null);
31593
+ const queueRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__([]);
31594
+ const isProcessingRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
31595
+ const isMountedRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(true);
31596
+ const initialLoadDoneRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(false);
31597
+ const initialLoadCountRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(0);
31598
+ function processQueue() {
31599
+ if (!isMountedRef.current || !thumbnail || queueRef.current.length === 0) {
31600
+ isProcessingRef.current = false;
31601
+ return;
31602
+ }
31603
+ const batchSize = initialLoadDoneRef.current ? CONCURRENT_LOADS : 1;
31604
+ const batch = queueRef.current.slice(0, batchSize);
31605
+ queueRef.current = queueRef.current.slice(batchSize);
31606
+ requestAnimationFrame(() => {
31607
+ if (!isMountedRef.current || !thumbnail) {
31608
+ isProcessingRef.current = false;
31609
+ return;
31610
+ }
31611
+ let completed = 0;
31612
+ const onComplete = () => {
31613
+ completed += 1;
31614
+ if (completed < batch.length) return;
31615
+ if (!isMountedRef.current) {
31616
+ isProcessingRef.current = false;
31617
+ return;
31618
+ }
31619
+ if (!initialLoadDoneRef.current) {
31620
+ initialLoadCountRef.current += batch.length;
31621
+ if (initialLoadCountRef.current >= INITIAL_LOAD_BUFFER) {
31622
+ initialLoadDoneRef.current = true;
31623
+ isProcessingRef.current = false;
31624
+ return;
31625
+ }
31626
+ }
31627
+ processQueue();
31628
+ };
31629
+ batch.forEach(pageNum => {
31630
+ thumbnail.createThumbnailImage(pageNum - 1, {
31631
+ createImgTag: true,
31632
+ thumbMaxWidth: GALLERY_THUMB_MAX_WIDTH
31633
+ }).then(imageEl => {
31634
+ if (isMountedRef.current && imageEl && imageEl.src) {
31635
+ setLoadedImages(prev => GalleryGrid_objectSpread(GalleryGrid_objectSpread({}, prev), {}, {
31636
+ [pageNum]: imageEl.src
31637
+ }));
31638
+ }
31639
+ onComplete();
31640
+ }).catch(() => {
31641
+ onComplete();
31642
+ });
31643
+ });
31644
+ });
31645
+ }
31646
+ function startProcessing() {
31647
+ if (!isProcessingRef.current && queueRef.current.length > 0) {
31648
+ isProcessingRef.current = true;
31649
+ processQueue();
31650
+ }
31651
+ }
31652
+ function getUnloadedNearViewport() {
31653
+ const grid = gridRef.current;
31654
+ if (!grid) return [];
31655
+ const {
31656
+ scrollTop,
31657
+ clientHeight
31658
+ } = grid;
31659
+ const bufferZone = clientHeight * 3;
31660
+ const viewportTop = scrollTop - bufferZone;
31661
+ const viewportBottom = scrollTop + clientHeight + bufferZone;
31662
+ const nearbyUnloaded = [];
31663
+ const tiles = grid.querySelectorAll('[data-page]');
31664
+ tiles.forEach(tile => {
31665
+ const el = tile;
31666
+ if (!el.dataset.page) return;
31667
+ const pageNum = parseInt(el.dataset.page, 10);
31668
+ const tileTop = el.offsetTop;
31669
+ const tileBottom = tileTop + el.offsetHeight;
31670
+ if (tileBottom > viewportTop && tileTop < viewportBottom && !el.querySelector('img')) {
31671
+ nearbyUnloaded.push(pageNum);
31672
+ }
31673
+ });
31674
+ return nearbyUnloaded;
31064
31675
  }
31065
31676
  const handleScrollRef = __WEBPACK_EXTERNAL_MODULE_react_useRef__(throttle_default()(() => {
31066
31677
  const nearbyUnloaded = getUnloadedNearViewport();
@@ -31132,51 +31743,229 @@ function GalleryGrid(_ref) {
31132
31743
  onClose();
31133
31744
  return;
31134
31745
  }
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
- }
31746
+ if (event.key === 'Tab' && gridRef.current) {
31747
+ const buttons = gridRef.current.querySelectorAll('button');
31748
+ const first = buttons[0];
31749
+ const last = buttons[buttons.length - 1];
31750
+ if (event.shiftKey && document.activeElement === first) {
31751
+ event.preventDefault();
31752
+ last.focus();
31753
+ } else if (!event.shiftKey && document.activeElement === last) {
31754
+ event.preventDefault();
31755
+ first.focus();
31756
+ }
31757
+ }
31758
+ }, [onClose]);
31759
+ const tiles = [];
31760
+ for (let i = 1; i <= pageCount; i += 1) {
31761
+ const isFocused = i === focusedPage;
31762
+ tiles.push( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("button", {
31763
+ key: i,
31764
+ "aria-label": `Page ${i}${isFocused ? ', current page' : ''}`,
31765
+ className: `bp-gallery-tile${isFocused ? ' bp-gallery-tile--selected' : ''}`,
31766
+ "data-page": i,
31767
+ onClick: () => onPageNavigate(i),
31768
+ onFocus: () => handleTileFocus(i),
31769
+ type: "button"
31770
+ }, /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31771
+ className: "bp-gallery-tile-badge"
31772
+ }, i), loadedImages[i] ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("img", {
31773
+ alt: `Page ${i}`,
31774
+ src: loadedImages[i]
31775
+ }) : /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement("span", {
31776
+ className: "bp-gallery-tile-placeholder"
31777
+ })));
31778
+ }
31779
+ return (
31780
+ /*#__PURE__*/
31781
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
31782
+ __WEBPACK_EXTERNAL_MODULE_react_default__.createElement("div", {
31783
+ ref: gridRef,
31784
+ className: "bp-gallery-grid",
31785
+ onFocus: handleGridFocus,
31786
+ onKeyDown: handleGridKeyDown,
31787
+ onScroll: handleScrollRef.current,
31788
+ tabIndex: -1
31789
+ }, tiles)
31790
+ );
31791
+ }
31792
+ ;// ./src/lib/viewers/gallery/GalleryController.tsx
31793
+ 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; }
31794
+ function GalleryController_toPropertyKey(t) { var i = GalleryController_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
31795
+ 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); }
31796
+ // Doc-viewer-bound: this controller talks to PDF.js (pdfViewer, Thumbnail) and
31797
+ // the doc-specific ThumbnailsSidebar. If a non-doc viewer ever needs gallery,
31798
+ // the dependencies below must be abstracted first.
31799
+
31800
+
31801
+
31802
+
31803
+
31804
+
31805
+
31806
+ // Controller-owned shape: GalleryGrid only sees the read surface (GalleryThumbnail),
31807
+ // but the controller also needs destroy() to invalidate the cache on rotate/teardown.
31808
+
31809
+ const GALLERY_MAX_PAGES = 200; // Hide gallery toggle for files above this page count, will increase in V2
31810
+ const THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // ms
31811
+
31812
+ // Minimal local shapes for untyped peer modules (pdfjs is JS-only, sidebar is JS-only).
31813
+ // Only the members the controller actually uses are declared — extend as needed.
31814
+
31815
+ // The preloader is opaque to the controller; we only forward it into Thumbnail's constructor.
31816
+ // Type-alias what the Thumbnail constructor expects so the two sides stay in sync.
31817
+
31818
+ class GalleryController {
31819
+ constructor(opts) {
31820
+ GalleryController_defineProperty(this, "containerEl", void 0);
31821
+ GalleryController_defineProperty(this, "features", void 0);
31822
+ GalleryController_defineProperty(this, "getPdfViewer", void 0);
31823
+ GalleryController_defineProperty(this, "getPreloader", void 0);
31824
+ GalleryController_defineProperty(this, "getThumbnailsSidebar", void 0);
31825
+ GalleryController_defineProperty(this, "setPage", void 0);
31826
+ GalleryController_defineProperty(this, "toggleThumbnails", void 0);
31827
+ GalleryController_defineProperty(this, "requestUiUpdate", void 0);
31828
+ GalleryController_defineProperty(this, "galleryRoot", null);
31829
+ GalleryController_defineProperty(this, "galleryEl", null);
31830
+ GalleryController_defineProperty(this, "galleryThumbnail", null);
31831
+ GalleryController_defineProperty(this, "galleryFocusedPage", null);
31832
+ GalleryController_defineProperty(this, "galleryMountTimeoutId", null);
31833
+ GalleryController_defineProperty(this, "gallerySidebarTimeoutId", null);
31834
+ GalleryController_defineProperty(this, "sidebarWasOpen", false);
31835
+ GalleryController_defineProperty(this, "isGalleryOpen", false);
31836
+ GalleryController_defineProperty(this, "toggle", () => {
31837
+ this.isGalleryOpen = !this.isGalleryOpen;
31838
+ if (this.isGalleryOpen) {
31839
+ if (this.gallerySidebarTimeoutId !== null) {
31840
+ clearTimeout(this.gallerySidebarTimeoutId);
31841
+ this.gallerySidebarTimeoutId = null;
31842
+ }
31843
+ const sidebar = this.getThumbnailsSidebar();
31844
+ this.sidebarWasOpen = !!(sidebar && sidebar.isOpen);
31845
+ if (this.sidebarWasOpen) {
31846
+ this.toggleThumbnails();
31847
+ this.galleryMountTimeoutId = setTimeout(() => {
31848
+ this.galleryMountTimeoutId = null;
31849
+ this.mountGrid();
31850
+ }, THUMBNAILS_SIDEBAR_TRANSITION_TIME / 2);
31851
+ } else {
31852
+ this.mountGrid();
31853
+ }
31854
+ } else {
31855
+ if (this.galleryMountTimeoutId !== null) {
31856
+ clearTimeout(this.galleryMountTimeoutId);
31857
+ this.galleryMountTimeoutId = null;
31858
+ }
31859
+ const pdfViewer = this.getPdfViewer();
31860
+ const navigateToPage = this.galleryFocusedPage && this.galleryFocusedPage !== pdfViewer.currentPageNumber ? this.galleryFocusedPage : null;
31861
+ if (this.galleryRoot) {
31862
+ this.galleryRoot.unmount();
31863
+ this.galleryRoot = null;
31864
+ }
31865
+ if (this.galleryEl) {
31866
+ this.galleryEl.remove();
31867
+ this.galleryEl = null;
31868
+ }
31869
+ this.galleryFocusedPage = null;
31870
+ const sidebar = this.getThumbnailsSidebar();
31871
+ if (this.sidebarWasOpen && sidebar && !sidebar.isOpen) {
31872
+ this.toggleThumbnails();
31873
+ }
31874
+ if (navigateToPage) {
31875
+ this.setPage(navigateToPage);
31876
+ if (this.sidebarWasOpen && sidebar) {
31877
+ this.gallerySidebarTimeoutId = setTimeout(() => {
31878
+ this.gallerySidebarTimeoutId = null;
31879
+ sidebar.setCurrentPage(navigateToPage);
31880
+ }, THUMBNAILS_SIDEBAR_TRANSITION_TIME);
31881
+ }
31882
+ }
31883
+ }
31884
+ this.requestUiUpdate();
31885
+ });
31886
+ GalleryController_defineProperty(this, "handleGalleryNavigate", pageNum => {
31887
+ this.galleryFocusedPage = pageNum;
31888
+ this.toggle();
31889
+ });
31890
+ GalleryController_defineProperty(this, "handleFocusChange", pageNum => {
31891
+ this.galleryFocusedPage = pageNum;
31892
+ });
31893
+ this.containerEl = opts.containerEl;
31894
+ this.features = opts.features;
31895
+ this.getPdfViewer = opts.getPdfViewer;
31896
+ this.getPreloader = opts.getPreloader;
31897
+ this.getThumbnailsSidebar = opts.getThumbnailsSidebar;
31898
+ this.setPage = opts.setPage;
31899
+ this.toggleThumbnails = opts.toggleThumbnails;
31900
+ this.requestUiUpdate = opts.requestUiUpdate;
31901
+ }
31902
+ get isOpen() {
31903
+ return this.isGalleryOpen;
31904
+ }
31905
+ canRender(pageCount) {
31906
+ return isFeatureEnabled(this.features, 'galleryView.enabled') && pageCount > 1 && pageCount <= GALLERY_MAX_PAGES;
31907
+ }
31908
+ handleEscape() {
31909
+ if (!this.isGalleryOpen) return false;
31910
+ this.toggle();
31911
+ return true;
31912
+ }
31913
+ handleRotate() {
31914
+ if (this.galleryThumbnail) {
31915
+ this.galleryThumbnail.destroy();
31916
+ this.galleryThumbnail = null;
31917
+ }
31918
+ }
31919
+ destroy() {
31920
+ if (this.galleryMountTimeoutId !== null) {
31921
+ clearTimeout(this.galleryMountTimeoutId);
31922
+ this.galleryMountTimeoutId = null;
31923
+ }
31924
+ if (this.gallerySidebarTimeoutId !== null) {
31925
+ clearTimeout(this.gallerySidebarTimeoutId);
31926
+ this.gallerySidebarTimeoutId = null;
31927
+ }
31928
+ if (this.galleryRoot) {
31929
+ this.galleryRoot.unmount();
31930
+ this.galleryRoot = null;
31931
+ }
31932
+ if (this.galleryEl) {
31933
+ this.galleryEl.remove();
31934
+ this.galleryEl = null;
31935
+ }
31936
+ if (this.galleryThumbnail) {
31937
+ this.galleryThumbnail.destroy();
31938
+ this.galleryThumbnail = null;
31939
+ }
31940
+
31941
+ // Reset state so isOpen is honest even after teardown.
31942
+ this.isGalleryOpen = false;
31943
+ this.sidebarWasOpen = false;
31944
+ this.galleryFocusedPage = null;
31945
+ }
31946
+ mountGrid() {
31947
+ if (this.galleryRoot) {
31948
+ return;
31949
+ }
31950
+ const pdfViewer = this.getPdfViewer();
31951
+ if (!this.galleryThumbnail) {
31952
+ // Thumbnail is a JS class; cast to the typed interface used by the controller + grid.
31953
+ this.galleryThumbnail = new lib_Thumbnail(pdfViewer, this.getPreloader());
31146
31954
  }
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
- })));
31955
+ const thumbnail = this.galleryThumbnail;
31956
+ this.galleryEl = document.createElement('div');
31957
+ this.containerEl.appendChild(this.galleryEl);
31958
+ this.galleryRoot = __WEBPACK_EXTERNAL_MODULE_react_dom_client_4cb20cd7_createRoot__(this.galleryEl);
31959
+ this.galleryFocusedPage = pdfViewer.currentPageNumber;
31960
+ this.galleryRoot.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(GalleryGrid, {
31961
+ currentPage: pdfViewer.currentPageNumber,
31962
+ onClose: this.toggle,
31963
+ onFocusChange: this.handleFocusChange,
31964
+ onPageNavigate: this.handleGalleryNavigate,
31965
+ pageCount: pdfViewer.pagesCount,
31966
+ thumbnail: thumbnail
31967
+ }));
31167
31968
  }
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
31969
  }
31181
31970
  ;// ./src/lib/logUtils.js
31182
31971
 
@@ -31603,232 +32392,27 @@ class PageTracker extends (events_default()) {
31603
32392
  /**
31604
32393
  * Update content insights options
31605
32394
  *
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
32395
+ * @private
32396
+ * @param {Object} options - Content Insights options
31811
32397
  * @return {void}
31812
32398
  */
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);
32399
+ updateOptions() {
32400
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
32401
+ // Set User and file information
32402
+ const prevActiveState = this.isAdvancedInsightsActive;
32403
+ this.setOptions(options);
32404
+ if (prevActiveState !== this.isAdvancedInsightsActive) {
32405
+ // If ACI was deactivated, stop tracking user events
32406
+ if (!this.isAdvancedInsightsActive) {
32407
+ this.stopTracking();
32408
+ this.unbindIdleUserEvents();
32409
+ } else {
32410
+ this.init();
32411
+ }
31828
32412
  }
31829
32413
  }
31830
32414
  }
31831
- /* harmony default export */ const lib_BoundedCache = (BoundedCache);
32415
+ /* harmony default export */ const lib_PageTracker = (PageTracker);
31832
32416
  // EXTERNAL MODULE: ./node_modules/lodash/isFunction.js
31833
32417
  var isFunction = __webpack_require__(1882);
31834
32418
  var isFunction_default = /*#__PURE__*/__webpack_require__.n(isFunction);
@@ -32164,365 +32748,129 @@ class VirtualScroller {
32164
32748
  if (!listEl || start < 0 || end < 0) {
32165
32749
  return;
32166
32750
  }
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
- });
32751
+ const listItems = Array.prototype.slice.call(listEl.children, start, end);
32752
+ listItems.forEach(listItem => listEl.removeChild(listItem));
32391
32753
  }
32392
32754
 
32393
32755
  /**
32394
- * Creates the image element
32395
- * @param {string} dataUrl - The image data URL for the thumbnail
32396
- * @return {HTMLElement} - The image element
32756
+ * Render a single item
32757
+ *
32758
+ * @param {number} rowIndex - The index of the item to be rendered
32759
+ * @return {HTMLElement} The newly created row item
32397
32760
  */
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;
32761
+ renderItem(rowIndex) {
32762
+ const rowEl = document.createElement('li');
32763
+ const topPosition = (this.itemHeight + this.margin) * rowIndex + this.margin;
32764
+ let renderedThumbnail;
32765
+ try {
32766
+ renderedThumbnail = this.renderItemFn.call(this, rowIndex);
32767
+ } catch (err) {
32768
+ // eslint-disable-next-line
32769
+ console.error(`Error rendering thumbnail - ${err}`);
32403
32770
  }
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;
32771
+ rowEl.style.top = `${topPosition}px`;
32772
+ rowEl.style.height = `${this.itemHeight}px`;
32773
+ rowEl.classList.add('bp-vs-list-item');
32774
+ rowEl.dataset.bpVsRowIndex = rowIndex;
32775
+ if (renderedThumbnail) {
32776
+ rowEl.appendChild(renderedThumbnail);
32777
+ }
32778
+ return rowEl;
32412
32779
  }
32413
32780
 
32414
32781
  /**
32415
- * Make a thumbnail image element
32782
+ * Utility to create the list element
32416
32783
  *
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
32784
+ * @return {HTMLElement} The list element
32419
32785
  */
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
- }
32786
+ createListElement() {
32787
+ const newListEl = document.createElement('ol');
32788
+ newListEl.className = 'bp-vs-list';
32789
+ newListEl.style.height = `${this.totalItems * (this.itemHeight + this.margin) + this.margin}px`;
32790
+ return newListEl;
32791
+ }
32426
32792
 
32427
- // If this thumbnail has already been requested, resolve with null
32428
- if (cacheEntry && cacheEntry.inProgress) {
32429
- return Promise.resolve(null);
32793
+ /**
32794
+ * Scrolls the provided row index into view.
32795
+ * @param {number} rowIndex - the index of the row in the overall list
32796
+ * @return {void}
32797
+ */
32798
+ scrollIntoView(rowIndex) {
32799
+ if (!this.scrollingEl || rowIndex < 0 || rowIndex >= this.totalItems) {
32800
+ return;
32430
32801
  }
32431
32802
 
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');
32803
+ // See if the list item indexed by `rowIndex` is already present
32804
+ const foundItem = this.getListItems().find(listItem => {
32805
+ const {
32806
+ bpVsRowIndex
32807
+ } = listItem.dataset;
32808
+ const parsedRowIndex = parseInt(bpVsRowIndex, 10);
32809
+ return parsedRowIndex === rowIndex;
32450
32810
  });
32811
+ if (foundItem) {
32812
+ // If it is already present and visible, do nothing, but if not visible
32813
+ // then scroll it into view
32814
+ if (!this.isVisible(foundItem)) {
32815
+ foundItem.scrollIntoView({
32816
+ block: 'nearest'
32817
+ });
32818
+ }
32819
+ } else {
32820
+ // If it is not present, then adjust the scrollTop so that the list item
32821
+ // will get rendered.
32822
+ const topPosition = (this.itemHeight + this.margin) * rowIndex;
32823
+ this.scrollingEl.scrollTop = topPosition;
32824
+ // Some browsers don't fire the scroll event when setting scrollTop
32825
+ // (IE11 & Firefox) so we need to manually dispatch the event
32826
+ // in order to trigger `onScrollHandler` to render the items
32827
+ this.scrollingEl.dispatchEvent(new Event('scroll'));
32828
+ }
32451
32829
  }
32452
32830
 
32453
32831
  /**
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
32832
+ * Checks to see whether the provided list item element is currently visible
32833
+ * @param {HTMLElement} listItemEl - the list item elment
32834
+ * @return {boolean} Returns true if the list item is visible, false otherwise
32458
32835
  */
32459
- getImageFromCache(itemIndex) {
32460
- return this.thumbnailImageCache.get(itemIndex);
32836
+ isVisible(listItemEl) {
32837
+ if (!this.scrollingEl || !listItemEl) {
32838
+ return false;
32839
+ }
32840
+ const {
32841
+ scrollTop
32842
+ } = this.scrollingEl;
32843
+ const {
32844
+ offsetTop
32845
+ } = listItemEl;
32846
+
32847
+ // Ensure that the offsetTop and entire height of the listItemEl are inside the visible window
32848
+ return scrollTop <= offsetTop && offsetTop + this.itemHeight <= scrollTop + this.containerHeight;
32461
32849
  }
32462
32850
 
32463
32851
  /**
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
32852
+ * Gets the currently visible list items
32853
+ * @return {Array<HTMLElement>} - the list of current visible list items
32467
32854
  */
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'));
32855
+ getVisibleItems() {
32856
+ if (!this.listEl) {
32857
+ return [];
32475
32858
  }
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;
32859
+ return this.getListItems().filter(itemEl => this.isVisible(itemEl)).map(itemEl => itemEl && itemEl.children && itemEl.children[0]);
32860
+ }
32493
32861
 
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());
32862
+ /**
32863
+ * Gets the list items of this.listEl as an array
32864
+ * @return {Array<HTMLElement>} - the list items
32865
+ */
32866
+ getListItems() {
32867
+ if (!this.listEl) {
32868
+ return [];
32869
+ }
32870
+ return Array.prototype.slice.call(this.listEl.children);
32523
32871
  }
32524
32872
  }
32525
- /* harmony default export */ const lib_Thumbnail = (Thumbnail);
32873
+ /* harmony default export */ const lib_VirtualScroller = (VirtualScroller);
32526
32874
  ;// ./src/lib/ThumbnailsSidebar.js
32527
32875
  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
32876
  function ThumbnailsSidebar_toPropertyKey(t) { var i = ThumbnailsSidebar_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -32991,7 +33339,6 @@ function DocBaseViewer_toPrimitive(t, r) { if ("object" != typeof t || !t) retur
32991
33339
 
32992
33340
 
32993
33341
 
32994
-
32995
33342
 
32996
33343
 
32997
33344
  const DOC_FIRST_PAGES_ENABLED = 'docFirstPages.enabled';
@@ -33026,8 +33373,7 @@ const RANGE_CHUNK_SIZE_US = 1048576; // 1MB
33026
33373
  const RANGE_REQUEST_MINIMUM_SIZE = 26214400; // 25MB
33027
33374
  const SAFARI_PRINT_TIMEOUT_MS = 1000; // Wait 1s before trying to print
33028
33375
  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
33376
+ const DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME = 301; // 301ms
33031
33377
  const THUMBNAILS_SIDEBAR_TOGGLED_MAP_KEY = 'doc-thumbnails-toggled-map';
33032
33378
  const MAX_OPERATIONS = 320000; // Block PDFs with more than 320,000 drawing operations
33033
33379
  const MAX_OPERATION_PAGES = 5; // Check only the first 5 pages
@@ -33056,18 +33402,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33056
33402
  //--------------------------------------------------------------------------
33057
33403
  /** @property {Thumbnail} - Thumbnail reference */
33058
33404
  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);
33405
+ /** @property {GalleryController} - Owns gallery-view state, lifecycle, and toolbar gating */
33406
+ DocBaseViewer_defineProperty(this, "galleryController", void 0);
33071
33407
  /** @property {PageTracker} - PageTracker instance */
33072
33408
  DocBaseViewer_defineProperty(this, "pageTracker", void 0);
33073
33409
  DocBaseViewer_defineProperty(this, "doc", void 0);
@@ -33088,7 +33424,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33088
33424
  this.handleAnnotationCreateEvent = this.handleAnnotationCreateEvent.bind(this);
33089
33425
  this.handleAnnotationCreatorChangeEvent = this.handleAnnotationCreatorChangeEvent.bind(this);
33090
33426
  this.handleDocElKeydown = this.handleDocElKeydown.bind(this);
33091
- this.handleGalleryNavigate = this.handleGalleryNavigate.bind(this);
33092
33427
  this.handlePageSubmit = this.handlePageSubmit.bind(this);
33093
33428
  this.onThumbnailSelectHandler = this.onThumbnailSelectHandler.bind(this);
33094
33429
  this.pagechangingHandler = this.pagechangingHandler.bind(this);
@@ -33103,7 +33438,6 @@ class DocBaseViewer extends viewers_BaseViewer {
33103
33438
  this.setPage = this.setPage.bind(this);
33104
33439
  this.throttledScrollHandler = this.getScrollHandler().bind(this);
33105
33440
  this.toggleFindBar = this.toggleFindBar.bind(this);
33106
- this.toggleGallery = this.toggleGallery.bind(this);
33107
33441
  this.toggleThumbnails = this.toggleThumbnails.bind(this);
33108
33442
  this.updateExperiences = this.updateExperiences.bind(this);
33109
33443
  this.updateDiscoverabilityResinTag = this.updateDiscoverabilityResinTag.bind(this);
@@ -33158,6 +33492,16 @@ class DocBaseViewer extends viewers_BaseViewer {
33158
33492
  if (isFeatureEnabled(this.options.features, 'advancedContentInsights.enabled')) {
33159
33493
  this.pageTracker = new lib_PageTracker(advancedContentInsightsConfig, this.options.file);
33160
33494
  }
33495
+ this.galleryController = new GalleryController({
33496
+ containerEl: this.containerEl,
33497
+ features: this.options.features,
33498
+ getPdfViewer: () => this.pdfViewer,
33499
+ getPreloader: () => this.preloader,
33500
+ getThumbnailsSidebar: () => this.thumbnailsSidebar,
33501
+ setPage: n => this.setPage(n),
33502
+ toggleThumbnails: () => this.toggleThumbnails(),
33503
+ requestUiUpdate: () => this.renderUI()
33504
+ });
33161
33505
  }
33162
33506
 
33163
33507
  /**
@@ -33183,26 +33527,9 @@ class DocBaseViewer extends viewers_BaseViewer {
33183
33527
  this.findBar.destroy();
33184
33528
  }
33185
33529
 
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;
33530
+ // Must run before pdfViewer teardown galleryController holds Thumbnail render promises against pdfViewer
33531
+ if (this.galleryController) {
33532
+ this.galleryController.destroy();
33206
33533
  }
33207
33534
 
33208
33535
  // Clean up PDF network requests
@@ -33810,9 +34137,8 @@ class DocBaseViewer extends viewers_BaseViewer {
33810
34137
  if (this.thumbnailsSidebar) {
33811
34138
  this.thumbnailsSidebar.refresh();
33812
34139
  }
33813
- if (this.galleryThumbnail) {
33814
- this.galleryThumbnail.destroy();
33815
- this.galleryThumbnail = null;
34140
+ if (this.galleryController) {
34141
+ this.galleryController.handleRotate();
33816
34142
  }
33817
34143
  this.renderUI();
33818
34144
 
@@ -34378,7 +34704,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34378
34704
  const canDownload = checkPermission(this.options.file, PERMISSION_DOWNLOAD);
34379
34705
  const isAnnotationsMode = this.currentAnnotatorViewMode === ANNOTATOR_VIEW_MODES.ANNOTATIONS;
34380
34706
  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;
34707
+ const canGallery = this.galleryController.canRender(this.pdfViewer.pagesCount);
34382
34708
  this.controls.render( /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_default__.createElement(DocControls, {
34383
34709
  annotationColor: this.annotationModule.getColor(),
34384
34710
  annotationMode: this.annotationControlsFSM.getMode(),
@@ -34386,7 +34712,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34386
34712
  hasDrawing: canAnnotate && showAnnotationsDrawingCreate && isAnnotationsMode,
34387
34713
  hasHighlight: canAnnotate && canDownload && isAnnotationsMode,
34388
34714
  hasRegion: canAnnotate && isAnnotationsMode,
34389
- isGalleryOpen: this.isGalleryOpen,
34715
+ isGalleryOpen: this.galleryController.isOpen,
34390
34716
  isThumbnailsOpen: this.thumbnailsSidebar && this.thumbnailsSidebar.isOpen,
34391
34717
  maxScale: DocBaseViewer_MAX_SCALE,
34392
34718
  minScale: DocBaseViewer_MIN_SCALE,
@@ -34395,7 +34721,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34395
34721
  onAnnotationModeEscape: this.handleAnnotationControlsEscape,
34396
34722
  onFindBarToggle: !this.isFindDisabled() ? this.toggleFindBar : undefined,
34397
34723
  onFullscreenToggle: this.toggleFullscreen,
34398
- onGalleryToggle: canGallery ? this.toggleGallery : undefined,
34724
+ onGalleryToggle: canGallery ? this.galleryController.toggle : undefined,
34399
34725
  onPageChange: this.setPage,
34400
34726
  onPageSubmit: this.handlePageSubmit,
34401
34727
  onRotateLeft: canRotate ? this.rotateLeft : undefined,
@@ -34629,8 +34955,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34629
34955
  */
34630
34956
  handleDocElKeydown(event) {
34631
34957
  const key = decodeKeydown(event);
34632
- if (key === 'Escape' && this.isGalleryOpen) {
34633
- this.toggleGallery();
34958
+ if (key === 'Escape' && this.galleryController.handleEscape()) {
34634
34959
  return;
34635
34960
  }
34636
34961
  if (event.altKey && key.includes('Arrow')) {
@@ -34881,80 +35206,7 @@ class DocBaseViewer extends viewers_BaseViewer {
34881
35206
  // Remove the active classes to allow the container to be transitioned properly
34882
35207
  this.rootEl.classList.remove(CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE);
34883
35208
  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();
35209
+ }, DocBaseViewer_THUMBNAILS_SIDEBAR_TRANSITION_TIME);
34958
35210
  }
34959
35211
 
34960
35212
  /**