@prose-reader/core 1.72.0 → 1.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/cfi/generate/{getCfiForSpineItemPage.d.ts → generateCfiForSpineItemPage.d.ts} +1 -1
  2. package/dist/cfi/lookup/resolveCfi.d.ts +236 -0
  3. package/dist/constants.d.ts +0 -1
  4. package/dist/context/Context.d.ts +6 -29
  5. package/dist/createReaderWithEnhancer.d.ts +252 -9
  6. package/dist/enhancers/events/events.d.ts +1 -6
  7. package/dist/enhancers/events/frames.d.ts +3 -0
  8. package/dist/enhancers/events/normalizeEventForViewport.d.ts +1 -5
  9. package/dist/enhancers/navigation/index.d.ts +1 -1
  10. package/dist/enhancers/navigation/navigators/manualNavigator.d.ts +4 -0
  11. package/dist/enhancers/navigation/resolvers/{getNavigationForLeftPage.d.ts → getNavigationForLeftOrTopPage.d.ts} +1 -1
  12. package/dist/enhancers/navigation/resolvers/{getNavigationForRightPage.d.ts → getNavigationForRightOrBottomPage.d.ts} +1 -1
  13. package/dist/enhancers/navigation/types.d.ts +8 -0
  14. package/dist/enhancers/zoom/ControllableZoomer.d.ts +19 -0
  15. package/dist/enhancers/zoom/ScrollableZoomer.d.ts +16 -0
  16. package/dist/enhancers/zoom/Zoomer.d.ts +21 -0
  17. package/dist/enhancers/zoom/index.d.ts +2 -2
  18. package/dist/enhancers/zoom/types.d.ts +10 -12
  19. package/dist/index.d.ts +3 -1
  20. package/dist/index.js +1021 -923
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.umd.cjs +1041 -941
  23. package/dist/index.umd.cjs.map +1 -1
  24. package/dist/navigation/InternalNavigator.d.ts +3 -5
  25. package/dist/navigation/Navigator.d.ts +1 -3
  26. package/dist/navigation/UserNavigator.d.ts +3 -1
  27. package/dist/navigation/consolidation/withSpineItemLayoutInfo.d.ts +3 -3
  28. package/dist/navigation/consolidation/withSpineItemPosition.d.ts +0 -2
  29. package/dist/navigation/resolvers/NavigationResolver.d.ts +3 -1
  30. package/dist/navigation/resolvers/getAdjustedPositionWithSafeEdge.d.ts +3 -1
  31. package/dist/navigation/restoration/restoreNavigationForControlledPageTurnMode.d.ts +3 -1
  32. package/dist/navigation/restoration/restorePosition.d.ts +3 -1
  33. package/dist/navigation/restoration/withRestoredPosition.d.ts +3 -7
  34. package/dist/navigation/tests/SpineItemsManagerMock.d.ts +2 -1
  35. package/dist/navigation/tests/utils.d.ts +2 -0
  36. package/dist/navigation/viewport/getScaledDownPosition.d.ts +2 -3
  37. package/dist/reader.d.ts +260 -18
  38. package/dist/settings/SettingsInterface.d.ts +2 -2
  39. package/dist/settings/SettingsManager.d.ts +2 -2
  40. package/dist/settings/SettingsManagerOverload.d.ts +2 -2
  41. package/dist/spine/Spine.d.ts +5 -2
  42. package/dist/spine/SpineItemsManager.d.ts +5 -26
  43. package/dist/spine/SpineItemsObserver.d.ts +3 -1
  44. package/dist/spine/SpineLayout.d.ts +49 -0
  45. package/dist/spine/layout/convertViewportPositionToLayoutPosition.d.ts +10 -0
  46. package/dist/spine/loader/SpineItemsLoader.d.ts +3 -1
  47. package/dist/spine/locator/SpineLocator.d.ts +146 -5
  48. package/dist/spine/locator/getAbsolutePageIndexFromPageIndex.d.ts +14 -0
  49. package/dist/spine/locator/getSpineInfoFromAbsolutePageIndex.d.ts +134 -0
  50. package/dist/spine/locator/getSpineItemFromPosition.d.ts +3 -1
  51. package/dist/spine/locator/getSpinePositionFromSpineItemPageIndex.d.ts +13 -0
  52. package/dist/spine/locator/getSpinePositionFromSpineItemPosition.d.ts +10 -0
  53. package/dist/spine/locator/getVisibleSpineItemsFromPosition.d.ts +3 -1
  54. package/dist/spineItem/locationResolver.d.ts +12 -2
  55. package/dist/spineItem/locator/getSpineItemNumberOfPages.d.ts +10 -0
  56. package/dist/spineItem/locator/getSpineItemPagesPosition.d.ts +12 -0
  57. package/dist/spineItem/locator/getSpineItemPositionFromPageIndex.d.ts +12 -0
  58. package/dist/utils/frames.d.ts +1 -0
  59. package/dist/utils/objects.d.ts +1 -6
  60. package/package.json +3 -3
  61. package/dist/enhancers/events/createIframeEventBridgeElement.d.ts +0 -1
  62. package/dist/enhancers/zoom/elementZoomer.d.ts +0 -19
  63. package/dist/enhancers/zoom/viewportZoomer.d.ts +0 -19
  64. package/dist/frames.d.ts +0 -5
@@ -7,7 +7,7 @@
7
7
  reader.context.state$.pipe(rxjs.takeUntil(reader.$.destroy$)).subscribe(({ containerElement }) => {
8
8
  if (!containerElement) return;
9
9
  const onScroll = () => {
10
- if (reader.settings.settings.computedPageTurnMode === `controlled`) {
10
+ if (reader.settings.values.computedPageTurnMode === `controlled`) {
11
11
  containerElement.scrollTo(0, 0);
12
12
  }
13
13
  };
@@ -19,98 +19,32 @@
19
19
  });
20
20
  return reader;
21
21
  };
22
- const hasOwn = Object.prototype.hasOwnProperty;
23
- const is = (x, y) => {
24
- if (x === y) {
25
- return x !== 0 || y !== 0 || 1 / x === 1 / y;
26
- } else {
27
- return false;
28
- }
29
- };
30
- const isShallowEqual = (objectA, objectB, options) => {
31
- if (objectA === objectB) {
32
- return true;
33
- }
34
- if (typeof objectA !== `object` || objectA === null) {
35
- return false;
36
- }
37
- if (typeof objectB !== `object` || objectB === null) {
38
- return false;
39
- }
40
- const keysA = Object.keys(objectA);
41
- const keysB = Object.keys(objectB);
42
- if (keysA.length !== keysB.length) {
43
- return false;
44
- }
45
- const isEqual = options && typeof options.customEqual === `function` ? options.customEqual : is;
46
- for (let i = 0; i < keysA.length; i++) {
47
- const key = keysA[i] || ``;
48
- if (!hasOwn.call(objectB, key) || !isEqual(objectA[key], objectB[key])) {
49
- return false;
50
- }
51
- }
52
- return true;
53
- };
54
- const groupBy = (list, getKey) => list.reduce(
55
- (previous, currentItem) => {
56
- const group = getKey(currentItem);
57
- if (!previous[group]) previous[group] = [];
58
- previous[group].push(currentItem);
59
- return previous;
60
- },
61
- {}
62
- );
63
- const getBase64FromBlob = (data) => {
64
- const reader = new FileReader();
65
- return new Promise((resolve) => {
66
- reader.addEventListener(
67
- `load`,
68
- function() {
69
- resolve(reader.result);
70
- },
71
- false
72
- );
73
- reader.readAsDataURL(data);
74
- });
75
- };
76
- function shallowMergeIfDefined(obj1, obj2) {
77
- const result = { ...obj1 };
78
- for (const key in obj2) {
79
- if (Object.prototype.hasOwnProperty.call(obj2, key)) {
80
- const value = obj2[key];
81
- if (value !== void 0 || !(key in obj1)) {
82
- result[key] = value;
83
- }
84
- }
85
- }
86
- return result;
87
- }
88
22
  class SettingsManagerOverload {
89
23
  constructor(initialSettings, settingsManager) {
90
24
  this.settingsManager = settingsManager;
91
- const inputSettings = shallowMergeIfDefined(
25
+ const inputSettings = shared.shallowMergeIfDefined(
92
26
  this.getDefaultSettings(),
93
27
  initialSettings
94
28
  );
95
29
  this.outputSettings = this.computeOutputSettings(inputSettings);
96
- this.inputSettings = shallowMergeIfDefined(
30
+ this.inputSettings = shared.shallowMergeIfDefined(
97
31
  this.getDefaultSettings(),
98
32
  initialSettings
99
33
  );
100
34
  this.outputSettingsUpdateSubject = new rxjs.Subject();
101
- this.settings$ = rxjs.combineLatest([
102
- this.settingsManager.settings$,
35
+ this.values$ = rxjs.combineLatest([
36
+ this.settingsManager.values$,
103
37
  this.outputSettingsUpdateSubject.pipe(operators.startWith(this.outputSettings))
104
38
  ]).pipe(
105
39
  operators.map(([parentSettings, settings]) => ({ ...parentSettings, ...settings })),
106
40
  operators.shareReplay(1)
107
41
  );
108
- this.settings$.subscribe();
42
+ this.values$.subscribe();
109
43
  }
110
44
  _prepareUpdate(settings) {
111
45
  const parentInputSettings = this.getCleanedParentInputSettings(settings);
112
46
  const parentManagerPreparedUpdate = this.settingsManager._prepareUpdate(parentInputSettings);
113
- const inputSettings = shallowMergeIfDefined(this.inputSettings, settings);
47
+ const inputSettings = shared.shallowMergeIfDefined(this.inputSettings, settings);
114
48
  const outputSettings = this.computeOutputSettings(inputSettings);
115
49
  const hasChanged = this.hasSettingsChanged(outputSettings);
116
50
  return {
@@ -133,9 +67,9 @@
133
67
  const { commit } = this._prepareUpdate(settings);
134
68
  commit();
135
69
  }
136
- get settings() {
70
+ get values() {
137
71
  return {
138
- ...this.settingsManager.settings,
72
+ ...this.settingsManager.values,
139
73
  ...this.outputSettings
140
74
  };
141
75
  }
@@ -143,12 +77,25 @@
143
77
  this.outputSettingsUpdateSubject.complete();
144
78
  }
145
79
  }
80
+ const getBase64FromBlob = (data) => {
81
+ const reader = new FileReader();
82
+ return new Promise((resolve) => {
83
+ reader.addEventListener(
84
+ `load`,
85
+ function() {
86
+ resolve(reader.result);
87
+ },
88
+ false
89
+ );
90
+ reader.readAsDataURL(data);
91
+ });
92
+ };
146
93
  let SettingsManager$2 = class SettingsManager extends SettingsManagerOverload {
147
94
  computeOutputSettings(settings) {
148
95
  return settings;
149
96
  }
150
97
  hasSettingsChanged(newOutputSettings) {
151
- return !isShallowEqual(this.outputSettings, newOutputSettings);
98
+ return !shared.isShallowEqual(this.outputSettings, newOutputSettings);
152
99
  }
153
100
  getCleanedParentInputSettings(settings) {
154
101
  const { fontJustification, fontScale, fontWeight, lineHeight, ...rest } = settings;
@@ -187,10 +134,10 @@
187
134
  */
188
135
  ``}
189
136
  body {
190
- ${settingsManager.settings.fontScale !== 1 ? `font-size: ${settingsManager.settings.fontScale}em !important;` : ``}
191
- ${settingsManager.settings.lineHeight !== `publisher` ? `line-height: ${settingsManager.settings.lineHeight} !important;` : ``}
192
- ${settingsManager.settings.fontWeight !== `publisher` ? `font-weight: ${settingsManager.settings.fontWeight} !important;` : ``}
193
- ${settingsManager.settings.fontJustification !== `publisher` ? `text-align: ${settingsManager.settings.fontJustification} !important;` : ``}
137
+ ${settingsManager.values.fontScale !== 1 ? `font-size: ${settingsManager.values.fontScale}em !important;` : ``}
138
+ ${settingsManager.values.lineHeight !== `publisher` ? `line-height: ${settingsManager.values.lineHeight} !important;` : ``}
139
+ ${settingsManager.values.fontWeight !== `publisher` ? `font-weight: ${settingsManager.values.fontWeight} !important;` : ``}
140
+ ${settingsManager.values.fontJustification !== `publisher` ? `text-align: ${settingsManager.values.fontJustification} !important;` : ``}
194
141
  }
195
142
  `;
196
143
  const applyChangeToSpineItems = (requireLayout) => {
@@ -220,7 +167,7 @@
220
167
  return false;
221
168
  })
222
169
  );
223
- settingsManager.settings$.pipe(
170
+ settingsManager.values$.pipe(
224
171
  shouldRequireLayout,
225
172
  operators.tap(applyChangeToSpineItems),
226
173
  rxjs.takeUntil(reader.$.destroy$)
@@ -238,7 +185,7 @@
238
185
  const hotkeysEnhancer = (next) => (options) => {
239
186
  const reader = next(options);
240
187
  const navigateOnKey = (document2) => rxjs.fromEvent(document2, "keyup").pipe(
241
- rxjs.withLatestFrom(reader.settings.settings$),
188
+ rxjs.withLatestFrom(reader.settings.values$),
242
189
  rxjs.map(([e, { pageTurnDirection }]) => {
243
190
  if (pageTurnDirection === "horizontal") {
244
191
  if (e.key === `ArrowRight`) {
@@ -318,8 +265,8 @@
318
265
  const resetLockViewportFree$ = createResetLock$(
319
266
  reader.navigation.viewportFree$
320
267
  ).pipe(operators.take(1));
321
- const pageTurnMode$ = reader.settings.settings$.pipe(
322
- operators.map(() => reader.settings.settings.computedPageTurnMode),
268
+ const pageTurnMode$ = reader.settings.values$.pipe(
269
+ operators.map(() => reader.settings.values.computedPageTurnMode),
323
270
  operators.distinctUntilChanged()
324
271
  );
325
272
  const handleViewportLock$ = pageTurnMode$.pipe(
@@ -395,7 +342,7 @@
395
342
  return inputSettings;
396
343
  }
397
344
  hasSettingsChanged(newOutputSettings) {
398
- return !isShallowEqual(this.outputSettings, newOutputSettings);
345
+ return !shared.isShallowEqual(this.outputSettings, newOutputSettings);
399
346
  }
400
347
  getCleanedParentInputSettings(settings) {
401
348
  const {
@@ -443,7 +390,7 @@
443
390
  ({ itemIndex, minimumWidth, isImageType }) => {
444
391
  const item = reader.spineItemsManager.get(itemIndex);
445
392
  const frame = item == null ? void 0 : item.frame;
446
- const { pageHorizontalMargin: pageHorizontalMargin2 = 0, pageVerticalMargin: pageVerticalMargin2 = 0 } = settingsManager.settings;
393
+ const { pageHorizontalMargin: pageHorizontalMargin2 = 0, pageVerticalMargin: pageVerticalMargin2 = 0 } = settingsManager.values;
447
394
  const pageSize = reader.context.getPageSize();
448
395
  if ((item == null ? void 0 : item.item.renditionLayout) === `reflowable` && (frame == null ? void 0 : frame.isReady) && !isImageType() && !frame.getViewportDimensions()) {
449
396
  let columnWidth = pageSize.width - pageHorizontalMargin2 * 2;
@@ -491,7 +438,7 @@
491
438
  resizeObserver.disconnect();
492
439
  };
493
440
  });
494
- const layoutOnContainerResize$ = settingsManager.settings$.pipe(
441
+ const layoutOnContainerResize$ = settingsManager.values$.pipe(
495
442
  operators.filter(({ layoutAutoResize: layoutAutoResize2 }) => layoutAutoResize2 === "container"),
496
443
  operators.switchMap(() => reader.context.containerElement$),
497
444
  operators.filter(isDefined),
@@ -503,9 +450,9 @@
503
450
  );
504
451
  const movingSafePan$ = createMovingSafePan$(reader);
505
452
  movingSafePan$.subscribe();
506
- settingsManager.settings$.pipe(
453
+ settingsManager.values$.pipe(
507
454
  mapKeysTo([`pageHorizontalMargin`, `pageVerticalMargin`]),
508
- operators.distinctUntilChanged(isShallowEqual),
455
+ operators.distinctUntilChanged(shared.isShallowEqual),
509
456
  operators.skip(1),
510
457
  operators.tap(() => {
511
458
  reader.layout();
@@ -709,14 +656,14 @@
709
656
  pageTurnDirection === `horizontal` ? { x: position.x + context.getPageSize().width, y: 0 } : { y: position.y + context.getPageSize().height, x: 0 }
710
657
  );
711
658
  } else {
712
- const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition(
713
- spineItemNavigationForRightPage,
659
+ const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition({
660
+ spineItemPosition: spineItemNavigationForRightPage,
714
661
  spineItem
715
- );
662
+ });
716
663
  return readingOrderPosition;
717
664
  }
718
665
  };
719
- const getNavigationForRightPage = ({
666
+ const getNavigationForRightOrBottomPage = ({
720
667
  position,
721
668
  spineItem,
722
669
  context,
@@ -822,14 +769,14 @@
822
769
  pageTurnDirection === `horizontal` ? { x: position.x - context.getPageSize().width, y: 0 } : { y: position.y - context.getPageSize().height, x: 0 }
823
770
  );
824
771
  } else {
825
- const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition(
826
- spineItemNavigation,
772
+ const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition({
773
+ spineItemPosition: spineItemNavigation,
827
774
  spineItem
828
- );
775
+ });
829
776
  return readingOrderPosition;
830
777
  }
831
778
  };
832
- const getNavigationForLeftPage = ({
779
+ const getNavigationForLeftOrTopPage = ({
833
780
  position,
834
781
  spineItem,
835
782
  context,
@@ -883,14 +830,26 @@
883
830
  this.unlock = void 0;
884
831
  }
885
832
  turnRight() {
833
+ return this.turnRightOrBottom();
834
+ }
835
+ turnLeft() {
836
+ return this.turnLeftOrTop();
837
+ }
838
+ turnTop() {
839
+ return this.turnLeftOrTop();
840
+ }
841
+ turnBottom() {
842
+ return this.turnRightOrBottom();
843
+ }
844
+ turnRightOrBottom() {
886
845
  const navigation = this.reader.navigation.getNavigation();
887
846
  const spineItem = this.reader.spineItemsManager.get(navigation.spineItem);
888
847
  if (!spineItem) return;
889
- const position = getNavigationForRightPage({
848
+ const position = getNavigationForRightOrBottomPage({
890
849
  context: this.reader.context,
891
850
  navigationResolver: this.reader.navigation.navigationResolver,
892
851
  position: navigation.position,
893
- computedPageTurnDirection: this.reader.settings.settings.computedPageTurnDirection,
852
+ computedPageTurnDirection: this.reader.settings.values.computedPageTurnDirection,
894
853
  spineItem,
895
854
  spineItemsManager: this.reader.spineItemsManager,
896
855
  spineLocator: this.reader.spine.locator
@@ -899,15 +858,15 @@
899
858
  position
900
859
  });
901
860
  }
902
- turnLeft() {
861
+ turnLeftOrTop() {
903
862
  const navigation = this.reader.navigation.getNavigation();
904
863
  const spineItem = this.reader.spineItemsManager.get(navigation.spineItem);
905
864
  if (!spineItem) return;
906
- const position = getNavigationForLeftPage({
865
+ const position = getNavigationForLeftOrTopPage({
907
866
  context: this.reader.context,
908
867
  navigationResolver: this.reader.navigation.navigationResolver,
909
868
  position: navigation.position,
910
- computedPageTurnDirection: this.reader.settings.settings.computedPageTurnDirection,
869
+ computedPageTurnDirection: this.reader.settings.values.computedPageTurnDirection,
911
870
  spineItem,
912
871
  spineItemsManager: this.reader.spineItemsManager,
913
872
  spineLocator: this.reader.spine.locator
@@ -955,7 +914,7 @@
955
914
  });
956
915
  }
957
916
  goToRightSpineItem() {
958
- if (this.reader.settings.settings.computedPageTurnDirection === "vertical") {
917
+ if (this.reader.settings.values.computedPageTurnDirection === "vertical") {
959
918
  Report.warn(
960
919
  `You cannot call this navigation method on vertical direction`
961
920
  );
@@ -967,7 +926,7 @@
967
926
  return this.goToNextSpineItem();
968
927
  }
969
928
  goToLeftSpineItem() {
970
- if (this.reader.settings.settings.computedPageTurnDirection === "vertical") {
929
+ if (this.reader.settings.values.computedPageTurnDirection === "vertical") {
971
930
  Report.warn(
972
931
  `You cannot call this navigation method on vertical direction`
973
932
  );
@@ -979,7 +938,7 @@
979
938
  return this.goToPreviousSpineItem();
980
939
  }
981
940
  goToTopSpineItem() {
982
- if (this.reader.settings.settings.computedPageTurnDirection === "horizontal") {
941
+ if (this.reader.settings.values.computedPageTurnDirection === "horizontal") {
983
942
  Report.warn(
984
943
  `You cannot call this navigation method on horizontal direction`
985
944
  );
@@ -988,7 +947,7 @@
988
947
  return this.goToPreviousSpineItem();
989
948
  }
990
949
  goToBottomSpineItem() {
991
- if (this.reader.settings.settings.computedPageTurnDirection === "horizontal") {
950
+ if (this.reader.settings.values.computedPageTurnDirection === "horizontal") {
992
951
  Report.warn(
993
952
  `You cannot call this navigation method on horizontal direction`
994
953
  );
@@ -1016,16 +975,16 @@
1016
975
  }
1017
976
  moveTo(delta, { final, start } = {}) {
1018
977
  var _a, _b, _c, _d;
1019
- if (this.reader.settings.settings.computedPageTurnMode === `scrollable`) {
978
+ if (this.reader.settings.values.computedPageTurnMode === `scrollable`) {
1020
979
  Report.warn(`pan control is not available on free page turn mode`);
1021
980
  return;
1022
981
  }
1023
- const pageTurnDirection = this.reader.settings.settings.computedPageTurnDirection;
982
+ const pageTurnDirection = this.reader.settings.values.computedPageTurnDirection;
1024
983
  if (start) {
1025
984
  (_a = this.unlock) == null ? void 0 : _a.call(this);
1026
985
  this.unlock = this.reader.navigation.lock();
1027
986
  this.lastDelta = { x: 0, y: 0 };
1028
- this.lastStartPosition = this.reader.navigation.viewportPosition;
987
+ this.lastStartPosition = this.reader.navigation.getViewportPosition();
1029
988
  this.lastPosition = this.lastStartPosition;
1030
989
  }
1031
990
  let navigation = this.reader.navigation.getNavigation().position;
@@ -1062,7 +1021,7 @@
1062
1021
  }
1063
1022
  const observeState = (reader) => {
1064
1023
  return reader.pagination.state$.pipe(
1065
- rxjs.withLatestFrom(reader.context.manifest$, reader.settings.settings$),
1024
+ rxjs.withLatestFrom(reader.context.manifest$, reader.settings.values$),
1066
1025
  rxjs.map(
1067
1026
  ([
1068
1027
  paginationInfo,
@@ -1086,7 +1045,7 @@
1086
1045
  };
1087
1046
  }
1088
1047
  ),
1089
- rxjs.distinctUntilChanged(isShallowEqual)
1048
+ rxjs.distinctUntilChanged(shared.isShallowEqual)
1090
1049
  );
1091
1050
  };
1092
1051
  const navigationEnhancer = (next) => (options) => {
@@ -1094,10 +1053,11 @@
1094
1053
  const state$ = observeState(reader);
1095
1054
  const manualNavigator = new ManualNavigator(reader);
1096
1055
  const panNavigator = new PanNavigator(reader);
1097
- const load = (manifest, loadOptions) => {
1098
- reader.load(manifest, loadOptions);
1099
- if (loadOptions.cfi) {
1100
- manualNavigator.goToCfi(loadOptions.cfi, { animate: false });
1056
+ const load = (options2) => {
1057
+ const { cfi, ...rest } = options2;
1058
+ reader.load(rest);
1059
+ if (cfi) {
1060
+ manualNavigator.goToCfi(cfi, { animate: false });
1101
1061
  }
1102
1062
  };
1103
1063
  return {
@@ -1107,6 +1067,10 @@
1107
1067
  ...reader.navigation,
1108
1068
  state$,
1109
1069
  moveTo: panNavigator.moveTo.bind(panNavigator),
1070
+ turnBottom: manualNavigator.turnBottom.bind(manualNavigator),
1071
+ turnTop: manualNavigator.turnTop.bind(manualNavigator),
1072
+ turnLeftOrTop: manualNavigator.turnLeftOrTop.bind(manualNavigator),
1073
+ turnRightOrBottom: manualNavigator.turnRightOrBottom.bind(manualNavigator),
1110
1074
  turnLeft: manualNavigator.turnLeft.bind(manualNavigator),
1111
1075
  turnRight: manualNavigator.turnRight.bind(manualNavigator),
1112
1076
  goToCfi: manualNavigator.goToCfi.bind(manualNavigator),
@@ -1191,7 +1155,7 @@
1191
1155
  });
1192
1156
  }, 0);
1193
1157
  const trackTotalPages = (reader) => {
1194
- const totalPages$ = reader.spine.layout$.pipe(
1158
+ const totalPages$ = reader.layout$.pipe(
1195
1159
  rxjs.debounceTime(10, rxjs.animationFrameScheduler),
1196
1160
  rxjs.withLatestFrom(reader.pagination.state$),
1197
1161
  rxjs.map(() => {
@@ -1207,7 +1171,7 @@
1207
1171
  )
1208
1172
  };
1209
1173
  }),
1210
- rxjs.distinctUntilChanged(isShallowEqual),
1174
+ rxjs.distinctUntilChanged(shared.isShallowEqual),
1211
1175
  rxjs.startWith({
1212
1176
  numberOfPagesPerItems: [],
1213
1177
  numberOfTotalPages: 0
@@ -1275,7 +1239,7 @@
1275
1239
  ...info,
1276
1240
  ...mapPaginationInfoToExtendedInfo(reader)(info, chaptersInfo)
1277
1241
  })),
1278
- rxjs.distinctUntilChanged(isShallowEqual)
1242
+ rxjs.distinctUntilChanged(shared.isShallowEqual)
1279
1243
  );
1280
1244
  const paginationInfo$ = rxjs.combineLatest([
1281
1245
  extandedBasePagination$,
@@ -1415,22 +1379,29 @@
1415
1379
  }
1416
1380
  };
1417
1381
  };
1418
- const createElementZoomer = (reader) => {
1419
- const isZooming$ = new rxjs.BehaviorSubject(false);
1420
- let imageMagnifierContainer;
1421
- let imgLastPosition = { x: 0, y: 0 };
1422
- let movingLastDelta = { x: 0, y: 0 };
1423
- let baseScale = 1;
1424
- let lastUserScale = 1;
1425
- const enter = (imgElement) => {
1426
- isZooming$.next(true);
1427
- imgLastPosition = { x: 0, y: 0 };
1428
- baseScale = 1;
1429
- lastUserScale = 1;
1430
- const container = reader.context.state.containerElement;
1382
+ class Zoomer {
1383
+ constructor(reader) {
1384
+ this.reader = reader;
1385
+ }
1386
+ }
1387
+ class ControllableZoomer extends Zoomer {
1388
+ constructor() {
1389
+ super(...arguments);
1390
+ this.isZooming$ = new rxjs.BehaviorSubject(false);
1391
+ this.currentScale = 1;
1392
+ this.currentPosition = { x: 0, y: 0 };
1393
+ }
1394
+ enter(element) {
1395
+ if (!element) {
1396
+ console.warn(`You need an image to enter zoom`);
1397
+ return;
1398
+ }
1399
+ this.currentPosition = { x: 0, y: 0 };
1400
+ this.currentScale = 1;
1401
+ const container = this.reader.context.state.containerElement;
1431
1402
  if (container) {
1432
- imageMagnifierContainer = container.ownerDocument.createElement(`div`);
1433
- imageMagnifierContainer.style.cssText = `
1403
+ this.element = container.ownerDocument.createElement(`div`);
1404
+ this.element.style.cssText = `
1434
1405
  top: 0;
1435
1406
  left: 0;
1436
1407
  display: block;
@@ -1441,82 +1412,45 @@
1441
1412
  height: 100%;
1442
1413
  user-select: none;
1443
1414
  `;
1444
- const clonedImgElement = imgElement.cloneNode();
1445
- clonedImgElement.src = imgElement.src;
1415
+ const clonedImgElement = element.cloneNode();
1416
+ clonedImgElement.src = element.src;
1446
1417
  clonedImgElement.style.setProperty(`height`, `100%`);
1447
1418
  clonedImgElement.style.setProperty(`width`, `100%`);
1448
1419
  clonedImgElement.style.setProperty(`object-fit`, `contain`);
1449
1420
  clonedImgElement.style.setProperty(`pointer-events`, `none`);
1450
- imageMagnifierContainer.appendChild(clonedImgElement);
1451
- container.appendChild(imageMagnifierContainer);
1452
- }
1453
- scale(1.2);
1454
- setCurrentScaleAsBase();
1455
- };
1456
- const setCurrentScaleAsBase = () => {
1457
- baseScale = lastUserScale;
1458
- };
1459
- const scale = (userScale) => {
1460
- const imgElement = imageMagnifierContainer == null ? void 0 : imageMagnifierContainer.querySelector(`img`);
1461
- const roundedScale = Math.ceil(
1462
- (userScale < 1 ? baseScale - (1 - userScale) : baseScale + (userScale - 1)) * 100
1463
- ) / 100;
1464
- const newScale = Math.max(roundedScale, 1);
1465
- if (roundedScale < 1) {
1466
- imgLastPosition = { x: 0, y: 0 };
1421
+ this.element.appendChild(clonedImgElement);
1422
+ container.appendChild(this.element);
1423
+ this.isZooming$.next(true);
1467
1424
  }
1425
+ }
1426
+ exit() {
1427
+ var _a;
1428
+ (_a = this.element) == null ? void 0 : _a.remove();
1429
+ this.element = void 0;
1430
+ this.currentPosition = { x: 0, y: 0 };
1431
+ this.currentScale = 1;
1432
+ this.isZooming$.next(false);
1433
+ }
1434
+ moveAt(position) {
1435
+ var _a;
1436
+ const imgElement = (_a = this.element) == null ? void 0 : _a.querySelector(`img`);
1468
1437
  imgElement == null ? void 0 : imgElement.style.setProperty(
1469
1438
  `transform`,
1470
- `translate3d(${imgLastPosition.x}px, ${imgLastPosition.y}px, 0px) scale3d(${newScale}, ${newScale}, 1)`
1439
+ `translate3d(${position.x}px, ${position.y}px, 0px) scale3d(${this.currentScale}, ${this.currentScale}, 1)`
1471
1440
  );
1472
- lastUserScale = newScale;
1473
- };
1474
- const move = (delta, { isFirst, isLast }) => {
1475
- const imgElement = imageMagnifierContainer == null ? void 0 : imageMagnifierContainer.querySelector(`img`);
1476
- if (isFirst) {
1477
- movingLastDelta = delta;
1478
- }
1479
- if (delta) {
1480
- const newOffsetX = delta.x - ((movingLastDelta == null ? void 0 : movingLastDelta.x) || 0);
1481
- const newOffsetY = delta.y - ((movingLastDelta == null ? void 0 : movingLastDelta.y) || 0);
1482
- imgLastPosition = {
1483
- x: imgLastPosition.x + newOffsetX,
1484
- y: imgLastPosition.y + newOffsetY
1485
- };
1486
- imgElement == null ? void 0 : imgElement.style.setProperty(
1487
- `transform`,
1488
- `translate3d(${imgLastPosition.x}px, ${imgLastPosition.y}px, 0px) scale3d(${baseScale}, ${baseScale}, 1)`
1489
- );
1490
- movingLastDelta = delta;
1491
- }
1492
- if (isLast) {
1493
- movingLastDelta = void 0;
1494
- }
1495
- };
1496
- const exit = () => {
1497
- lastUserScale = 1;
1498
- imageMagnifierContainer == null ? void 0 : imageMagnifierContainer.remove();
1499
- imageMagnifierContainer = void 0;
1500
- isZooming$.next(false);
1501
- };
1502
- const _isZooming = () => isZooming$.value;
1503
- const destroy = () => {
1504
- imageMagnifierContainer == null ? void 0 : imageMagnifierContainer.remove();
1505
- imageMagnifierContainer = void 0;
1506
- isZooming$.complete();
1507
- };
1508
- return {
1509
- enter,
1510
- exit,
1511
- move,
1512
- scale,
1513
- setCurrentScaleAsBase,
1514
- getScaleValue: () => lastUserScale,
1515
- isZooming: _isZooming,
1516
- destroy,
1517
- isZooming$: isZooming$.asObservable()
1518
- };
1519
- };
1441
+ this.currentPosition = position;
1442
+ }
1443
+ scaleAt(userScale) {
1444
+ var _a;
1445
+ const computedScale = Math.max(0.01, userScale);
1446
+ const imgElement = (_a = this.element) == null ? void 0 : _a.querySelector(`img`);
1447
+ imgElement == null ? void 0 : imgElement.style.setProperty(
1448
+ `transform`,
1449
+ `translate3d(${this.currentPosition.x}px, ${this.currentPosition.y}px, 0px) scale3d(${computedScale}, ${computedScale}, 1)`
1450
+ );
1451
+ this.currentScale = computedScale;
1452
+ }
1453
+ }
1520
1454
  const getNewScaledOffset = ({
1521
1455
  newScale,
1522
1456
  oldScale,
@@ -1529,35 +1463,33 @@
1529
1463
  const realScrollOffset = scrollOffset - oldCenterPosition;
1530
1464
  return Math.max(centerXPosition + realScrollOffset * scaleDifference, 0);
1531
1465
  };
1532
- const createViewportZoomer = (reader) => {
1533
- const isZooming$ = new rxjs.BehaviorSubject(false);
1534
- let baseScale = 1;
1535
- let lastUserScale = 1;
1536
- const reset = () => {
1537
- scale(0 - baseScale);
1538
- lastUserScale = 1;
1539
- baseScale = 1;
1540
- };
1541
- const enter = () => {
1542
- reset();
1543
- const spineElement = reader.spine.element;
1466
+ class ScrollableZoomer extends Zoomer {
1467
+ constructor() {
1468
+ super(...arguments);
1469
+ this.isZooming$ = new rxjs.BehaviorSubject(false);
1470
+ this.currentScale = 1;
1471
+ this.currentPosition = { x: 0, y: 0 };
1472
+ }
1473
+ enter() {
1474
+ this.currentScale = 1;
1475
+ this.currentPosition = { x: 0, y: 0 };
1476
+ const spineElement = this.reader.spine.element;
1544
1477
  if (spineElement) {
1545
1478
  spineElement.style.transformOrigin = `0 0`;
1546
1479
  }
1547
- isZooming$.next(true);
1548
- scale(1);
1549
- setCurrentScaleAsBase();
1550
- };
1551
- const setCurrentScaleAsBase = () => {
1552
- baseScale = lastUserScale;
1553
- };
1554
- const scale = (userScale) => {
1555
- const spineElement = reader.spine.element;
1556
- const viewportElement = reader.navigation.getElement();
1480
+ this.isZooming$.next(true);
1481
+ }
1482
+ exit() {
1483
+ this.scaleAt(1);
1484
+ this.isZooming$.next(false);
1485
+ }
1486
+ moveAt() {
1487
+ }
1488
+ scaleAt(userScale) {
1489
+ const spineElement = this.reader.spine.element;
1490
+ const viewportElement = this.reader.navigation.getElement();
1557
1491
  if (!spineElement || !viewportElement) return;
1558
- const roundedScale = Math.ceil(
1559
- (userScale < 1 ? baseScale - (1 - userScale) : baseScale + (userScale - 1)) * 100
1560
- ) / 100;
1492
+ const roundedScale = Math.ceil(userScale * 100) / 100;
1561
1493
  const newScale = Math.max(roundedScale, 1);
1562
1494
  const currentScale = spineElement.getBoundingClientRect().width / spineElement.offsetWidth;
1563
1495
  const currentScrollTop = viewportElement.scrollTop;
@@ -1576,75 +1508,23 @@
1576
1508
  screenSize: spineElement.offsetHeight,
1577
1509
  scrollOffset: currentScrollTop
1578
1510
  });
1579
- lastUserScale = newScale;
1580
- };
1581
- const move = (_, __) => {
1582
- };
1583
- const exit = () => {
1584
- reset();
1585
- isZooming$.next(false);
1586
- };
1587
- const _isZooming = () => isZooming$.value;
1588
- const destroy = () => {
1589
- isZooming$.complete();
1590
- };
1591
- return {
1592
- enter,
1593
- exit,
1594
- move,
1595
- scale,
1596
- setCurrentScaleAsBase,
1597
- getScaleValue: () => lastUserScale,
1598
- isZooming: _isZooming,
1599
- destroy,
1600
- isZooming$: isZooming$.asObservable()
1601
- };
1602
- };
1511
+ this.currentScale = roundedScale;
1512
+ }
1513
+ }
1603
1514
  const zoomEnhancer = (next) => (options) => {
1604
1515
  const reader = next(options);
1605
- const elementZoomer = createElementZoomer(reader);
1606
- const viewportZoomer = createViewportZoomer(reader);
1607
- const currentZoomerSubject$ = new rxjs.BehaviorSubject(void 0);
1608
- const isUsingScrollableViewport = () => reader.settings.settings.computedPageTurnMode === `scrollable`;
1609
- const enter = (imgElement) => {
1610
- var _a;
1611
- (_a = currentZoomerSubject$ == null ? void 0 : currentZoomerSubject$.value) == null ? void 0 : _a.exit();
1612
- if (isUsingScrollableViewport()) {
1613
- viewportZoomer.enter();
1614
- currentZoomerSubject$ == null ? void 0 : currentZoomerSubject$.next(viewportZoomer);
1615
- return;
1616
- }
1617
- if (!imgElement) {
1618
- Report.warn(`You should specify an element to zoom at`);
1619
- return;
1620
- }
1621
- elementZoomer.enter(imgElement);
1622
- currentZoomerSubject$ == null ? void 0 : currentZoomerSubject$.next(elementZoomer);
1623
- };
1624
- const setCurrentScaleAsBase = () => {
1625
- var _a;
1626
- (_a = currentZoomerSubject$.value) == null ? void 0 : _a.setCurrentScaleAsBase();
1627
- };
1628
- const scale = (userScale) => {
1629
- var _a;
1630
- if (!((_a = currentZoomerSubject$.value) == null ? void 0 : _a.isZooming())) {
1631
- Report.warn(`You need to start zoom before being able to call this fn`);
1632
- return;
1633
- }
1634
- currentZoomerSubject$.value.scale(userScale);
1635
- };
1636
- const move = (delta, options2) => {
1637
- var _a;
1638
- (_a = currentZoomerSubject$.value) == null ? void 0 : _a.move(delta, options2);
1639
- };
1640
- const exit = () => {
1641
- var _a;
1642
- (_a = currentZoomerSubject$.value) == null ? void 0 : _a.exit();
1516
+ const controllableZoomer = new ControllableZoomer(reader);
1517
+ const scrollableZoomer = new ScrollableZoomer(reader);
1518
+ const zoomerSubject = new rxjs.BehaviorSubject(scrollableZoomer);
1519
+ const enter = (element) => {
1520
+ const zoomer = reader.settings.values.computedPageTurnMode === `scrollable` ? scrollableZoomer : controllableZoomer;
1521
+ zoomerSubject.next(zoomer);
1522
+ zoomer.enter(element);
1643
1523
  };
1644
1524
  const destroy = () => {
1645
- elementZoomer.destroy();
1646
- viewportZoomer.destroy();
1647
- currentZoomerSubject$.complete();
1525
+ controllableZoomer.exit();
1526
+ scrollableZoomer.exit();
1527
+ zoomerSubject.complete();
1648
1528
  reader.destroy();
1649
1529
  };
1650
1530
  return {
@@ -1652,23 +1532,23 @@
1652
1532
  destroy,
1653
1533
  zoom: {
1654
1534
  enter,
1655
- exit,
1656
- move,
1657
- isZooming: () => {
1658
- var _a;
1659
- return ((_a = currentZoomerSubject$.value) == null ? void 0 : _a.isZooming()) || false;
1535
+ scaleAt: (scale) => zoomerSubject.getValue().scaleAt(scale),
1536
+ moveAt: (position) => zoomerSubject.getValue().moveAt(position),
1537
+ exit: () => zoomerSubject.getValue().exit(),
1538
+ get currentPosition() {
1539
+ return zoomerSubject.getValue().currentPosition;
1660
1540
  },
1661
- getScaleValue: () => {
1662
- var _a;
1663
- return ((_a = currentZoomerSubject$.value) == null ? void 0 : _a.getScaleValue()) || 1;
1541
+ get currentScale() {
1542
+ return zoomerSubject.getValue().currentScale;
1664
1543
  },
1665
- scale,
1666
- isUsingScrollableZoom: isUsingScrollableViewport,
1667
- setCurrentScaleAsBase,
1668
- $: {
1669
- isZooming$: currentZoomerSubject$.pipe(
1670
- rxjs.switchMap((zoomer) => (zoomer == null ? void 0 : zoomer.isZooming$) || rxjs.of(false))
1671
- )
1544
+ isZooming$: zoomerSubject.pipe(
1545
+ rxjs.switchMap((zoomer) => zoomer.isZooming$)
1546
+ ),
1547
+ get zoomContainerElement() {
1548
+ return zoomerSubject.getValue().element;
1549
+ },
1550
+ get isZooming() {
1551
+ return zoomerSubject.getValue().isZooming$.getValue();
1672
1552
  }
1673
1553
  }
1674
1554
  };
@@ -1725,7 +1605,7 @@
1725
1605
  });
1726
1606
  this.bridgeEvent = new BridgeEvent();
1727
1607
  this.destroy$ = new rxjs.Subject();
1728
- this.state$ = this._stateSubject.pipe(operators.distinctUntilChanged(isShallowEqual));
1608
+ this.state$ = this._stateSubject.pipe(operators.distinctUntilChanged(shared.isShallowEqual));
1729
1609
  this.manifest$ = this._stateSubject.pipe(
1730
1610
  operators.map((state) => state.manifest),
1731
1611
  operators.filter(isDefined),
@@ -1782,7 +1662,7 @@
1782
1662
  forceSinglePageMode
1783
1663
  })
1784
1664
  };
1785
- if (!isShallowEqual(newCompleteState, previousState)) {
1665
+ if (!shared.isShallowEqual(newCompleteState, previousState)) {
1786
1666
  this._stateSubject.next(newCompleteState);
1787
1667
  }
1788
1668
  }
@@ -1833,7 +1713,7 @@
1833
1713
  navigationId: void 0
1834
1714
  });
1835
1715
  this.state$ = this.paginationSubject.pipe(
1836
- rxjs.distinctUntilChanged(isShallowEqual),
1716
+ rxjs.distinctUntilChanged(shared.isShallowEqual),
1837
1717
  rxjs.tap((value) => {
1838
1718
  report$3.info(`update`, value);
1839
1719
  }),
@@ -1854,7 +1734,6 @@
1854
1734
  this.paginationSubject.complete();
1855
1735
  }
1856
1736
  }
1857
- const __UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY = `__UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT`;
1858
1737
  const ITEM_EXTENSION_VALID_FOR_FRAME_SRC = [`.xhtml`, `.html`, `.htm`];
1859
1738
  const HTML_PREFIX$1 = `prose-reader`;
1860
1739
  const pointerEvents$1 = [
@@ -2039,6 +1918,80 @@
2039
1918
  return offsetValues[offsetValues.length - 1] || 0;
2040
1919
  return offsetValues.find((offsetRange) => offset < offsetRange + pageWidth) || 0;
2041
1920
  };
1921
+ const getSpineItemNumberOfPages = ({
1922
+ itemHeight,
1923
+ itemWidth,
1924
+ isUsingVerticalWriting,
1925
+ settings,
1926
+ context
1927
+ }) => {
1928
+ const { pageTurnDirection, pageTurnMode } = settings.values;
1929
+ if (pageTurnDirection === `vertical` && pageTurnMode === `scrollable`) {
1930
+ return 1;
1931
+ }
1932
+ if (isUsingVerticalWriting || pageTurnDirection === `vertical`) {
1933
+ return calculateNumberOfPagesForItem(
1934
+ itemHeight,
1935
+ context.getPageSize().height
1936
+ );
1937
+ }
1938
+ return calculateNumberOfPagesForItem(itemWidth, context.getPageSize().width);
1939
+ };
1940
+ const getSpineItemPositionFromPageIndex = ({
1941
+ pageIndex,
1942
+ itemLayout,
1943
+ context,
1944
+ isUsingVerticalWriting
1945
+ }) => {
1946
+ if (isUsingVerticalWriting) {
1947
+ const ltrRelativeOffset2 = getItemOffsetFromPageIndex(
1948
+ context.getPageSize().height,
1949
+ pageIndex,
1950
+ itemLayout.height
1951
+ );
1952
+ return {
1953
+ x: 0,
1954
+ y: ltrRelativeOffset2
1955
+ };
1956
+ }
1957
+ const ltrRelativeOffset = getItemOffsetFromPageIndex(
1958
+ context.getPageSize().width,
1959
+ pageIndex,
1960
+ itemLayout.width
1961
+ );
1962
+ if (context.isRTL()) {
1963
+ return {
1964
+ x: itemLayout.width - ltrRelativeOffset - context.getPageSize().width,
1965
+ y: 0
1966
+ };
1967
+ }
1968
+ return {
1969
+ x: ltrRelativeOffset,
1970
+ y: 0
1971
+ };
1972
+ };
1973
+ const getSpineItemPagesPosition = ({
1974
+ context,
1975
+ isUsingVerticalWriting,
1976
+ settings,
1977
+ itemLayout
1978
+ }) => {
1979
+ const numberOfPages = getSpineItemNumberOfPages({
1980
+ context,
1981
+ isUsingVerticalWriting,
1982
+ itemHeight: itemLayout.height,
1983
+ itemWidth: itemLayout.width,
1984
+ settings
1985
+ });
1986
+ return new Array(numberOfPages).fill(void 0).map(
1987
+ (_, pageIndex) => getSpineItemPositionFromPageIndex({
1988
+ context,
1989
+ isUsingVerticalWriting,
1990
+ itemLayout,
1991
+ pageIndex
1992
+ })
1993
+ );
1994
+ };
2042
1995
  const createSpineItemLocator = ({
2043
1996
  context,
2044
1997
  settings
@@ -2051,52 +2004,6 @@
2051
2004
  x: Math.min(itemWidth, Math.max(0, spineItemPosition.x)),
2052
2005
  y: Math.min(itemHeight, Math.max(0, spineItemPosition.y))
2053
2006
  });
2054
- const getSpineItemNumberOfPages = ({
2055
- itemHeight,
2056
- itemWidth,
2057
- isUsingVerticalWriting
2058
- }) => {
2059
- const { pageTurnDirection, pageTurnMode } = settings.settings;
2060
- if (pageTurnDirection === `vertical` && pageTurnMode === `scrollable`) {
2061
- return 1;
2062
- }
2063
- if (isUsingVerticalWriting || pageTurnDirection === `vertical`) {
2064
- return calculateNumberOfPagesForItem(
2065
- itemHeight,
2066
- context.getPageSize().height
2067
- );
2068
- }
2069
- return calculateNumberOfPagesForItem(itemWidth, context.getPageSize().width);
2070
- };
2071
- const getSpineItemPositionFromPageIndex = (pageIndex, spineItem) => {
2072
- const { width: itemWidth, height: itemHeight } = spineItem.getElementDimensions();
2073
- if (spineItem.isUsingVerticalWriting()) {
2074
- const ltrRelativeOffset2 = getItemOffsetFromPageIndex(
2075
- context.getPageSize().height,
2076
- pageIndex,
2077
- itemHeight
2078
- );
2079
- return {
2080
- x: 0,
2081
- y: ltrRelativeOffset2
2082
- };
2083
- }
2084
- const ltrRelativeOffset = getItemOffsetFromPageIndex(
2085
- context.getPageSize().width,
2086
- pageIndex,
2087
- itemWidth
2088
- );
2089
- if (context.isRTL()) {
2090
- return {
2091
- x: itemWidth - ltrRelativeOffset - context.getPageSize().width,
2092
- y: 0
2093
- };
2094
- }
2095
- return {
2096
- x: ltrRelativeOffset,
2097
- y: 0
2098
- };
2099
- };
2100
2007
  const getSpineItemPageIndexFromPosition = ({
2101
2008
  itemWidth,
2102
2009
  itemHeight,
@@ -2114,7 +2021,9 @@
2114
2021
  const numberOfPages = getSpineItemNumberOfPages({
2115
2022
  isUsingVerticalWriting,
2116
2023
  itemHeight,
2117
- itemWidth
2024
+ itemWidth,
2025
+ context,
2026
+ settings
2118
2027
  });
2119
2028
  if (isUsingVerticalWriting) {
2120
2029
  return getPageFromOffset(position.y, pageHeight, numberOfPages);
@@ -2134,7 +2043,7 @@
2134
2043
  }
2135
2044
  const spineItemWidth = ((_a = spineItem.getElementDimensions()) == null ? void 0 : _a.width) || 0;
2136
2045
  const pageWidth = context.getPageSize().width;
2137
- if (offsetOfNodeInSpineItem) {
2046
+ if (offsetOfNodeInSpineItem !== void 0) {
2138
2047
  const val = getClosestValidOffsetFromApproximateOffsetInPages(
2139
2048
  offsetOfNodeInSpineItem,
2140
2049
  pageWidth,
@@ -2150,10 +2059,12 @@
2150
2059
  const frame = (_a = spineItem.frame) == null ? void 0 : _a.element;
2151
2060
  if (((_b = frame == null ? void 0 : frame.contentWindow) == null ? void 0 : _b.document) && // very important because it is being used by next functions
2152
2061
  frame.contentWindow.document.body !== null) {
2153
- const { x: left, y: top } = getSpineItemPositionFromPageIndex(
2062
+ const { x: left, y: top } = getSpineItemPositionFromPageIndex({
2154
2063
  pageIndex,
2155
- spineItem
2156
- );
2064
+ itemLayout: spineItem.getElementDimensions(),
2065
+ context,
2066
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting()
2067
+ });
2157
2068
  const viewport = {
2158
2069
  left,
2159
2070
  right: left + pageSize.width,
@@ -2205,12 +2116,33 @@
2205
2116
  };
2206
2117
  return {
2207
2118
  getSpineItemPositionFromNode,
2208
- getSpineItemPositionFromPageIndex,
2119
+ getSpineItemPositionFromPageIndex: ({
2120
+ pageIndex,
2121
+ itemLayout,
2122
+ isUsingVerticalWriting
2123
+ }) => getSpineItemPositionFromPageIndex({
2124
+ context,
2125
+ isUsingVerticalWriting,
2126
+ itemLayout,
2127
+ pageIndex
2128
+ }),
2209
2129
  getSpineItemPageIndexFromPosition,
2210
2130
  getSpineItemPageIndexFromNode,
2211
2131
  getSpineItemClosestPositionFromUnsafePosition,
2212
2132
  getFirstNodeOrRangeAtPage,
2213
- getSpineItemNumberOfPages
2133
+ getSpineItemPagesPosition: ({ item }) => {
2134
+ return getSpineItemPagesPosition({
2135
+ context,
2136
+ isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
2137
+ settings,
2138
+ itemLayout: item.getElementDimensions()
2139
+ });
2140
+ },
2141
+ getSpineItemNumberOfPages: (params) => getSpineItemNumberOfPages({
2142
+ context,
2143
+ settings,
2144
+ ...params
2145
+ })
2214
2146
  };
2215
2147
  };
2216
2148
  const createNavigationResolver$1 = ({
@@ -2225,10 +2157,11 @@
2225
2157
  itemHeight: height,
2226
2158
  itemWidth: width
2227
2159
  });
2228
- return spineItemLocator.getSpineItemPositionFromPageIndex(
2229
- numberOfPages - 1,
2230
- spineItem
2231
- );
2160
+ return spineItemLocator.getSpineItemPositionFromPageIndex({
2161
+ pageIndex: numberOfPages - 1,
2162
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
2163
+ itemLayout: spineItem.getElementDimensions()
2164
+ });
2232
2165
  };
2233
2166
  const getNavigationFromNode = (spineItem, node, offset) => {
2234
2167
  const position = spineItemLocator.getSpineItemPositionFromNode(
@@ -2265,10 +2198,13 @@
2265
2198
  isRTL,
2266
2199
  pageSizeHeight,
2267
2200
  spineItemsManager,
2268
- visibleAreaRectWidth
2201
+ visibleAreaRectWidth,
2202
+ spineLayout
2269
2203
  }) => {
2270
- const lastSpineItem = spineItemsManager.get(spineItemsManager.getLength() - 1);
2271
- const distanceOfLastSpineItem = spineItemsManager.getAbsolutePositionOf(
2204
+ const lastSpineItem = spineItemsManager.get(
2205
+ spineItemsManager.items.length - 1
2206
+ );
2207
+ const distanceOfLastSpineItem = spineLayout.getAbsolutePositionOf(
2272
2208
  lastSpineItem || 0
2273
2209
  );
2274
2210
  const maximumYOffset = distanceOfLastSpineItem.bottom - pageSizeHeight;
@@ -2312,10 +2248,10 @@
2312
2248
  spineItem,
2313
2249
  context
2314
2250
  });
2315
- const position = spineLocator.getSpinePositionFromSpineItemPosition(
2316
- { x: spineItemOffset, y: 0 },
2251
+ const position = spineLocator.getSpinePositionFromSpineItemPosition({
2252
+ spineItemPosition: { x: spineItemOffset, y: 0 },
2317
2253
  spineItem
2318
- );
2254
+ });
2319
2255
  return position;
2320
2256
  };
2321
2257
  const getNavigationForAnchor = ({
@@ -2391,10 +2327,10 @@
2391
2327
  spineItemPosition,
2392
2328
  spineItem
2393
2329
  );
2394
- const spinePosition = spineLocator.getSpinePositionFromSpineItemPosition(
2395
- navigationInSpineItem,
2330
+ const spinePosition = spineLocator.getSpinePositionFromSpineItemPosition({
2331
+ spineItemPosition: navigationInSpineItem,
2396
2332
  spineItem
2397
- );
2333
+ });
2398
2334
  return getAdjustedPositionForSpread({
2399
2335
  position: spinePosition,
2400
2336
  pageSizeWidth: context.getPageSize().width,
@@ -2417,10 +2353,10 @@
2417
2353
  spineItem,
2418
2354
  spineItemPosition
2419
2355
  );
2420
- const viewportNavigation = spineLocator.getSpinePositionFromSpineItemPosition(
2421
- spineItemValidPosition,
2356
+ const viewportNavigation = spineLocator.getSpinePositionFromSpineItemPosition({
2357
+ spineItemPosition: spineItemValidPosition,
2422
2358
  spineItem
2423
- );
2359
+ });
2424
2360
  return getAdjustedPositionForSpread({
2425
2361
  position: viewportNavigation,
2426
2362
  pageSizeWidth: context.getPageSize().width,
@@ -2447,14 +2383,15 @@
2447
2383
  spineLocator
2448
2384
  });
2449
2385
  }
2450
- const spineItemNavigation = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex(
2386
+ const spineItemNavigation = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
2451
2387
  pageIndex,
2388
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
2389
+ itemLayout: spineItem.getElementDimensions()
2390
+ });
2391
+ const readingOffset = spineLocator.getSpinePositionFromSpineItemPosition({
2392
+ spineItemPosition: spineItemNavigation,
2452
2393
  spineItem
2453
- );
2454
- const readingOffset = spineLocator.getSpinePositionFromSpineItemPosition(
2455
- spineItemNavigation,
2456
- spineItem
2457
- );
2394
+ });
2458
2395
  return getAdjustedPositionForSpread({
2459
2396
  position: readingOffset,
2460
2397
  pageSizeWidth: context.getPageSize().width,
@@ -3337,16 +3274,23 @@
3337
3274
  if (doc) {
3338
3275
  try {
3339
3276
  const { node, offset: resolvedOffset } = cfiHandler.resolve(doc, {});
3340
- return { node, offset: offset ?? resolvedOffset, spineItemIndex };
3277
+ return {
3278
+ node,
3279
+ offset: offset ?? resolvedOffset,
3280
+ spineItemIndex,
3281
+ spineItem
3282
+ };
3341
3283
  } catch (e) {
3342
3284
  Report.error(e);
3343
3285
  return {
3344
- spineItemIndex
3286
+ spineItemIndex,
3287
+ spineItem
3345
3288
  };
3346
3289
  }
3347
3290
  }
3348
3291
  return {
3349
- spineItemIndex
3292
+ spineItemIndex,
3293
+ spineItem
3350
3294
  };
3351
3295
  };
3352
3296
  const NAMESPACE$4 = `spineNavigator`;
@@ -3354,7 +3298,8 @@
3354
3298
  context,
3355
3299
  spineItemsManager,
3356
3300
  locator,
3357
- settings
3301
+ settings,
3302
+ spineLayout
3358
3303
  }) => {
3359
3304
  const spineItemNavigator = createNavigationResolver$1({ context, settings });
3360
3305
  const arePositionsDifferent = (a, b) => a.x !== b.x || a.y !== b.y;
@@ -3369,10 +3314,10 @@
3369
3314
  Report.warn(NAMESPACE$4, `unable to detect item id from cfi ${cfi}`);
3370
3315
  } else {
3371
3316
  const spineItemNavigation = node ? spineItemNavigator.getNavigationFromNode(spineItem, node, offset) : { x: 0, y: 0 };
3372
- const readingPosition = locator.getSpinePositionFromSpineItemPosition(
3373
- spineItemNavigation,
3317
+ const readingPosition = locator.getSpinePositionFromSpineItemPosition({
3318
+ spineItemPosition: spineItemNavigation,
3374
3319
  spineItem
3375
- );
3320
+ });
3376
3321
  return getAdjustedPositionForSpread({
3377
3322
  position: readingPosition,
3378
3323
  pageSizeWidth: context.getPageSize().width,
@@ -3383,10 +3328,10 @@
3383
3328
  };
3384
3329
  const getNavigationForLastPage = (spineItem) => {
3385
3330
  const spineItemNavigation = spineItemNavigator.getNavigationForLastPage(spineItem);
3386
- const position = locator.getSpinePositionFromSpineItemPosition(
3387
- spineItemNavigation,
3331
+ const position = locator.getSpinePositionFromSpineItemPosition({
3332
+ spineItemPosition: spineItemNavigation,
3388
3333
  spineItem
3389
- );
3334
+ });
3390
3335
  return getAdjustedPositionForSpread({
3391
3336
  position,
3392
3337
  pageSizeWidth: context.getPageSize().width,
@@ -3406,7 +3351,7 @@
3406
3351
  return { x: 0, y: 0 };
3407
3352
  };
3408
3353
  const getMostPredominantNavigationForPosition = (viewportPosition) => {
3409
- const pageTurnDirection = settings.settings.computedPageTurnDirection;
3354
+ const pageTurnDirection = settings.values.computedPageTurnDirection;
3410
3355
  const triggerPercentage = 0.5;
3411
3356
  const triggerXPosition = pageTurnDirection === `horizontal` ? viewportPosition.x + context.state.visibleAreaRect.width * triggerPercentage : 0;
3412
3357
  const triggerYPosition = pageTurnDirection === `horizontal` ? 0 : viewportPosition.y + context.state.visibleAreaRect.height * triggerPercentage;
@@ -3418,7 +3363,8 @@
3418
3363
  isRTL: context.isRTL(),
3419
3364
  pageSizeHeight: context.getPageSize().height,
3420
3365
  visibleAreaRectWidth: context.state.visibleAreaRect.width,
3421
- spineItemsManager
3366
+ spineItemsManager,
3367
+ spineLayout
3422
3368
  });
3423
3369
  return getNavigationForPosition({
3424
3370
  context,
@@ -3428,7 +3374,7 @@
3428
3374
  });
3429
3375
  };
3430
3376
  const isNavigationGoingForwardFrom = (to, from) => {
3431
- const pageTurnDirection = settings.settings.computedPageTurnDirection;
3377
+ const pageTurnDirection = settings.values.computedPageTurnDirection;
3432
3378
  if (pageTurnDirection === `vertical`) {
3433
3379
  return to.y > from.y;
3434
3380
  }
@@ -3471,7 +3417,8 @@
3471
3417
  isRTL: context.isRTL(),
3472
3418
  pageSizeHeight: context.getPageSize().height,
3473
3419
  visibleAreaRectWidth: context.state.visibleAreaRect.width,
3474
- spineItemsManager
3420
+ spineItemsManager,
3421
+ spineLayout
3475
3422
  }),
3476
3423
  isNavigationGoingForwardFrom,
3477
3424
  areNavigationDifferent,
@@ -3486,10 +3433,9 @@
3486
3433
  };
3487
3434
  const getScaledDownPosition = ({
3488
3435
  position: { x, y },
3489
- spine,
3436
+ spineElement,
3490
3437
  element
3491
3438
  }) => {
3492
- const spineElement = spine.element;
3493
3439
  if (!spineElement) throw new Error("Invalid spine element");
3494
3440
  const spineScaleX = spineElement.getBoundingClientRect().width / spineElement.offsetWidth;
3495
3441
  const scaledDownPosition = {
@@ -3523,13 +3469,13 @@
3523
3469
  this.navigateSubject = new rxjs.Subject();
3524
3470
  this.scrollingSubject = new rxjs.BehaviorSubject(false);
3525
3471
  this.isScrolling$ = this.scrollingSubject.asObservable();
3526
- const settingsThatRequireLayout$ = settings.settings$.pipe(
3472
+ const settingsThatRequireLayout$ = settings.values$.pipe(
3527
3473
  mapKeysTo([
3528
3474
  `computedPageTurnDirection`,
3529
3475
  `computedPageTurnMode`,
3530
3476
  `numberOfAdjacentSpineItemToPreLoad`
3531
3477
  ]),
3532
- rxjs.distinctUntilChanged(isShallowEqual)
3478
+ rxjs.distinctUntilChanged(shared.isShallowEqual)
3533
3479
  );
3534
3480
  const updateElementOnSettingsChange$ = rxjs.merge(
3535
3481
  settingsThatRequireLayout$,
@@ -3537,7 +3483,7 @@
3537
3483
  ).pipe(
3538
3484
  rxjs.withLatestFrom(this.viewportElement$),
3539
3485
  rxjs.tap(([, element]) => {
3540
- if (settings.settings.computedPageTurnMode === `scrollable`) {
3486
+ if (settings.values.computedPageTurnMode === `scrollable`) {
3541
3487
  element.style.removeProperty(`transform`);
3542
3488
  element.style.removeProperty(`transition`);
3543
3489
  element.style.overflow = `scroll`;
@@ -3549,7 +3495,7 @@
3549
3495
  );
3550
3496
  this.layout$ = updateElementOnSettingsChange$.pipe(
3551
3497
  rxjs.tap(() => {
3552
- report$2.info(`layout`, settings.settings);
3498
+ report$2.info(`layout`, settings.values);
3553
3499
  }),
3554
3500
  rxjs.share()
3555
3501
  );
@@ -3560,7 +3506,7 @@
3560
3506
  );
3561
3507
  this.isNavigating$ = navigate$.pipe(
3562
3508
  rxjs.map(({ animation, position }) => {
3563
- const shouldAnimate = !(!animation || animation === `turn` && settings.settings.computedPageTurnAnimation === `none`);
3509
+ const shouldAnimate = !(!animation || animation === `turn` && settings.values.computedPageTurnAnimation === `none`);
3564
3510
  return {
3565
3511
  type: `manualAdjust`,
3566
3512
  shouldAnimate,
@@ -3577,8 +3523,8 @@
3577
3523
  rxjs.of(null).pipe(
3578
3524
  rxjs.mergeMap(() => {
3579
3525
  if ((currentEvent == null ? void 0 : currentEvent.type) !== `manualAdjust`) return rxjs.of(false);
3580
- const animationDuration = currentEvent.animation === `snap` ? settings.settings.snapAnimationDuration : settings.settings.computedPageTurnAnimationDuration;
3581
- const pageTurnAnimation = currentEvent.animation === `snap` ? `slide` : settings.settings.computedPageTurnAnimation;
3526
+ const animationDuration = currentEvent.animation === `snap` ? settings.values.snapAnimationDuration : settings.values.computedPageTurnAnimationDuration;
3527
+ const pageTurnAnimation = currentEvent.animation === `snap` ? `slide` : settings.values.computedPageTurnAnimation;
3582
3528
  return rxjs.of(currentEvent).pipe(
3583
3529
  /**
3584
3530
  * @important
@@ -3659,7 +3605,7 @@
3659
3605
  */
3660
3606
  setViewportPosition({ x, y }) {
3661
3607
  const element = this.viewportElement$.getValue();
3662
- if (this.settings.settings.computedPageTurnMode === `scrollable`) {
3608
+ if (this.settings.values.computedPageTurnMode === `scrollable`) {
3663
3609
  this.scrollingSubject.next(true);
3664
3610
  element.scrollTo({ left: x, top: y, behavior: "instant" });
3665
3611
  rxjs.timer(1).pipe(
@@ -3678,14 +3624,14 @@
3678
3624
  }
3679
3625
  get viewportPosition() {
3680
3626
  const element = this.viewportElement$.getValue();
3681
- if (this.settings.settings.computedPageTurnMode === `scrollable`) {
3627
+ if (this.settings.values.computedPageTurnMode === `scrollable`) {
3682
3628
  return getScaledDownPosition({
3683
3629
  element,
3684
3630
  position: {
3685
3631
  x: (element == null ? void 0 : element.scrollLeft) ?? 0,
3686
3632
  y: (element == null ? void 0 : element.scrollTop) ?? 0
3687
3633
  },
3688
- spine: this.spine
3634
+ spineElement: this.spine.element
3689
3635
  });
3690
3636
  }
3691
3637
  const { x, y } = (element == null ? void 0 : element.getBoundingClientRect()) ?? {
@@ -3723,18 +3669,19 @@
3723
3669
  const NAMESPACE$2 = `navigation/UserNavigator`;
3724
3670
  const report$1 = Report.namespace(NAMESPACE$2);
3725
3671
  class UserNavigator extends DestroyableClass {
3726
- constructor(settings, element$, context, scrollHappeningFromBrowser$) {
3672
+ constructor(settings, element$, context, scrollHappeningFromBrowser$, spine) {
3727
3673
  super();
3728
3674
  this.settings = settings;
3729
3675
  this.element$ = element$;
3730
3676
  this.context = context;
3731
3677
  this.scrollHappeningFromBrowser$ = scrollHappeningFromBrowser$;
3678
+ this.spine = spine;
3732
3679
  this.navigationSubject = new rxjs.Subject();
3733
3680
  this.locker = new Locker();
3734
3681
  this.navigation$ = this.navigationSubject.asObservable();
3735
3682
  const userScroll$ = element$.pipe(
3736
3683
  rxjs.switchMap(
3737
- (element) => settings.settings$.pipe(
3684
+ (element) => settings.values$.pipe(
3738
3685
  rxjs.map(({ computedPageTurnMode }) => computedPageTurnMode),
3739
3686
  rxjs.distinctUntilChanged(),
3740
3687
  rxjs.filter(
@@ -3751,31 +3698,10 @@
3751
3698
  ),
3752
3699
  rxjs.share()
3753
3700
  );
3754
- const userScrollEnd$ = userScroll$.pipe(
3755
- rxjs.exhaustMap(
3756
- () => userScroll$.pipe(
3757
- rxjs.debounceTime(
3758
- SCROLL_FINISHED_DEBOUNCE_TIMEOUT,
3759
- rxjs.animationFrameScheduler
3760
- )
3761
- )
3762
- ),
3763
- rxjs.share()
3764
- );
3765
- const lockNavigationWhileScrolling$ = userScroll$.pipe(
3766
- rxjs.exhaustMap(() => {
3767
- return userScrollEnd$.pipe(
3768
- rxjs.take(1),
3769
- rxjs.finalize(() => {
3770
- })
3771
- );
3772
- })
3773
- );
3774
- const navigateOnScroll$ = settings.settings$.pipe(
3701
+ const navigateOnScroll$ = settings.values$.pipe(
3775
3702
  rxjs.map(({ computedPageTurnMode }) => computedPageTurnMode),
3776
3703
  rxjs.distinctUntilChanged(),
3777
3704
  rxjs.filter((computedPageTurnMode) => computedPageTurnMode === "scrollable"),
3778
- rxjs.withLatestFrom(element$),
3779
3705
  rxjs.switchMap(() => userScroll$),
3780
3706
  rxjs.exhaustMap((event) => {
3781
3707
  const unlock = this.locker.lock();
@@ -3786,14 +3712,19 @@
3786
3712
  ),
3787
3713
  rxjs.first(),
3788
3714
  rxjs.tap(() => {
3789
- const element = event.target;
3715
+ const targetElement = event.target;
3716
+ const scaledDownPosition = getScaledDownPosition({
3717
+ element: targetElement,
3718
+ position: {
3719
+ x: targetElement.scrollLeft ?? 0,
3720
+ y: targetElement.scrollTop ?? 0
3721
+ },
3722
+ spineElement: this.spine.element
3723
+ });
3790
3724
  this.navigate({
3791
3725
  animation: false,
3792
3726
  type: "scroll",
3793
- position: {
3794
- x: element.scrollLeft ?? 0,
3795
- y: element.scrollTop ?? 0
3796
- }
3727
+ position: scaledDownPosition
3797
3728
  });
3798
3729
  }),
3799
3730
  rxjs.finalize(() => {
@@ -3802,7 +3733,7 @@
3802
3733
  );
3803
3734
  })
3804
3735
  );
3805
- rxjs.merge(lockNavigationWhileScrolling$, navigateOnScroll$).pipe(rxjs.takeUntil(this.destroy$)).subscribe();
3736
+ rxjs.merge(navigateOnScroll$).pipe(rxjs.takeUntil(this.destroy$)).subscribe();
3806
3737
  }
3807
3738
  /**
3808
3739
  * Remember that this navigation is not trustable.
@@ -3821,14 +3752,15 @@
3821
3752
  spineLocator,
3822
3753
  navigation,
3823
3754
  navigationResolver,
3824
- spineItemsManager
3755
+ spineItemsManager,
3756
+ spineLayout
3825
3757
  }) => {
3826
3758
  var _a, _b;
3827
3759
  const spineItem = spineItemsManager.get(navigation.spineItem);
3828
3760
  if (!spineItem) {
3829
3761
  return { x: 0, y: 0 };
3830
3762
  }
3831
- const spineItemAbsolutePosition = spineItemsManager.getAbsolutePositionOf(spineItem);
3763
+ const spineItemAbsolutePosition = spineLayout.getAbsolutePositionOf(spineItem);
3832
3764
  const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
3833
3765
  navigation.position,
3834
3766
  spineItem
@@ -3885,12 +3817,13 @@
3885
3817
  spineLocator,
3886
3818
  spineItemsManager,
3887
3819
  settings,
3888
- navigationResolver
3820
+ navigationResolver,
3821
+ spineLayout
3889
3822
  }) => {
3890
3823
  const { spineItem } = navigation;
3891
3824
  const foundSpineItem = spineItemsManager.get(spineItem);
3892
3825
  if (!foundSpineItem) return { x: 0, y: 0 };
3893
- const { height, top } = spineItemsManager.getAbsolutePositionOf(foundSpineItem);
3826
+ const { height, top } = spineLayout.getAbsolutePositionOf(foundSpineItem);
3894
3827
  const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
3895
3828
  navigation.position,
3896
3829
  foundSpineItem
@@ -3899,7 +3832,7 @@
3899
3832
  y: 0,
3900
3833
  x: 0
3901
3834
  };
3902
- if (settings.settings.computedPageTurnDirection === "vertical") {
3835
+ if (settings.values.computedPageTurnDirection === "vertical") {
3903
3836
  if (top === navigation.spineItemTop && height === navigation.spineItemHeight && isPositionWithinSpineItem) {
3904
3837
  return navigation.position;
3905
3838
  }
@@ -3914,10 +3847,10 @@
3914
3847
  },
3915
3848
  foundSpineItem
3916
3849
  );
3917
- return spineLocator.getSpinePositionFromSpineItemPosition(
3918
- positionInSpineItem2,
3919
- foundSpineItem
3920
- );
3850
+ return spineLocator.getSpinePositionFromSpineItemPosition({
3851
+ spineItemPosition: positionInSpineItem2,
3852
+ spineItem: foundSpineItem
3853
+ });
3921
3854
  }
3922
3855
  if (top === navigation.spineItemTop && height !== navigation.spineItemHeight) {
3923
3856
  const positionYfromBottomPreviousNavigation = (navigation.spineItemHeight ?? positionInSpineItem.y) - positionInSpineItem.y;
@@ -3930,10 +3863,10 @@
3930
3863
  positionInspineItem,
3931
3864
  foundSpineItem
3932
3865
  );
3933
- return spineLocator.getSpinePositionFromSpineItemPosition(
3934
- positionInSpineItem2,
3935
- foundSpineItem
3936
- );
3866
+ return spineLocator.getSpinePositionFromSpineItemPosition({
3867
+ spineItemPosition: positionInSpineItem2,
3868
+ spineItem: foundSpineItem
3869
+ });
3937
3870
  }
3938
3871
  if (!isPositionWithinSpineItem) {
3939
3872
  if (navigation.directionFromLastNavigation === "backward") {
@@ -3941,26 +3874,26 @@
3941
3874
  y: height - positionYfromBottomPreviousNavigation,
3942
3875
  x: navigation.position.x
3943
3876
  };
3944
- return spineLocator.getSpinePositionFromSpineItemPosition(
3945
- spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
3877
+ return spineLocator.getSpinePositionFromSpineItemPosition({
3878
+ spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
3946
3879
  positionInItem,
3947
3880
  foundSpineItem
3948
3881
  ),
3949
- foundSpineItem
3950
- );
3882
+ spineItem: foundSpineItem
3883
+ });
3951
3884
  }
3952
3885
  if (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor") {
3953
3886
  const positionInItem = {
3954
3887
  y: height - positionYfromBottomPreviousNavigation,
3955
3888
  x: navigation.position.x
3956
3889
  };
3957
- return spineLocator.getSpinePositionFromSpineItemPosition(
3958
- spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
3890
+ return spineLocator.getSpinePositionFromSpineItemPosition({
3891
+ spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
3959
3892
  positionInItem,
3960
3893
  foundSpineItem
3961
3894
  ),
3962
- foundSpineItem
3963
- );
3895
+ spineItem: foundSpineItem
3896
+ });
3964
3897
  }
3965
3898
  return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
3966
3899
  }
@@ -3973,44 +3906,46 @@
3973
3906
  spineItemsManager,
3974
3907
  settings,
3975
3908
  spineLocator,
3976
- navigationResolver
3909
+ navigationResolver,
3910
+ spineLayout
3977
3911
  }) => {
3978
- if (settings.settings.computedPageTurnMode === "scrollable") {
3912
+ if (settings.values.computedPageTurnMode === "scrollable") {
3979
3913
  return restoreNavigationForScrollingPageTurnMode({
3980
3914
  navigation,
3981
3915
  spineLocator,
3982
3916
  navigationResolver,
3983
3917
  settings,
3984
- spineItemsManager
3918
+ spineItemsManager,
3919
+ spineLayout
3985
3920
  });
3986
3921
  }
3987
3922
  return restoreNavigationForControlledPageTurnMode({
3988
3923
  navigation,
3989
3924
  spineLocator,
3990
3925
  navigationResolver,
3991
- spineItemsManager
3926
+ spineItemsManager,
3927
+ spineLayout
3992
3928
  });
3993
3929
  };
3994
3930
  const withRestoredPosition = ({
3995
- spineItemsManager,
3996
3931
  settings,
3997
- spineLocator,
3998
3932
  navigationResolver,
3999
- spineItemLocator,
4000
- context
3933
+ context,
3934
+ spine
4001
3935
  }) => (stream) => stream.pipe(
4002
3936
  rxjs.map((params) => ({
4003
3937
  ...params,
4004
3938
  navigation: {
4005
3939
  ...params.navigation,
4006
3940
  position: restorePosition({
4007
- spineLocator,
3941
+ spineLocator: spine.locator,
4008
3942
  navigation: params.navigation,
4009
3943
  navigationResolver,
4010
3944
  settings,
4011
- spineItemsManager,
4012
- spineItemLocator,
4013
- context
3945
+ spineItemsManager: spine.spineItemsManager,
3946
+ spineItemLocator: spine.locator.spineItemLocator,
3947
+ context,
3948
+ spineLayout: spine.spineLayout
4014
3949
  })
4015
3950
  }
4016
3951
  }))
@@ -4053,7 +3988,7 @@
4053
3988
  if (!navigation.position) {
4054
3989
  return "forward";
4055
3990
  }
4056
- if (settings.settings.computedPageTurnDirection === "vertical") {
3991
+ if (settings.values.computedPageTurnDirection === "vertical") {
4057
3992
  if (navigation.position.y > previousNavigation.position.y) {
4058
3993
  return "forward";
4059
3994
  } else {
@@ -4103,7 +4038,7 @@
4103
4038
  navigationResolver
4104
4039
  }) => (stream) => {
4105
4040
  const getPosition = (navigation) => {
4106
- const { navigationSnapThreshold, computedPageTurnMode } = settings.settings;
4041
+ const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
4107
4042
  const spineItem = spineItemsManager.get(navigation.spineItem);
4108
4043
  if (!spineItem || !navigation.position) return void 0;
4109
4044
  if (computedPageTurnMode === "controlled") {
@@ -4125,10 +4060,11 @@
4125
4060
  restrictToScreen: true
4126
4061
  });
4127
4062
  const beginPageIndexForDirection = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.beginPageIndex : visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.endPageIndex) ?? 0;
4128
- const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex(
4129
- beginPageIndexForDirection,
4130
- spineItem
4131
- );
4063
+ const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
4064
+ pageIndex: beginPageIndexForDirection,
4065
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
4066
+ itemLayout: spineItem.getElementDimensions()
4067
+ });
4132
4068
  return positionInSpineItem;
4133
4069
  }
4134
4070
  return spineLocator.getSpineItemPositionFromSpinePosition(
@@ -4184,13 +4120,13 @@
4184
4120
  })
4185
4121
  );
4186
4122
  };
4187
- const withSpineItemLayoutInfo = ({ spineItemsManager }) => (stream) => {
4123
+ const withSpineItemLayoutInfo = ({ spine }) => (stream) => {
4188
4124
  return stream.pipe(
4189
4125
  rxjs.map(({ navigation, ...rest }) => {
4190
- const spineItemDimensions = spineItemsManager.getAbsolutePositionOf(
4126
+ const spineItemDimensions = spine.spineLayout.getAbsolutePositionOf(
4191
4127
  navigation.spineItem
4192
4128
  );
4193
- const spineItem = spineItemsManager.get(navigation.spineItem);
4129
+ const spineItem = spine.spineItemsManager.get(navigation.spineItem);
4194
4130
  return {
4195
4131
  navigation: {
4196
4132
  ...navigation,
@@ -4274,14 +4210,14 @@
4274
4210
  cfi,
4275
4211
  directionFromLastNavigation: direction
4276
4212
  } = navigation;
4277
- const { navigationSnapThreshold, computedPageTurnMode } = settings.settings;
4213
+ const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
4278
4214
  if (spineItem !== void 0) {
4279
4215
  const existingSpineItem = spineItemsManager.get(spineItem);
4280
4216
  if (existingSpineItem) return existingSpineItem;
4281
4217
  }
4282
4218
  if (typeof spineItem === "number") {
4283
- if (spineItem > spineItemsManager.getLength() - 1) {
4284
- return spineItemsManager.get(spineItemsManager.getLength() - 1);
4219
+ if (spineItem > spineItemsManager.items.length - 1) {
4220
+ return spineItemsManager.get(spineItemsManager.items.length - 1);
4285
4221
  }
4286
4222
  return spineItemsManager.get(0);
4287
4223
  }
@@ -4338,15 +4274,14 @@
4338
4274
  const NAMESPACE$1 = `navigation/InternalNavigator`;
4339
4275
  const report = Report.namespace(NAMESPACE$1);
4340
4276
  class InternalNavigator extends DestroyableClass {
4341
- constructor(settings, context, userNavigation$, viewportController, navigationResolver, spineItemsManager, spineLocator, element$, isUserLocked$) {
4277
+ constructor(settings, context, userNavigation$, viewportController, navigationResolver, spine, element$, isUserLocked$) {
4342
4278
  super();
4343
4279
  this.settings = settings;
4344
4280
  this.context = context;
4345
4281
  this.userNavigation$ = userNavigation$;
4346
4282
  this.viewportController = viewportController;
4347
4283
  this.navigationResolver = navigationResolver;
4348
- this.spineItemsManager = spineItemsManager;
4349
- this.spineLocator = spineLocator;
4284
+ this.spine = spine;
4350
4285
  this.element$ = element$;
4351
4286
  this.isUserLocked$ = isUserLocked$;
4352
4287
  this.navigationSubject = new rxjs.BehaviorSubject({
@@ -4365,14 +4300,14 @@
4365
4300
  id
4366
4301
  })),
4367
4302
  rxjs.distinctUntilChanged(
4368
- ({ position: previousPosition, ...previousRest }, { position: currentPosition, ...currentRest }) => isShallowEqual(previousRest, currentRest) && isShallowEqual(previousPosition, currentPosition)
4303
+ ({ position: previousPosition, ...previousRest }, { position: currentPosition, ...currentRest }) => shared.isShallowEqual(previousRest, currentRest) && shared.isShallowEqual(previousPosition, currentPosition)
4369
4304
  ),
4370
4305
  rxjs.shareReplay(1)
4371
4306
  );
4372
4307
  this.locker = new Locker();
4373
4308
  const layoutHasChanged$ = rxjs.merge(
4374
4309
  viewportController.layout$,
4375
- spineItemsManager.layout$.pipe(rxjs.filter((hasChanged) => hasChanged))
4310
+ spine.spineLayout.layout$.pipe(rxjs.filter(({ hasChanged }) => hasChanged))
4376
4311
  );
4377
4312
  const navigationFromUser$ = userNavigation$.pipe(
4378
4313
  rxjs.withLatestFrom(this.navigationSubject),
@@ -4396,43 +4331,39 @@
4396
4331
  context,
4397
4332
  navigationResolver,
4398
4333
  settings,
4399
- spineItemsManager,
4400
- spineLocator
4334
+ spineItemsManager: spine.spineItemsManager,
4335
+ spineLocator: spine.locator
4401
4336
  }),
4402
4337
  withSpineItemPosition({
4403
- context,
4404
4338
  navigationResolver,
4405
4339
  settings,
4406
- spineItemsManager,
4407
- spineLocator
4340
+ spineItemsManager: spine.spineItemsManager,
4341
+ spineLocator: spine.locator
4408
4342
  }),
4409
4343
  withSpineItemLayoutInfo({
4410
- spineItemsManager
4344
+ spine
4411
4345
  })
4412
4346
  ).pipe(
4413
4347
  withFallbackPosition({
4414
4348
  navigationResolver,
4415
- spineItemsManager
4349
+ spineItemsManager: spine.spineItemsManager
4416
4350
  }),
4417
4351
  rxjs.withLatestFrom(isUserLocked$),
4418
4352
  rxjs.switchMap(([params, isUserLocked]) => {
4419
- const shouldNotAlterPosition = params.navigation.cfi || params.navigation.url || settings.settings.computedPageTurnMode === "scrollable" || isUserLocked;
4353
+ const shouldNotAlterPosition = params.navigation.cfi || params.navigation.url || settings.values.computedPageTurnMode === "scrollable" || isUserLocked;
4420
4354
  return rxjs.of(params).pipe(
4421
4355
  shouldNotAlterPosition ? rxjs.identity : withRestoredPosition({
4422
4356
  navigationResolver,
4423
4357
  settings,
4424
- spineItemsManager,
4425
- spineLocator,
4426
- spineItemLocator: spineLocator.spineItemLocator,
4358
+ spine,
4427
4359
  context
4428
4360
  })
4429
4361
  );
4430
4362
  }),
4431
4363
  withSpineItemPosition({
4432
- spineItemsManager,
4433
- spineLocator,
4364
+ spineItemsManager: spine.spineItemsManager,
4365
+ spineLocator: spine.locator,
4434
4366
  settings,
4435
- context,
4436
4367
  navigationResolver
4437
4368
  }),
4438
4369
  rxjs.map((params) => params.navigation),
@@ -4489,10 +4420,8 @@
4489
4420
  withRestoredPosition({
4490
4421
  navigationResolver,
4491
4422
  settings,
4492
- spineItemsManager,
4493
- spineLocator,
4494
- spineItemLocator: spineLocator.spineItemLocator,
4495
- context
4423
+ context,
4424
+ spine
4496
4425
  }),
4497
4426
  rxjs.map((params) => {
4498
4427
  const navigation = {
@@ -4507,13 +4436,12 @@
4507
4436
  };
4508
4437
  }),
4509
4438
  withSpineItemLayoutInfo({
4510
- spineItemsManager
4439
+ spine
4511
4440
  }),
4512
4441
  withSpineItemPosition({
4513
- spineItemsManager,
4514
- spineLocator,
4442
+ spineItemsManager: spine.spineItemsManager,
4443
+ spineLocator: spine.locator,
4515
4444
  settings,
4516
- context,
4517
4445
  navigationResolver
4518
4446
  }),
4519
4447
  rxjs.map(({ navigation }) => navigation),
@@ -4565,7 +4493,7 @@
4565
4493
  const isScrollFromUser = currentNavigation.type === `scroll`;
4566
4494
  const isPaginationUpdate = currentNavigation.meta.triggeredBy === "pagination";
4567
4495
  const isRestoration = currentNavigation.meta.triggeredBy === "restoration";
4568
- const positionIsSame = isShallowEqual(
4496
+ const positionIsSame = shared.isShallowEqual(
4569
4497
  previousNavigation.position,
4570
4498
  currentNavigation.position
4571
4499
  );
@@ -4597,7 +4525,6 @@
4597
4525
  }
4598
4526
  const createNavigator = ({
4599
4527
  spineItemsManager,
4600
- spineItemsObserver,
4601
4528
  context,
4602
4529
  parentElement$,
4603
4530
  hookManager,
@@ -4609,7 +4536,8 @@
4609
4536
  context,
4610
4537
  settings,
4611
4538
  spineItemsManager,
4612
- locator: spine.locator
4539
+ locator: spine.locator,
4540
+ spineLayout: spine.spineLayout
4613
4541
  });
4614
4542
  const viewportNavigator = new ViewportNavigator(
4615
4543
  settings,
@@ -4621,7 +4549,7 @@
4621
4549
  const isSpineScrolling$ = rxjs.merge(
4622
4550
  spine.elementResize$,
4623
4551
  spine.element$.pipe(operators.switchMap((element) => rxjs.fromEvent(element, "scroll"))),
4624
- spineItemsObserver.itemResize$
4552
+ spine.spineItemsObserver.itemResize$
4625
4553
  ).pipe(
4626
4554
  operators.switchMap(() => rxjs.merge(rxjs.of(true), rxjs.timer(5).pipe(operators.map(() => false)))),
4627
4555
  operators.startWith(false)
@@ -4639,7 +4567,8 @@
4639
4567
  settings,
4640
4568
  element$,
4641
4569
  context,
4642
- scrollHappeningFromBrowser$
4570
+ scrollHappeningFromBrowser$,
4571
+ spine
4643
4572
  );
4644
4573
  const internalNavigator = new InternalNavigator(
4645
4574
  settings,
@@ -4647,8 +4576,7 @@
4647
4576
  userNavigator.navigation$,
4648
4577
  viewportNavigator,
4649
4578
  navigationResolver,
4650
- spineItemsManager,
4651
- spine.locator,
4579
+ spine,
4652
4580
  element$,
4653
4581
  userNavigator.locker.isLocked$
4654
4582
  );
@@ -4710,9 +4638,9 @@
4710
4638
  this._settings$.subscribe();
4711
4639
  }
4712
4640
  _prepareUpdate(settings) {
4713
- const newInputSettings = shallowMergeIfDefined(this.inputSettings, settings);
4641
+ const newInputSettings = shared.shallowMergeIfDefined(this.inputSettings, settings);
4714
4642
  const state = this.getOutputSettings(newInputSettings);
4715
- const hasChanged = !isShallowEqual(this.outputSettings, state);
4643
+ const hasChanged = !shared.isShallowEqual(this.outputSettings, state);
4716
4644
  return {
4717
4645
  hasChanged,
4718
4646
  state,
@@ -4730,14 +4658,14 @@
4730
4658
  const { commit } = this._prepareUpdate(settings);
4731
4659
  commit();
4732
4660
  }
4733
- get settings() {
4661
+ get values() {
4734
4662
  if (!this.outputSettings) {
4735
4663
  const { commit } = this._prepareUpdate(this.inputSettings);
4736
4664
  return commit();
4737
4665
  }
4738
4666
  return this.outputSettings;
4739
4667
  }
4740
- get settings$() {
4668
+ get values$() {
4741
4669
  if (!this.outputSettings) {
4742
4670
  const { commit } = this._prepareUpdate(this.inputSettings);
4743
4671
  commit();
@@ -4757,10 +4685,10 @@
4757
4685
  context.manifest$
4758
4686
  ]).pipe(
4759
4687
  operators.tap(() => {
4760
- this.update(this.settings);
4688
+ this.update(this.values);
4761
4689
  })
4762
4690
  );
4763
- const updateContextOnSettingsChanges$ = this.settings$.pipe(
4691
+ const updateContextOnSettingsChanges$ = this.values$.pipe(
4764
4692
  operators.tap(({ forceSinglePageMode }) => {
4765
4693
  context.update({ forceSinglePageMode });
4766
4694
  })
@@ -4900,7 +4828,7 @@
4900
4828
  const itemAnchor = getItemAnchor(spineItem);
4901
4829
  return `epubcfi(/0${itemAnchor}) `;
4902
4830
  };
4903
- const getCfi = Report.measurePerformance(
4831
+ const generateCfiForSpineItemPage = Report.measurePerformance(
4904
4832
  `getCfi`,
4905
4833
  10,
4906
4834
  ({
@@ -4937,7 +4865,7 @@
4937
4865
  this.spineItemLocator = spineItemLocator;
4938
4866
  const updatePagination$ = rxjs.merge(
4939
4867
  this.context.bridgeEvent.navigation$,
4940
- spineItemsManager.layout$.pipe(rxjs.filter((hasChanged) => hasChanged))
4868
+ spine.spineLayout.layout$.pipe(rxjs.filter(({ hasChanged }) => hasChanged))
4941
4869
  ).pipe(
4942
4870
  rxjs.switchMap(() => {
4943
4871
  const getVisiblePagesFromViewportPosition = ({
@@ -5022,12 +4950,12 @@
5022
4950
  const endSpineItem = this.spineItemsManager.get(endSpineItemIndex);
5023
4951
  if (beginSpineItem === void 0 || endSpineItem === void 0) return;
5024
4952
  this.pagination.update({
5025
- beginCfi: getCfi({
4953
+ beginCfi: generateCfiForSpineItemPage({
5026
4954
  pageIndex: beginPageIndexInSpineItem,
5027
4955
  spineItem: beginSpineItem,
5028
4956
  spineItemLocator
5029
4957
  }),
5030
- endCfi: getCfi({
4958
+ endCfi: generateCfiForSpineItemPage({
5031
4959
  pageIndex: endPageIndexInSpineItem,
5032
4960
  spineItem: endSpineItem,
5033
4961
  spineItemLocator
@@ -5056,151 +4984,13 @@
5056
4984
  );
5057
4985
  return { start: startCFI, end: endCFI };
5058
4986
  };
5059
- class SpineItemsObserver extends DestroyableClass {
5060
- constructor(spineItemsManager) {
5061
- super();
5062
- this.spineItemsManager = spineItemsManager;
5063
- this.itemIsReady$ = this.spineItemsManager.items$.pipe(
5064
- rxjs.switchMap((items) => {
5065
- const itemsIsReady$ = items.map(
5066
- (item) => item.$.isReady$.pipe(rxjs.map((isReady) => ({ item, isReady })))
5067
- );
5068
- return rxjs.merge(...itemsIsReady$);
5069
- }),
5070
- rxjs.share()
5071
- );
5072
- this.itemResize$ = this.spineItemsManager.items$.pipe(
5073
- rxjs.switchMap((items) => {
5074
- const resize$ = items.map(
5075
- (item) => observeResize(item.element).pipe(
5076
- rxjs.map((entries) => ({ entries, item }))
5077
- )
5078
- );
5079
- return rxjs.merge(...resize$);
5080
- }),
5081
- rxjs.share()
5082
- );
5083
- }
5084
- }
5085
- const NAMESPACE = `spineItemsManager`;
5086
4987
  class SpineItemsManager extends DestroyableClass {
5087
4988
  constructor(context, settings) {
5088
4989
  super();
5089
4990
  this.context = context;
5090
4991
  this.settings = settings;
5091
- this.layoutSubject = new rxjs.Subject();
5092
- this.itemLayoutInformation = [];
5093
4992
  this.orderedSpineItemsSubject = new rxjs.BehaviorSubject([]);
5094
4993
  this.items$ = this.orderedSpineItemsSubject.asObservable();
5095
- this.layout$ = this.layoutSubject.asObservable();
5096
- }
5097
- /**
5098
- * @todo
5099
- * move this logic to the spine
5100
- *
5101
- * @todo
5102
- * make sure to check how many times it is being called and try to reduce number of layouts
5103
- * it is called eery time an item is being unload (which can adds up quickly for big books)
5104
- */
5105
- layout() {
5106
- const manifest = this.context.manifest;
5107
- const newItemLayoutInformation = [];
5108
- const isGloballyPrePaginated = (manifest == null ? void 0 : manifest.renditionLayout) === `pre-paginated`;
5109
- this.orderedSpineItemsSubject.value.reduce(
5110
- ({ horizontalOffset, verticalOffset }, item, index) => {
5111
- let minimumWidth = this.context.getPageSize().width;
5112
- let blankPagePosition = `none`;
5113
- const itemStartOnNewScreen = horizontalOffset % this.context.state.visibleAreaRect.width === 0;
5114
- const isLastItem = index === this.orderedSpineItemsSubject.value.length - 1;
5115
- if (this.context.state.isUsingSpreadMode) {
5116
- if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && !isLastItem) {
5117
- minimumWidth = this.context.getPageSize().width * 2;
5118
- }
5119
- if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && isLastItem && itemStartOnNewScreen) {
5120
- minimumWidth = this.context.getPageSize().width * 2;
5121
- }
5122
- const lastItemStartOnNewScreenInAPrepaginatedBook = itemStartOnNewScreen && isLastItem && isGloballyPrePaginated;
5123
- if (item.item.pageSpreadRight && itemStartOnNewScreen && !this.context.isRTL()) {
5124
- blankPagePosition = `before`;
5125
- minimumWidth = this.context.getPageSize().width * 2;
5126
- } else if (item.item.pageSpreadLeft && itemStartOnNewScreen && this.context.isRTL()) {
5127
- blankPagePosition = `before`;
5128
- minimumWidth = this.context.getPageSize().width * 2;
5129
- } else if (lastItemStartOnNewScreenInAPrepaginatedBook) {
5130
- if (this.context.isRTL()) {
5131
- blankPagePosition = `before`;
5132
- } else {
5133
- blankPagePosition = `after`;
5134
- }
5135
- minimumWidth = this.context.getPageSize().width * 2;
5136
- }
5137
- }
5138
- const { width, height } = item.layout({
5139
- minimumWidth,
5140
- blankPagePosition,
5141
- spreadPosition: this.context.state.isUsingSpreadMode ? itemStartOnNewScreen ? this.context.isRTL() ? `right` : `left` : this.context.isRTL() ? `left` : `right` : `none`
5142
- });
5143
- if (this.settings.settings.computedPageTurnDirection === `vertical`) {
5144
- const currentValidEdgeYForVerticalPositioning = itemStartOnNewScreen ? verticalOffset : verticalOffset - this.context.state.visibleAreaRect.height;
5145
- const currentValidEdgeXForVerticalPositioning = itemStartOnNewScreen ? 0 : horizontalOffset;
5146
- if (this.context.isRTL()) {
5147
- item.adjustPositionOfElement({
5148
- top: currentValidEdgeYForVerticalPositioning,
5149
- left: currentValidEdgeXForVerticalPositioning
5150
- });
5151
- } else {
5152
- item.adjustPositionOfElement({
5153
- top: currentValidEdgeYForVerticalPositioning,
5154
- left: currentValidEdgeXForVerticalPositioning
5155
- });
5156
- }
5157
- const newEdgeX = width + currentValidEdgeXForVerticalPositioning;
5158
- const newEdgeY = height + currentValidEdgeYForVerticalPositioning;
5159
- newItemLayoutInformation.push({
5160
- left: currentValidEdgeXForVerticalPositioning,
5161
- right: newEdgeX,
5162
- top: currentValidEdgeYForVerticalPositioning,
5163
- bottom: newEdgeY,
5164
- height,
5165
- width
5166
- });
5167
- return {
5168
- horizontalOffset: newEdgeX,
5169
- verticalOffset: newEdgeY
5170
- };
5171
- }
5172
- item.adjustPositionOfElement(
5173
- this.context.isRTL() ? { right: horizontalOffset, top: 0 } : { left: horizontalOffset, top: 0 }
5174
- );
5175
- newItemLayoutInformation.push({
5176
- ...this.context.isRTL() ? {
5177
- left: this.context.state.visibleAreaRect.width - horizontalOffset - width,
5178
- right: this.context.state.visibleAreaRect.width - horizontalOffset
5179
- } : {
5180
- left: horizontalOffset,
5181
- right: horizontalOffset + width
5182
- },
5183
- top: verticalOffset,
5184
- bottom: height,
5185
- height,
5186
- width
5187
- });
5188
- return {
5189
- horizontalOffset: horizontalOffset + width,
5190
- verticalOffset: 0
5191
- };
5192
- },
5193
- { horizontalOffset: 0, verticalOffset: 0 }
5194
- );
5195
- const hasLayoutChanges = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
5196
- (old, index) => !isShallowEqual(old, newItemLayoutInformation[index])
5197
- );
5198
- this.itemLayoutInformation = newItemLayoutInformation;
5199
- Report.log(NAMESPACE, `layout`, {
5200
- hasLayoutChanges,
5201
- itemLayoutInformation: this.itemLayoutInformation
5202
- });
5203
- this.layoutSubject.next(hasLayoutChanges);
5204
4994
  }
5205
4995
  get(indexOrId) {
5206
4996
  if (typeof indexOrId === `number`) {
@@ -5213,24 +5003,6 @@
5213
5003
  }
5214
5004
  return indexOrId;
5215
5005
  }
5216
- /**
5217
- * It's important to not use x,y since we need the absolute position of each element. Otherwise x,y would be relative to
5218
- * current window (viewport).
5219
- */
5220
- getAbsolutePositionOf(spineItemOrIndex) {
5221
- const fallback = {
5222
- left: 0,
5223
- right: 0,
5224
- top: 0,
5225
- bottom: 0,
5226
- width: 0,
5227
- height: 0
5228
- };
5229
- const spineItem = this.get(spineItemOrIndex);
5230
- const indexOfItem = spineItem ? this.orderedSpineItemsSubject.value.indexOf(spineItem) : -1;
5231
- const layoutInformation = this.itemLayoutInformation[indexOfItem];
5232
- return layoutInformation || fallback;
5233
- }
5234
5006
  comparePositionOf(toCompare, withItem) {
5235
5007
  const toCompareIndex = this.getSpineItemIndex(toCompare) ?? 0;
5236
5008
  const withIndex = this.getSpineItemIndex(withItem) ?? 0;
@@ -5246,32 +5018,8 @@
5246
5018
  ...this.orderedSpineItemsSubject.getValue(),
5247
5019
  ...spineItems
5248
5020
  ]);
5249
- spineItems.forEach((spineItem) => {
5250
- spineItem.$.contentLayout$.pipe(operators.takeUntil(this.context.destroy$)).subscribe(() => {
5251
- this.layout();
5252
- });
5253
- spineItem.$.loaded$.pipe(
5254
- operators.tap(() => {
5255
- if (spineItem.isUsingVerticalWriting()) {
5256
- this.context.update({
5257
- hasVerticalWriting: true
5258
- });
5259
- } else {
5260
- this.context.update({
5261
- hasVerticalWriting: false
5262
- });
5263
- }
5264
- }),
5265
- operators.takeUntil(this.context.destroy$)
5266
- ).subscribe();
5267
- });
5268
- }
5269
- get items() {
5270
- return this.orderedSpineItemsSubject.value;
5271
- }
5272
- getLength() {
5273
- return this.orderedSpineItemsSubject.value.length;
5274
5021
  }
5022
+ // @todo move
5275
5023
  getSpineItemFromCfi(cfi) {
5276
5024
  const { itemId } = extractProseMetadataFromCfi(cfi);
5277
5025
  if (itemId) {
@@ -5281,52 +5029,22 @@
5281
5029
  }
5282
5030
  return void 0;
5283
5031
  }
5032
+ get items() {
5033
+ return this.orderedSpineItemsSubject.value;
5034
+ }
5284
5035
  /**
5285
5036
  * @todo handle reload, remove subscription to each items etc. See add()
5286
5037
  */
5287
5038
  destroyItems() {
5288
5039
  this.orderedSpineItemsSubject.value.forEach((item) => item.destroy());
5289
5040
  }
5290
- destroy() {
5291
- super.destroy();
5292
- this.layoutSubject.complete();
5293
- }
5294
5041
  }
5295
- const createRemoveStyleHelper = (frameElement) => (id) => {
5296
- if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
5297
- const styleElement = frameElement.contentDocument.getElementById(id);
5298
- if (styleElement) {
5299
- styleElement.remove();
5300
- }
5301
- }
5302
- };
5303
- const createAddStyleHelper = (frameElement) => (id, style, prepend = false) => {
5304
- if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
5305
- const userStyle = document.createElement(`style`);
5306
- userStyle.id = id;
5307
- userStyle.innerHTML = style;
5308
- if (prepend) {
5309
- frameElement.contentDocument.head.prepend(userStyle);
5310
- } else {
5311
- frameElement.contentDocument.head.appendChild(userStyle);
5312
- }
5313
- }
5314
- };
5315
5042
  const getAttributeValueFromString = (string, key) => {
5316
5043
  const regExp = new RegExp(key + `\\s*=\\s*([0-9.]+)`, `i`);
5317
5044
  const match = string.match(regExp) || [];
5318
5045
  const firstMatch = match[1] || `0`;
5319
5046
  return match && parseFloat(firstMatch) || 0;
5320
5047
  };
5321
- const getOriginalFrameEventFromDocumentEvent = (event) => {
5322
- return event[__UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY];
5323
- };
5324
- const attachOriginalFrameEventToDocumentEvent = (event, frameEvent) => {
5325
- Object.defineProperty(event, __UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY, {
5326
- value: frameEvent,
5327
- enumerable: true
5328
- });
5329
- };
5330
5048
  const getIntrinsicDimensionsFromBase64Img = (data) => new Promise((resolve, reject) => {
5331
5049
  const image = new Image();
5332
5050
  image.src = data;
@@ -5387,7 +5105,7 @@
5387
5105
  const getHtmlFromResource = (response) => createHtmlPageFromResource(response, item);
5388
5106
  return (stream) => stream.pipe(
5389
5107
  rxjs.switchMap((frameElement) => {
5390
- const { fetchResource } = settings.settings;
5108
+ const { fetchResource } = settings.values;
5391
5109
  if (!fetchResource && item.href.startsWith(window.location.origin) && // we have an encoding and it's a valid html
5392
5110
  (item.mediaType && [
5393
5111
  `application/xhtml+xml`,
@@ -5439,7 +5157,7 @@
5439
5157
  }
5440
5158
  frame.setAttribute(`role`, `main`);
5441
5159
  if ((frame == null ? void 0 : frame.contentDocument) && body) ;
5442
- if (settings.settings.computedPageTurnMode !== `scrollable`) {
5160
+ if (settings.values.computedPageTurnMode !== `scrollable`) {
5443
5161
  frame.setAttribute(`tab-index`, `0`);
5444
5162
  }
5445
5163
  const hookResults = hookManager.execute(`item.onLoad`, item.id, {
@@ -5704,7 +5422,7 @@
5704
5422
  if (frame) {
5705
5423
  frame.style.width = `${size.width}px`;
5706
5424
  frame.style.height = `${size.height}px`;
5707
- if (this.settings.settings.computedPageTurnMode !== `scrollable`) {
5425
+ if (this.settings.values.computedPageTurnMode !== `scrollable`) {
5708
5426
  frame.setAttribute(`tab-index`, `0`);
5709
5427
  }
5710
5428
  }
@@ -5763,14 +5481,24 @@
5763
5481
  }
5764
5482
  addStyle(id, style, prepend) {
5765
5483
  const frameElement = this.loader.element;
5766
- if (frameElement) {
5767
- createAddStyleHelper(frameElement)(id, style, prepend);
5484
+ if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
5485
+ const userStyle = document.createElement(`style`);
5486
+ userStyle.id = id;
5487
+ userStyle.innerHTML = style;
5488
+ if (prepend) {
5489
+ frameElement.contentDocument.head.prepend(userStyle);
5490
+ } else {
5491
+ frameElement.contentDocument.head.appendChild(userStyle);
5492
+ }
5768
5493
  }
5769
5494
  }
5770
5495
  removeStyle(id) {
5771
5496
  const frameElement = this.loader.element;
5772
- if (frameElement) {
5773
- createRemoveStyleHelper(frameElement)(id);
5497
+ if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
5498
+ const styleElement = frameElement.contentDocument.getElementById(id);
5499
+ if (styleElement) {
5500
+ styleElement.remove();
5501
+ }
5774
5502
  }
5775
5503
  }
5776
5504
  }
@@ -5994,7 +5722,7 @@
5994
5722
  };
5995
5723
  };
5996
5724
  const getResource = async () => {
5997
- const fetchResource = settings.settings.fetchResource;
5725
+ const fetchResource = settings.values.fetchResource;
5998
5726
  const lastFetch = (_) => {
5999
5727
  if (fetchResource) {
6000
5728
  return fetchResource(item);
@@ -6140,7 +5868,7 @@
6140
5868
  const cssLink = buildDocumentStyle(
6141
5869
  {
6142
5870
  ...commonSpineItem.getDimensionsForPaginatedContent(),
6143
- enableTouch: settings.settings.computedPageTurnMode !== `scrollable`,
5871
+ enableTouch: settings.values.computedPageTurnMode !== `scrollable`,
6144
5872
  spreadPosition
6145
5873
  },
6146
5874
  viewportDimensions
@@ -6523,7 +6251,7 @@
6523
6251
  } else {
6524
6252
  const frameStyle = commonSpineItem.isImageType() ? buildStyleForReflowableImageOnly({
6525
6253
  isScrollable: ((_f = context.manifest) == null ? void 0 : _f.renditionFlow) === `scrolled-continuous`,
6526
- enableTouch: settings.settings.computedPageTurnMode !== `scrollable`
6254
+ enableTouch: settings.values.computedPageTurnMode !== `scrollable`
6527
6255
  }) : buildStyleWithMultiColumn(
6528
6256
  commonSpineItem.getDimensionsForReflowableContent(
6529
6257
  spineItemFrame.isUsingVerticalWriting(),
@@ -6626,12 +6354,13 @@
6626
6354
  const getSpineItemFromPosition = ({
6627
6355
  position,
6628
6356
  spineItemsManager,
6357
+ spineLayout,
6629
6358
  settings
6630
6359
  }) => {
6631
6360
  const spineItem = spineItemsManager.items.find((item) => {
6632
- const { left, right, bottom, top } = spineItemsManager.getAbsolutePositionOf(item);
6361
+ const { left, right, bottom, top } = spineLayout.getAbsolutePositionOf(item);
6633
6362
  const isWithinXAxis = position.x >= left && position.x < right;
6634
- if (settings.settings.computedPageTurnDirection === `horizontal`) {
6363
+ if (settings.values.computedPageTurnDirection === `horizontal`) {
6635
6364
  return isWithinXAxis;
6636
6365
  } else {
6637
6366
  return isWithinXAxis && position.y >= top && position.y < bottom;
@@ -6680,9 +6409,15 @@
6680
6409
  context
6681
6410
  }) => {
6682
6411
  const viewportLeft = viewportPosition.x;
6683
- const viewportRight = viewportPosition.x + (context.state.visibleAreaRect.width - 1);
6412
+ const viewportRight = Math.max(
6413
+ viewportPosition.x + (context.state.visibleAreaRect.width - 1),
6414
+ 0
6415
+ );
6684
6416
  const viewportTop = viewportPosition.y;
6685
- const viewportBottom = viewportPosition.y + (context.state.visibleAreaRect.height - 1);
6417
+ const viewportBottom = Math.max(
6418
+ viewportPosition.y + (context.state.visibleAreaRect.height - 1),
6419
+ 0
6420
+ );
6686
6421
  const visibleWidthOfItem = Math.min(right, viewportRight) - Math.max(left, viewportLeft);
6687
6422
  const visibleHeightOfItem = Math.min(bottom, viewportBottom) - Math.max(top, viewportTop);
6688
6423
  const itemIsOnTheOuterEdge = visibleWidthOfItem <= 0 || visibleHeightOfItem <= 0;
@@ -6713,12 +6448,18 @@
6713
6448
  restrictToScreen,
6714
6449
  spineItemsManager,
6715
6450
  context,
6716
- settings
6451
+ settings,
6452
+ spineLayout
6717
6453
  }) => {
6718
- const fallbackSpineItem = getSpineItemFromPosition({ position, settings, spineItemsManager }) || spineItemsManager.get(0);
6454
+ const fallbackSpineItem = getSpineItemFromPosition({
6455
+ position,
6456
+ settings,
6457
+ spineItemsManager,
6458
+ spineLayout
6459
+ }) || spineItemsManager.get(0);
6719
6460
  const spineItemsVisible = spineItemsManager.items.reduce(
6720
6461
  (acc, spineItem) => {
6721
- const itemPosition = spineItemsManager.getAbsolutePositionOf(spineItem);
6462
+ const itemPosition = spineLayout.getAbsolutePositionOf(spineItem);
6722
6463
  const { visible } = getItemVisibilityForPosition({
6723
6464
  itemPosition,
6724
6465
  threshold,
@@ -6740,22 +6481,114 @@
6740
6481
  const endItemIndex = spineItemsManager.getSpineItemIndex(endItem);
6741
6482
  return {
6742
6483
  beginIndex: beginItemIndex ?? 0,
6743
- // beginPosition: position,
6744
6484
  endIndex: endItemIndex ?? 0
6745
- // endPosition: position,
6746
6485
  };
6747
6486
  };
6748
- const createSpineLocator = ({
6487
+ const getSpinePositionFromSpineItemPosition = ({
6488
+ spineItemPosition,
6489
+ itemLayout: { left, top }
6490
+ }) => {
6491
+ return {
6492
+ x: left + spineItemPosition.x,
6493
+ y: top + spineItemPosition.y
6494
+ };
6495
+ };
6496
+ const getSpineInfoFromAbsolutePageIndex = ({
6497
+ absolutePageIndex,
6498
+ spineLayout,
6749
6499
  spineItemsManager,
6750
6500
  context,
6751
- spineItemLocator,
6752
6501
  settings
6753
6502
  }) => {
6754
- const getSpineItemPositionFromSpinePosition = Report.measurePerformance(
6755
- `getSpineItemPositionFromSpinePosition`,
6756
- 10,
6757
- (position, spineItem) => {
6758
- const { left, top } = spineItemsManager.getAbsolutePositionOf(spineItem);
6503
+ const items = spineItemsManager.items;
6504
+ const { found, currentAbsolutePage } = items.reduce(
6505
+ (acc, item) => {
6506
+ if (acc.found) return acc;
6507
+ const itemLayout = spineLayout.getAbsolutePositionOf(item);
6508
+ const numberOfPages = getSpineItemNumberOfPages({
6509
+ isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
6510
+ itemHeight: itemLayout.height,
6511
+ itemWidth: itemLayout.width,
6512
+ context,
6513
+ settings
6514
+ });
6515
+ const possiblePageIndex = absolutePageIndex - acc.currentAbsolutePage;
6516
+ const currentAbsolutePage2 = acc.currentAbsolutePage + numberOfPages;
6517
+ if (possiblePageIndex <= numberOfPages - 1) {
6518
+ return {
6519
+ ...acc,
6520
+ currentAbsolutePage: currentAbsolutePage2,
6521
+ found: { item, pageIndex: possiblePageIndex }
6522
+ };
6523
+ }
6524
+ return {
6525
+ ...acc,
6526
+ currentAbsolutePage: currentAbsolutePage2
6527
+ };
6528
+ },
6529
+ { currentAbsolutePage: 0 }
6530
+ );
6531
+ if (found) {
6532
+ return {
6533
+ spineItem: found.item,
6534
+ pageIndex: found.pageIndex,
6535
+ itemIndex: spineItemsManager.getSpineItemIndex(found.item) ?? 0,
6536
+ currentAbsolutePage
6537
+ };
6538
+ }
6539
+ return void 0;
6540
+ };
6541
+ const getAbsolutePageIndexFromPageIndex = ({
6542
+ pageIndex,
6543
+ spineItemOrId,
6544
+ spineLayout,
6545
+ spineItemsManager,
6546
+ context,
6547
+ settings
6548
+ }) => {
6549
+ const items = spineItemsManager.items;
6550
+ const spineItem = spineItemsManager.get(spineItemOrId);
6551
+ if (!spineItem) return void 0;
6552
+ const { currentAbsolutePage } = items.reduce(
6553
+ (acc, item) => {
6554
+ if (acc.found) return acc;
6555
+ const itemLayout = spineLayout.getAbsolutePositionOf(item);
6556
+ const numberOfPages = getSpineItemNumberOfPages({
6557
+ isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
6558
+ itemHeight: itemLayout.height,
6559
+ itemWidth: itemLayout.width,
6560
+ context,
6561
+ settings
6562
+ });
6563
+ if (spineItem === item) {
6564
+ if (pageIndex <= numberOfPages - 1) {
6565
+ return {
6566
+ currentAbsolutePage: acc.currentAbsolutePage + pageIndex,
6567
+ found: true
6568
+ };
6569
+ }
6570
+ }
6571
+ return {
6572
+ ...acc,
6573
+ currentAbsolutePage: acc.currentAbsolutePage + numberOfPages
6574
+ };
6575
+ },
6576
+ { currentAbsolutePage: 0, found: false }
6577
+ );
6578
+ return currentAbsolutePage;
6579
+ };
6580
+ const createSpineLocator = ({
6581
+ spineItemsManager,
6582
+ context,
6583
+ spineItemLocator,
6584
+ settings,
6585
+ spineLayout
6586
+ }) => {
6587
+ const getSpineItemPositionFromSpinePosition = Report.measurePerformance(
6588
+ `getSpineItemPositionFromSpinePosition`,
6589
+ 10,
6590
+ (position, spineItem) => {
6591
+ const { left, top } = spineLayout.getAbsolutePositionOf(spineItem);
6759
6592
  return {
6760
6593
  /**
6761
6594
  * when using spread the item could be on the right and therefore will be negative
@@ -6770,15 +6603,11 @@
6770
6603
  },
6771
6604
  { disable: true }
6772
6605
  );
6773
- const getSpinePositionFromSpineItemPosition = (spineItemPosition, spineItem) => {
6774
- const { left, top } = spineItemsManager.getAbsolutePositionOf(spineItem);
6775
- return {
6776
- x: left + spineItemPosition.x,
6777
- y: top + spineItemPosition.y
6778
- };
6779
- };
6780
6606
  const getSpinePositionFromSpineItem = (spineItem) => {
6781
- return getSpinePositionFromSpineItemPosition({ x: 0, y: 0 }, spineItem);
6607
+ return getSpinePositionFromSpineItemPosition({
6608
+ spineItemPosition: { x: 0, y: 0 },
6609
+ itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
6610
+ });
6782
6611
  };
6783
6612
  const getSpineItemFromIframe = (iframe) => {
6784
6613
  return spineItemsManager.items.find((item) => item.frame.element === iframe);
@@ -6811,11 +6640,15 @@
6811
6640
  itemWidth: width
6812
6641
  });
6813
6642
  const pages = Array.from(Array(numberOfPages)).map((_, index) => {
6814
- const spineItemPosition = spineItemLocator.getSpineItemPositionFromPageIndex(index, spineItem);
6815
- const spinePosition = getSpinePositionFromSpineItemPosition(
6643
+ const spineItemPosition = spineItemLocator.getSpineItemPositionFromPageIndex({
6644
+ pageIndex: index,
6645
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
6646
+ itemLayout: spineItem.getElementDimensions()
6647
+ });
6648
+ const spinePosition = getSpinePositionFromSpineItemPosition({
6816
6649
  spineItemPosition,
6817
- spineItem
6818
- );
6650
+ itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
6651
+ });
6819
6652
  return {
6820
6653
  index,
6821
6654
  absolutePosition: {
@@ -6854,24 +6687,48 @@
6854
6687
  };
6855
6688
  };
6856
6689
  const isPositionWithinSpineItem = (position, spineItem) => {
6857
- const { bottom, left, right, top } = spineItemsManager.getAbsolutePositionOf(spineItem);
6690
+ const { bottom, left, right, top } = spineLayout.getAbsolutePositionOf(spineItem);
6858
6691
  return position.x >= left && position.x <= right && position.y <= bottom && position.y >= top;
6859
6692
  };
6860
6693
  const getSafeSpineItemPositionFromUnsafeSpineItemPosition = (unsafePosition, spineItem) => {
6861
- const { height, width } = spineItemsManager.getAbsolutePositionOf(spineItem);
6694
+ const { height, width } = spineLayout.getAbsolutePositionOf(spineItem);
6862
6695
  return {
6863
6696
  x: Math.min(Math.max(0, unsafePosition.x), width),
6864
6697
  y: Math.min(Math.max(0, unsafePosition.y), height)
6865
6698
  };
6866
6699
  };
6867
6700
  return {
6868
- getSpinePositionFromSpineItemPosition,
6701
+ getSpinePositionFromSpineItemPosition: ({
6702
+ spineItem,
6703
+ spineItemPosition
6704
+ }) => {
6705
+ const itemLayout = spineLayout.getAbsolutePositionOf(spineItem);
6706
+ return getSpinePositionFromSpineItemPosition({
6707
+ itemLayout,
6708
+ spineItemPosition
6709
+ });
6710
+ },
6711
+ getAbsolutePageIndexFromPageIndex: (params) => getAbsolutePageIndexFromPageIndex({
6712
+ ...params,
6713
+ context,
6714
+ settings,
6715
+ spineItemsManager,
6716
+ spineLayout
6717
+ }),
6718
+ getSpineInfoFromAbsolutePageIndex: (params) => getSpineInfoFromAbsolutePageIndex({
6719
+ ...params,
6720
+ context,
6721
+ settings,
6722
+ spineItemsManager,
6723
+ spineLayout
6724
+ }),
6869
6725
  getSpinePositionFromSpineItem,
6870
6726
  getSpineItemPositionFromSpinePosition,
6871
6727
  getSpineItemFromPosition: (position) => getSpineItemFromPosition({
6872
6728
  position,
6873
6729
  settings,
6874
- spineItemsManager
6730
+ spineItemsManager,
6731
+ spineLayout
6875
6732
  }),
6876
6733
  getSpineItemFromIframe,
6877
6734
  getSpineItemPageIndexFromNode,
@@ -6879,6 +6736,7 @@
6879
6736
  context,
6880
6737
  settings,
6881
6738
  spineItemsManager,
6739
+ spineLayout,
6882
6740
  ...params
6883
6741
  }),
6884
6742
  getVisiblePagesFromViewportPosition,
@@ -6892,7 +6750,7 @@
6892
6750
  settings
6893
6751
  }) => (stream) => stream.pipe(
6894
6752
  rxjs.tap(([beginIndex, endIndex]) => {
6895
- const { numberOfAdjacentSpineItemToPreLoad } = settings.settings;
6753
+ const { numberOfAdjacentSpineItemToPreLoad } = settings.values;
6896
6754
  const leftMaximumIndex = beginIndex - numberOfAdjacentSpineItemToPreLoad;
6897
6755
  const rightMaximumIndex = endIndex + numberOfAdjacentSpineItemToPreLoad;
6898
6756
  spineItemsManager.items.forEach((orderedSpineItem, index) => {
@@ -6915,17 +6773,18 @@
6915
6773
  })
6916
6774
  );
6917
6775
  class SpineItemsLoader extends DestroyableClass {
6918
- constructor(context, spineItemsManager, spineLocator, settings) {
6776
+ constructor(context, spineItemsManager, spineLocator, settings, spineLayout) {
6919
6777
  super();
6920
6778
  this.context = context;
6921
6779
  this.spineItemsManager = spineItemsManager;
6922
6780
  this.spineLocator = spineLocator;
6923
6781
  this.settings = settings;
6782
+ this.spineLayout = spineLayout;
6924
6783
  const navigationUpdate$ = this.context.bridgeEvent.navigation$;
6925
- const layoutHasChanged$ = spineItemsManager.layout$.pipe(
6926
- rxjs.filter((hasChanged) => hasChanged)
6784
+ const layoutHasChanged$ = this.spineLayout.layout$.pipe(
6785
+ rxjs.filter(({ hasChanged }) => hasChanged)
6927
6786
  );
6928
- const numberOfAdjacentSpineItemToPreLoad$ = settings.settings$.pipe(
6787
+ const numberOfAdjacentSpineItemToPreLoad$ = settings.values$.pipe(
6929
6788
  rxjs.map(
6930
6789
  ({ numberOfAdjacentSpineItemToPreLoad }) => numberOfAdjacentSpineItemToPreLoad
6931
6790
  ),
@@ -6950,6 +6809,272 @@
6950
6809
  loadSpineItems$.pipe(rxjs.takeUntil(this.destroy$)).subscribe();
6951
6810
  }
6952
6811
  }
6812
+ class SpineItemsObserver extends DestroyableClass {
6813
+ constructor(spineItemsManager, spineLocator) {
6814
+ super();
6815
+ this.spineItemsManager = spineItemsManager;
6816
+ this.spineLocator = spineLocator;
6817
+ this.itemIsReady$ = this.spineItemsManager.items$.pipe(
6818
+ rxjs.switchMap((items) => {
6819
+ const itemsIsReady$ = items.map(
6820
+ (item) => item.$.isReady$.pipe(rxjs.map((isReady) => ({ item, isReady })))
6821
+ );
6822
+ return rxjs.merge(...itemsIsReady$);
6823
+ }),
6824
+ rxjs.share()
6825
+ );
6826
+ this.itemResize$ = this.spineItemsManager.items$.pipe(
6827
+ rxjs.switchMap((items) => {
6828
+ const resize$ = items.map(
6829
+ (item) => observeResize(item.element).pipe(
6830
+ rxjs.map((entries) => ({ entries, item }))
6831
+ )
6832
+ );
6833
+ return rxjs.merge(...resize$);
6834
+ }),
6835
+ rxjs.share()
6836
+ );
6837
+ }
6838
+ }
6839
+ const convertSpinePositionToLayoutPosition = ({
6840
+ position,
6841
+ pageSize
6842
+ }) => {
6843
+ return {
6844
+ x: position.x,
6845
+ y: position.y,
6846
+ left: position.x,
6847
+ top: position.y,
6848
+ width: pageSize.width,
6849
+ height: pageSize.height,
6850
+ bottom: position.y + pageSize.height,
6851
+ right: position.x + pageSize.width
6852
+ };
6853
+ };
6854
+ const NAMESPACE = `SpineLayout`;
6855
+ class SpineLayout extends DestroyableClass {
6856
+ constructor(spineItemsManager, context, settings) {
6857
+ super();
6858
+ this.spineItemsManager = spineItemsManager;
6859
+ this.context = context;
6860
+ this.settings = settings;
6861
+ this.itemLayoutInformation = [];
6862
+ this.layoutSubject = new rxjs.Subject();
6863
+ spineItemsManager.items$.pipe(
6864
+ rxjs.switchMap((items) => {
6865
+ const itemsLayout$ = items.map(
6866
+ (spineItem) => spineItem.$.contentLayout$.pipe(
6867
+ rxjs.tap(() => {
6868
+ this.layout();
6869
+ })
6870
+ )
6871
+ );
6872
+ const writingModeUpdate$ = items.map(
6873
+ (spineItem) => spineItem.$.loaded$.pipe(
6874
+ rxjs.tap(() => {
6875
+ if (spineItem.isUsingVerticalWriting()) {
6876
+ this.context.update({
6877
+ hasVerticalWriting: true
6878
+ });
6879
+ } else {
6880
+ this.context.update({
6881
+ hasVerticalWriting: false
6882
+ });
6883
+ }
6884
+ })
6885
+ )
6886
+ );
6887
+ return rxjs.merge(...itemsLayout$, ...writingModeUpdate$);
6888
+ })
6889
+ ).pipe(rxjs.takeUntil(this.destroy$)).subscribe();
6890
+ this.layout$ = this.layoutSubject.pipe(
6891
+ rxjs.map((hasChanged) => ({ hasChanged })),
6892
+ rxjs.startWith({ hasChanged: true }),
6893
+ rxjs.map(({ hasChanged }) => {
6894
+ const items = spineItemsManager.items;
6895
+ const spineItemsPagesAbsolutePositions = items.map((item) => {
6896
+ const itemLayout = this.getAbsolutePositionOf(item);
6897
+ const numberOfPages = getSpineItemNumberOfPages({
6898
+ isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
6899
+ itemHeight: itemLayout.height,
6900
+ itemWidth: itemLayout.width,
6901
+ context,
6902
+ settings
6903
+ });
6904
+ const pages2 = new Array(numberOfPages).fill(void 0);
6905
+ return pages2.map(
6906
+ (_, pageIndex) => convertSpinePositionToLayoutPosition({
6907
+ pageSize: this.context.getPageSize(),
6908
+ position: getSpinePositionFromSpineItemPosition({
6909
+ itemLayout,
6910
+ spineItemPosition: getSpineItemPositionFromPageIndex({
6911
+ isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
6912
+ itemLayout,
6913
+ pageIndex,
6914
+ context
6915
+ })
6916
+ })
6917
+ })
6918
+ );
6919
+ });
6920
+ const pages = spineItemsPagesAbsolutePositions.reduce(
6921
+ (acc, itemPages, itemIndex) => {
6922
+ const itemPagesInfo = itemPages.map(
6923
+ (absolutePosition, pageIndex) => ({
6924
+ itemIndex,
6925
+ absolutePageIndex: itemIndex + pageIndex,
6926
+ absolutePosition
6927
+ })
6928
+ );
6929
+ return [...acc, ...itemPagesInfo];
6930
+ },
6931
+ []
6932
+ );
6933
+ return {
6934
+ hasChanged,
6935
+ spineItemsAbsolutePositions: items.map(
6936
+ (item) => this.getAbsolutePositionOf(item)
6937
+ ),
6938
+ spineItemsPagesAbsolutePositions,
6939
+ pages
6940
+ };
6941
+ }),
6942
+ rxjs.shareReplay(1)
6943
+ );
6944
+ }
6945
+ /**
6946
+ * @todo
6947
+ * move this logic to the spine
6948
+ *
6949
+ * @todo
6950
+ * make sure to check how many times it is being called and try to reduce number of layouts
6951
+ * it is called eery time an item is being unload (which can adds up quickly for big books)
6952
+ */
6953
+ layout() {
6954
+ const manifest = this.context.manifest;
6955
+ const newItemLayoutInformation = [];
6956
+ const isGloballyPrePaginated = (manifest == null ? void 0 : manifest.renditionLayout) === `pre-paginated`;
6957
+ this.spineItemsManager.items.reduce(
6958
+ ({ horizontalOffset, verticalOffset }, item, index) => {
6959
+ let minimumWidth = this.context.getPageSize().width;
6960
+ let blankPagePosition = `none`;
6961
+ const itemStartOnNewScreen = horizontalOffset % this.context.state.visibleAreaRect.width === 0;
6962
+ const isLastItem = index === this.spineItemsManager.items.length - 1;
6963
+ if (this.context.state.isUsingSpreadMode) {
6964
+ if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && !isLastItem) {
6965
+ minimumWidth = this.context.getPageSize().width * 2;
6966
+ }
6967
+ if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && isLastItem && itemStartOnNewScreen) {
6968
+ minimumWidth = this.context.getPageSize().width * 2;
6969
+ }
6970
+ const lastItemStartOnNewScreenInAPrepaginatedBook = itemStartOnNewScreen && isLastItem && isGloballyPrePaginated;
6971
+ if (item.item.pageSpreadRight && itemStartOnNewScreen && !this.context.isRTL()) {
6972
+ blankPagePosition = `before`;
6973
+ minimumWidth = this.context.getPageSize().width * 2;
6974
+ } else if (item.item.pageSpreadLeft && itemStartOnNewScreen && this.context.isRTL()) {
6975
+ blankPagePosition = `before`;
6976
+ minimumWidth = this.context.getPageSize().width * 2;
6977
+ } else if (lastItemStartOnNewScreenInAPrepaginatedBook) {
6978
+ if (this.context.isRTL()) {
6979
+ blankPagePosition = `before`;
6980
+ } else {
6981
+ blankPagePosition = `after`;
6982
+ }
6983
+ minimumWidth = this.context.getPageSize().width * 2;
6984
+ }
6985
+ }
6986
+ const { width, height } = item.layout({
6987
+ minimumWidth,
6988
+ blankPagePosition,
6989
+ spreadPosition: this.context.state.isUsingSpreadMode ? itemStartOnNewScreen ? this.context.isRTL() ? `right` : `left` : this.context.isRTL() ? `left` : `right` : `none`
6990
+ });
6991
+ if (this.settings.values.computedPageTurnDirection === `vertical`) {
6992
+ const currentValidEdgeYForVerticalPositioning = itemStartOnNewScreen ? verticalOffset : verticalOffset - this.context.state.visibleAreaRect.height;
6993
+ const currentValidEdgeXForVerticalPositioning = itemStartOnNewScreen ? 0 : horizontalOffset;
6994
+ if (this.context.isRTL()) {
6995
+ item.adjustPositionOfElement({
6996
+ top: currentValidEdgeYForVerticalPositioning,
6997
+ left: currentValidEdgeXForVerticalPositioning
6998
+ });
6999
+ } else {
7000
+ item.adjustPositionOfElement({
7001
+ top: currentValidEdgeYForVerticalPositioning,
7002
+ left: currentValidEdgeXForVerticalPositioning
7003
+ });
7004
+ }
7005
+ const newEdgeX = width + currentValidEdgeXForVerticalPositioning;
7006
+ const newEdgeY = height + currentValidEdgeYForVerticalPositioning;
7007
+ newItemLayoutInformation.push({
7008
+ left: currentValidEdgeXForVerticalPositioning,
7009
+ right: newEdgeX,
7010
+ top: currentValidEdgeYForVerticalPositioning,
7011
+ bottom: newEdgeY,
7012
+ height,
7013
+ width,
7014
+ x: currentValidEdgeXForVerticalPositioning,
7015
+ y: currentValidEdgeYForVerticalPositioning
7016
+ });
7017
+ return {
7018
+ horizontalOffset: newEdgeX,
7019
+ verticalOffset: newEdgeY
7020
+ };
7021
+ }
7022
+ item.adjustPositionOfElement(
7023
+ this.context.isRTL() ? { right: horizontalOffset, top: 0 } : { left: horizontalOffset, top: 0 }
7024
+ );
7025
+ const left = this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset - width : horizontalOffset;
7026
+ newItemLayoutInformation.push({
7027
+ right: this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset : horizontalOffset + width,
7028
+ left,
7029
+ x: left,
7030
+ top: verticalOffset,
7031
+ bottom: height,
7032
+ height,
7033
+ width,
7034
+ y: verticalOffset
7035
+ });
7036
+ return {
7037
+ horizontalOffset: horizontalOffset + width,
7038
+ verticalOffset: 0
7039
+ };
7040
+ },
7041
+ { horizontalOffset: 0, verticalOffset: 0 }
7042
+ );
7043
+ const hasLayoutChanges = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
7044
+ (old, index) => !shared.isShallowEqual(old, newItemLayoutInformation[index])
7045
+ );
7046
+ this.itemLayoutInformation = newItemLayoutInformation;
7047
+ Report.log(NAMESPACE, `layout`, {
7048
+ hasLayoutChanges,
7049
+ itemLayoutInformation: this.itemLayoutInformation
7050
+ });
7051
+ this.layoutSubject.next(hasLayoutChanges);
7052
+ }
7053
+ /**
7054
+ * It's important to not use x,y since we need the absolute position of each element. Otherwise x,y would be relative to
7055
+ * current window (viewport).
7056
+ */
7057
+ getAbsolutePositionOf(spineItemOrIndex) {
7058
+ const fallback = {
7059
+ left: 0,
7060
+ right: 0,
7061
+ top: 0,
7062
+ bottom: 0,
7063
+ width: 0,
7064
+ height: 0,
7065
+ x: 0,
7066
+ y: 0
7067
+ };
7068
+ const spineItem = this.spineItemsManager.get(spineItemOrIndex);
7069
+ const indexOfItem = spineItem ? this.spineItemsManager.items.indexOf(spineItem) : -1;
7070
+ const layoutInformation = this.itemLayoutInformation[indexOfItem];
7071
+ return layoutInformation || fallback;
7072
+ }
7073
+ destroy() {
7074
+ super.destroy();
7075
+ this.layoutSubject.complete();
7076
+ }
7077
+ }
6953
7078
  class Spine extends DestroyableClass {
6954
7079
  constructor(parentElement$, context, pagination, spineItemsManager, spineItemLocator, settings, hookManager) {
6955
7080
  super();
@@ -6966,17 +7091,24 @@
6966
7091
  operators.share()
6967
7092
  );
6968
7093
  this.element$ = this.elementSubject.asObservable();
7094
+ this.spineLayout = new SpineLayout(spineItemsManager, context, settings);
6969
7095
  this.locator = createSpineLocator({
6970
7096
  context,
6971
7097
  spineItemsManager,
6972
7098
  spineItemLocator,
6973
- settings
7099
+ settings,
7100
+ spineLayout: this.spineLayout
6974
7101
  });
6975
7102
  this.spineItemsLoader = new SpineItemsLoader(
6976
7103
  this.context,
6977
7104
  spineItemsManager,
6978
7105
  this.locator,
6979
- settings
7106
+ settings,
7107
+ this.spineLayout
7108
+ );
7109
+ this.spineItemsObserver = new SpineItemsObserver(
7110
+ spineItemsManager,
7111
+ this.locator
6980
7112
  );
6981
7113
  const reloadOnManifestChange$ = context.manifest$.pipe(
6982
7114
  operators.tap((manifest) => {
@@ -7011,7 +7143,7 @@
7011
7143
  return this.elementSubject.getValue();
7012
7144
  }
7013
7145
  layout() {
7014
- this.spineItemsManager.layout();
7146
+ this.spineLayout.layout();
7015
7147
  }
7016
7148
  isSelecting() {
7017
7149
  return this.spineItemsManager.items.some(
@@ -7022,9 +7154,6 @@
7022
7154
  var _a;
7023
7155
  return (_a = this.spineItemsManager.items.find((item) => item.selectionTracker.getSelection())) == null ? void 0 : _a.selectionTracker.getSelection();
7024
7156
  }
7025
- get layout$() {
7026
- return this.spineItemsManager.layout$;
7027
- }
7028
7157
  destroy() {
7029
7158
  super.destroy();
7030
7159
  this.spineItemsLoader.destroy();
@@ -7062,11 +7191,9 @@
7062
7191
  settingsManager,
7063
7192
  hookManager
7064
7193
  );
7065
- const spineItemsObserver = new SpineItemsObserver(spineItemsManager);
7066
7194
  const navigator2 = createNavigator({
7067
7195
  context,
7068
7196
  spineItemsManager,
7069
- spineItemsObserver,
7070
7197
  parentElement$: elementSubject$,
7071
7198
  hookManager,
7072
7199
  spine,
@@ -7112,26 +7239,27 @@
7112
7239
  });
7113
7240
  spine.layout();
7114
7241
  };
7115
- const load = (manifest, loadOptions) => {
7242
+ const load = (options) => {
7116
7243
  var _a;
7244
+ const { containerElement, manifest } = options;
7117
7245
  if (context.manifest) {
7118
7246
  Report.warn(`loading a new book is not supported yet`);
7119
7247
  return;
7120
7248
  }
7121
- Report.log(`load`, { manifest, loadOptions });
7122
- const element = createWrapperElement(loadOptions.containerElement);
7123
- if (loadOptions.containerElement !== ((_a = elementSubject$.getValue()) == null ? void 0 : _a.parentElement)) {
7249
+ Report.log(`load`, { options });
7250
+ const element = createWrapperElement(containerElement);
7251
+ if (containerElement !== ((_a = elementSubject$.getValue()) == null ? void 0 : _a.parentElement)) {
7124
7252
  elementSubject$.next(element);
7125
- loadOptions.containerElement.appendChild(element);
7253
+ containerElement.appendChild(element);
7126
7254
  }
7127
7255
  context.update({
7128
7256
  manifest,
7129
- ...loadOptions,
7130
- forceSinglePageMode: settingsManager.settings.forceSinglePageMode
7257
+ containerElement,
7258
+ forceSinglePageMode: settingsManager.values.forceSinglePageMode
7131
7259
  });
7132
7260
  layout();
7133
7261
  };
7134
- rxjs.merge(context.state$, settingsManager.settings$).pipe(
7262
+ rxjs.merge(context.state$, settingsManager.values$).pipe(
7135
7263
  operators.map(() => void 0),
7136
7264
  operators.withLatestFrom(context.state$),
7137
7265
  operators.map(([, { hasVerticalWriting }]) => {
@@ -7140,10 +7268,10 @@
7140
7268
  hasVerticalWriting,
7141
7269
  renditionFlow: manifest == null ? void 0 : manifest.renditionFlow,
7142
7270
  renditionLayout: manifest == null ? void 0 : manifest.renditionLayout,
7143
- computedPageTurnMode: settingsManager.settings.computedPageTurnMode
7271
+ computedPageTurnMode: settingsManager.values.computedPageTurnMode
7144
7272
  };
7145
7273
  }),
7146
- operators.distinctUntilChanged(isShallowEqual),
7274
+ operators.distinctUntilChanged(shared.isShallowEqual),
7147
7275
  operators.map(
7148
7276
  ({
7149
7277
  hasVerticalWriting,
@@ -7181,22 +7309,23 @@
7181
7309
  hookManager,
7182
7310
  cfi: {
7183
7311
  generateCfiFromRange,
7312
+ generateCfiForSpineItemPage: (params) => generateCfiForSpineItemPage({
7313
+ ...params,
7314
+ spineItemLocator
7315
+ }),
7184
7316
  resolveCfi: (params) => resolveCfi({ ...params, spineItemsManager })
7185
7317
  },
7186
7318
  navigation: {
7187
7319
  viewportFree$: context.bridgeEvent.viewportFree$,
7188
7320
  viewportBusy$: context.bridgeEvent.viewportBusy$,
7189
- // rest safe
7190
- get viewportPosition() {
7191
- return navigator2.viewportNavigator.viewportPosition;
7192
- },
7321
+ getViewportPosition: () => navigator2.viewportNavigator.viewportPosition,
7193
7322
  getNavigation: navigator2.getNavigation.bind(navigator2),
7194
7323
  getElement: navigator2.getElement.bind(navigator2),
7195
7324
  navigate: navigator2.navigate.bind(navigator2),
7196
7325
  lock: navigator2.lock.bind(navigator2),
7197
7326
  navigationResolver: navigator2.navigationResolver
7198
7327
  },
7199
- spineItemsObserver,
7328
+ spineItemsObserver: spine.spineItemsObserver,
7200
7329
  spineItemsManager,
7201
7330
  layout,
7202
7331
  load,
@@ -7207,17 +7336,19 @@
7207
7336
  },
7208
7337
  settings: settingsManager,
7209
7338
  element$,
7339
+ layout$: spine.spineLayout.layout$,
7340
+ viewportState$: context.bridgeEvent.viewportState$,
7341
+ /**
7342
+ * Dispatched when the reader has loaded a book and is rendering a book.
7343
+ * Using navigation API and getting information about current content will
7344
+ * have an effect.
7345
+ * It can typically be used to hide a loading indicator.
7346
+ */
7347
+ state$: context.manifest$.pipe(
7348
+ operators.map((manifest) => manifest ? "ready" : "idle")
7349
+ ),
7210
7350
  $: {
7211
7351
  state$: stateSubject$.asObservable(),
7212
- /**
7213
- * Dispatched when the reader has loaded a book and is rendering a book.
7214
- * Using navigation API and getting information about current content will
7215
- * have an effect.
7216
- * It can typically be used to hide a loading indicator.
7217
- */
7218
- loadStatus$: context.manifest$.pipe(
7219
- operators.map((manifest) => manifest ? "ready" : "idle")
7220
- ),
7221
7352
  destroy$
7222
7353
  }
7223
7354
  };
@@ -7558,8 +7689,8 @@
7558
7689
  };
7559
7690
  const getScrollPercentageWithinItem = (context, currentPosition, currentItem) => {
7560
7691
  const { height, width } = currentItem.getElementDimensions();
7561
- const { top, left } = reader.spineItemsManager.getAbsolutePositionOf(currentItem);
7562
- if (reader.settings.settings.computedPageTurnDirection === `vertical`) {
7692
+ const { top, left } = reader.spine.spineLayout.getAbsolutePositionOf(currentItem);
7693
+ if (reader.settings.values.computedPageTurnDirection === `vertical`) {
7563
7694
  return Math.max(
7564
7695
  0,
7565
7696
  Math.min(
@@ -7679,12 +7810,12 @@
7679
7810
  };
7680
7811
  }, {})
7681
7812
  );
7682
- const updateEntriesLayout$ = (entries) => rxjs.combineLatest([reader.spine.layout$, reader.theme.$.theme$]).pipe(
7813
+ const updateEntriesLayout$ = (entries) => rxjs.combineLatest([reader.layout$, reader.theme.$.theme$]).pipe(
7683
7814
  operators.map(([, theme]) => ({
7684
7815
  width: reader.context.state.visibleAreaRect.width,
7685
7816
  theme
7686
7817
  })),
7687
- operators.distinctUntilChanged(isShallowEqual),
7818
+ operators.distinctUntilChanged(shared.isShallowEqual),
7688
7819
  operators.tap(({ width, theme }) => {
7689
7820
  Object.values(entries).forEach((element) => {
7690
7821
  element.style.setProperty(`max-width`, `${width}px`);
@@ -7770,84 +7901,74 @@
7770
7901
  container.appendChild(detailsElement);
7771
7902
  return container;
7772
7903
  };
7773
- const createNormalizeEventForViewport = ({
7774
- iframeEventBridgeElement$,
7775
- locator
7776
- }) => {
7777
- const normalizeEventForViewport = (event) => {
7778
- var _a;
7779
- const eventIsComingFromBridge = event.target === iframeEventBridgeElement$.getValue();
7780
- const iframeOriginalEvent = getOriginalFrameEventFromDocumentEvent(event);
7781
- const originalFrame = (_a = iframeOriginalEvent == null ? void 0 : iframeOriginalEvent.view) == null ? void 0 : _a.frameElement;
7782
- if (!eventIsComingFromBridge || !iframeOriginalEvent || !originalFrame)
7783
- return event;
7784
- const spineItem = locator.getSpineItemFromIframe(originalFrame);
7785
- if (!spineItem) return event;
7786
- if (isPointerEvent(event)) {
7787
- const { clientX, clientY } = spineItem.translateFramePositionIntoPage(event);
7788
- const newEvent = new PointerEvent(event.type, {
7789
- ...event,
7790
- pointerId: event.pointerId,
7791
- clientX,
7792
- clientY
7793
- });
7794
- Object.defineProperty(newEvent, `target`, {
7795
- value: iframeOriginalEvent.target,
7796
- enumerable: true
7797
- });
7798
- return newEvent;
7799
- }
7800
- if (isMouseEvent(event)) {
7801
- const { clientX, clientY } = spineItem.translateFramePositionIntoPage(event);
7802
- const newEvent = new MouseEvent(event.type, {
7803
- ...event,
7904
+ const __UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY = `__UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT`;
7905
+ const attachOriginalFrameEventToDocumentEvent = (event, frameEvent) => {
7906
+ Object.defineProperty(event, __UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY, {
7907
+ value: frameEvent,
7908
+ enumerable: true
7909
+ });
7910
+ };
7911
+ const getOriginalFrameEventFromDocumentEvent = (event) => {
7912
+ return event[__UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY];
7913
+ };
7914
+ const normalizeEventForViewport = (event, locator) => {
7915
+ var _a;
7916
+ const eventIsComingFromBridge = __UNSAFE_REFERENCE_ORIGINAL_IFRAME_EVENT_KEY in event;
7917
+ const iframeOriginalEvent = getOriginalFrameEventFromDocumentEvent(event);
7918
+ const originalFrame = (_a = iframeOriginalEvent == null ? void 0 : iframeOriginalEvent.view) == null ? void 0 : _a.frameElement;
7919
+ if (!eventIsComingFromBridge || !iframeOriginalEvent || !originalFrame)
7920
+ return event;
7921
+ const spineItem = locator.getSpineItemFromIframe(originalFrame);
7922
+ if (!spineItem) return event;
7923
+ if (isPointerEvent(event)) {
7924
+ const { clientX, clientY } = spineItem.translateFramePositionIntoPage(event);
7925
+ const newEvent = new PointerEvent(event.type, {
7926
+ ...event,
7927
+ pointerId: event.pointerId,
7928
+ clientX,
7929
+ clientY
7930
+ });
7931
+ Object.defineProperty(newEvent, `target`, {
7932
+ value: iframeOriginalEvent.target,
7933
+ enumerable: true
7934
+ });
7935
+ return newEvent;
7936
+ }
7937
+ if (isMouseEvent(event)) {
7938
+ const { clientX, clientY } = spineItem.translateFramePositionIntoPage(event);
7939
+ const newEvent = new MouseEvent(event.type, {
7940
+ ...event,
7941
+ clientX,
7942
+ clientY
7943
+ });
7944
+ Object.defineProperty(newEvent, `target`, {
7945
+ value: iframeOriginalEvent.target,
7946
+ enumerable: true
7947
+ });
7948
+ return newEvent;
7949
+ }
7950
+ if (isTouchEvent(event)) {
7951
+ const touches = Array.from(event.touches).map((touch) => {
7952
+ const { clientX, clientY } = spineItem.translateFramePositionIntoPage(touch);
7953
+ return new Touch({
7954
+ identifier: touch.identifier,
7955
+ target: touch.target,
7804
7956
  clientX,
7805
7957
  clientY
7806
7958
  });
7807
- Object.defineProperty(newEvent, `target`, {
7808
- value: iframeOriginalEvent.target,
7809
- enumerable: true
7810
- });
7811
- return newEvent;
7812
- }
7813
- if (isTouchEvent(event)) {
7814
- const touches = Array.from(event.touches).map((touch) => {
7815
- const { clientX, clientY } = spineItem.translateFramePositionIntoPage(touch);
7816
- return new Touch({
7817
- identifier: touch.identifier,
7818
- target: touch.target,
7819
- clientX,
7820
- clientY
7821
- });
7822
- });
7823
- const newEvent = new TouchEvent(event.type, {
7824
- touches,
7825
- changedTouches: touches,
7826
- targetTouches: touches
7827
- });
7828
- Object.defineProperty(newEvent, `target`, {
7829
- value: iframeOriginalEvent.target,
7830
- enumerable: true
7831
- });
7832
- return newEvent;
7833
- }
7834
- return event;
7835
- };
7836
- return normalizeEventForViewport;
7837
- };
7838
- const IFRAME_EVENT_BRIDGE_ELEMENT_ID = `proseReaderIframeEventBridgeElement`;
7839
- const createIframeEventBridgeElement = (container) => {
7840
- const iframeEventBridgeElement = container.ownerDocument.createElement(`div`);
7841
- iframeEventBridgeElement.id = IFRAME_EVENT_BRIDGE_ELEMENT_ID;
7842
- iframeEventBridgeElement.style.cssText = `
7843
- position: absolute;
7844
- height: 100%;
7845
- width: 100%;
7846
- top: 0;
7847
- left: 0;
7848
- z-index: -1;
7849
- `;
7850
- return iframeEventBridgeElement;
7959
+ });
7960
+ const newEvent = new TouchEvent(event.type, {
7961
+ touches,
7962
+ changedTouches: touches,
7963
+ targetTouches: touches
7964
+ });
7965
+ Object.defineProperty(newEvent, `target`, {
7966
+ value: iframeOriginalEvent.target,
7967
+ enumerable: true
7968
+ });
7969
+ return newEvent;
7970
+ }
7971
+ return event;
7851
7972
  };
7852
7973
  const pointerEvents = [
7853
7974
  `pointercancel`,
@@ -7857,23 +7978,13 @@
7857
7978
  `pointermove`,
7858
7979
  `pointerout`,
7859
7980
  `pointerover`,
7860
- `pointerup`,
7861
- `touchstart`,
7862
- `touchend`
7981
+ `pointerup`
7863
7982
  ];
7864
- const mouseEvents = [
7865
- `click`,
7866
- `mousedown`,
7867
- `mouseup`,
7868
- `mouseenter`,
7869
- `mouseleave`,
7870
- `mousemove`,
7871
- `mouseout`,
7872
- `mouseover`
7983
+ const passthroughEvents = [
7984
+ ...pointerEvents
7985
+ /*, ...mouseEvents*/
7873
7986
  ];
7874
- const passthroughEvents = [...pointerEvents, ...mouseEvents];
7875
7987
  const eventsEnhancer = (next) => (options) => {
7876
- const iframeEventBridgeElement$ = new rxjs.BehaviorSubject(void 0);
7877
7988
  const reader = next(options);
7878
7989
  reader.hookManager.register(`item.onLoad`, ({ destroy, frame, itemId }) => {
7879
7990
  const item = reader.spineItemsManager.get(itemId);
@@ -7886,12 +7997,15 @@
7886
7997
  if (isPointerEvent(e)) {
7887
7998
  convertedEvent = new PointerEvent(e.type, e);
7888
7999
  }
7889
- if (isMouseEvent(e)) {
7890
- convertedEvent = new MouseEvent(e.type, e);
7891
- }
7892
8000
  if (convertedEvent !== e) {
7893
8001
  attachOriginalFrameEventToDocumentEvent(convertedEvent, e);
7894
- (_a2 = iframeEventBridgeElement$.getValue()) == null ? void 0 : _a2.dispatchEvent(convertedEvent);
8002
+ const normalizedEvent = normalizeEventForViewport(
8003
+ convertedEvent,
8004
+ reader.spine.locator
8005
+ );
8006
+ (_a2 = reader.context.state.containerElement) == null ? void 0 : _a2.dispatchEvent(
8007
+ normalizedEvent
8008
+ );
7895
8009
  }
7896
8010
  };
7897
8011
  (_a = frame.contentDocument) == null ? void 0 : _a.addEventListener(event, listener);
@@ -7906,25 +8020,7 @@
7906
8020
  unregister.forEach((cb) => cb());
7907
8021
  });
7908
8022
  });
7909
- reader.element$.pipe(
7910
- rxjs.tap((wrapper) => {
7911
- var _a;
7912
- const iframeEventBridgeElement = createIframeEventBridgeElement(wrapper);
7913
- wrapper.appendChild(iframeEventBridgeElement);
7914
- (_a = iframeEventBridgeElement$.getValue()) == null ? void 0 : _a.remove();
7915
- iframeEventBridgeElement$.next(iframeEventBridgeElement);
7916
- }),
7917
- rxjs.takeUntil(reader.$.destroy$)
7918
- ).subscribe();
7919
- return {
7920
- ...reader,
7921
- events: {
7922
- normalizeEventForViewport: createNormalizeEventForViewport({
7923
- iframeEventBridgeElement$,
7924
- locator: reader.spine.locator
7925
- })
7926
- }
7927
- };
8023
+ return reader;
7928
8024
  };
7929
8025
  const createReaderWithEnhancers = (
7930
8026
  //__
@@ -7965,12 +8061,16 @@
7965
8061
  )
7966
8062
  )
7967
8063
  );
8064
+ Object.defineProperty(exports2, "isShallowEqual", {
8065
+ enumerable: true,
8066
+ get: () => shared.isShallowEqual
8067
+ });
7968
8068
  exports2.HookManager = HookManager;
7969
8069
  exports2.Report = Report;
7970
8070
  exports2.SettingsManager = SettingsManager;
7971
8071
  exports2.createReader = createReaderWithEnhancers;
7972
- exports2.groupBy = groupBy;
7973
- exports2.isShallowEqual = isShallowEqual;
8072
+ exports2.isHtmlElement = isHtmlElement;
8073
+ exports2.waitForSwitch = waitForSwitch;
7974
8074
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
7975
8075
  });
7976
8076
  //# sourceMappingURL=index.umd.cjs.map