@prose-reader/core 1.177.0 → 1.179.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { switchMap, of, fromEvent, take, map, from, takeUntil, Observable, defer, Subject, combineLatest, merge, EMPTY, withLatestFrom, BehaviorSubject, filter, share, first as first$1, mergeMap, endWith, tap as tap$1, finalize, catchError, lastValueFrom, NEVER, scheduled, animationFrameScheduler, distinctUntilChanged as distinctUntilChanged$1, throttleTime, debounceTime as debounceTime$1, startWith as startWith$1, switchScan, forkJoin, shareReplay as shareReplay$1, delay, ReplaySubject, identity, timer, skip as skip$1, exhaustMap, reduce, concatMap } from "rxjs";
2
2
  import { switchMap as switchMap$1, first, map as map$1, startWith, shareReplay, distinctUntilChanged, tap, pairwise, take as take$1, takeUntil as takeUntil$1, filter as filter$1, debounceTime, skip, mergeMap as mergeMap$1, catchError as catchError$1, withLatestFrom as withLatestFrom$1, share as share$1 } from "rxjs/operators";
3
- import { shallowMergeIfDefined, isShallowEqual, parseContentType, detectMimeTypeFromName, getParentPath, arrayEqual } from "@prose-reader/shared";
3
+ import { shallowMergeIfDefined, isShallowEqual, getParentPath, parseContentType, detectMimeTypeFromName, arrayEqual } from "@prose-reader/shared";
4
4
  import { isShallowEqual as isShallowEqual2 } from "@prose-reader/shared";
5
5
  const getAttributeValueFromString = (string, key) => {
6
6
  const regExp = new RegExp(`${key}\\s*=\\s*([0-9.]+)`, `i`);
@@ -413,6 +413,51 @@ const isTouchEvent = (event) => {
413
413
  return false;
414
414
  };
415
415
  const noopElement = () => document.createElement("div");
416
+ const getElementsWithAssets = (_document) => {
417
+ const RESOURCE_ELEMENTS = [
418
+ "img",
419
+ // Images
420
+ "video",
421
+ // Video files
422
+ "audio",
423
+ // Audio files
424
+ "source",
425
+ // Source elements within video/audio
426
+ "link",
427
+ // Stylesheets and other linked resources
428
+ "script"
429
+ // JavaScript files
430
+ ].join(",");
431
+ return Array.from((_document == null ? void 0 : _document.querySelectorAll(RESOURCE_ELEMENTS)) || []);
432
+ };
433
+ const revokeDocumentBlobs = (_document) => {
434
+ const elementsWithAsset = getElementsWithAssets(_document);
435
+ elementsWithAsset.forEach((element) => {
436
+ var _a;
437
+ const url = element.getAttribute("src") || element.getAttribute("href");
438
+ if (url == null ? void 0 : url.startsWith("blob:")) {
439
+ (_a = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a.URL.revokeObjectURL(url);
440
+ }
441
+ });
442
+ if (_document) {
443
+ const styleSheets = Array.from(_document.styleSheets || []);
444
+ for (const sheet of styleSheets) {
445
+ const rules = Array.from(sheet.cssRules || []);
446
+ for (const rule of rules) {
447
+ if (_document.defaultView && rule instanceof _document.defaultView.CSSFontFaceRule) {
448
+ const src = rule.style.getPropertyValue("src");
449
+ const blobUrls = src.match(/blob:[^,\s'")]+/g);
450
+ if (blobUrls) {
451
+ blobUrls.forEach((url) => {
452
+ var _a;
453
+ (_a = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a.URL.revokeObjectURL(url);
454
+ });
455
+ }
456
+ }
457
+ }
458
+ }
459
+ }
460
+ };
416
461
  const translateFramePositionIntoPage = ({
417
462
  position,
418
463
  frameElement
@@ -1054,31 +1099,169 @@ class DocumentRenderer extends DestroyableClass {
1054
1099
  return ((_a = this.context.manifest) == null ? void 0 : _a.renditionLayout) ?? "reflowable";
1055
1100
  }
1056
1101
  }
1057
- const createFrameElement = Report.measurePerformance(
1058
- `SpineItemFrame createFrame`,
1059
- Infinity,
1060
- () => {
1061
- const frame = document.createElement(`iframe`);
1062
- frame.frameBorder = `no`;
1063
- frame.tabIndex = 0;
1064
- frame.setAttribute(
1065
- `sandbox`,
1066
- `
1067
- allow-same-origin
1068
- allow-scripts
1069
- allow-top-navigation-to-custom-protocols
1070
- `
1102
+ const defaultGetResource = (item) => new URL(item.href);
1103
+ class ResourceHandler {
1104
+ constructor(item, settings) {
1105
+ this.item = item;
1106
+ this.settings = settings;
1107
+ }
1108
+ async getResource() {
1109
+ var _a, _b;
1110
+ const resource = await lastValueFrom(
1111
+ ((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
1071
1112
  );
1072
- frame.style.cssText = `
1073
- overflow: hidden;
1074
- background-color: transparent;
1075
- border: 0px none transparent;
1076
- padding: 0px;
1077
- `;
1078
- frame.setAttribute(`role`, `main`);
1079
- return frame;
1113
+ return resource ?? defaultGetResource(this.item);
1114
+ }
1115
+ async fetchResource() {
1116
+ const resource = await this.getResource();
1117
+ if (resource instanceof Response) return resource;
1118
+ if (resource instanceof URL) return fetch(resource);
1119
+ return resource;
1120
+ }
1121
+ }
1122
+ const joinPath = (base, path) => {
1123
+ const isFileProtocol = base.startsWith("file://");
1124
+ const tempBase = isFileProtocol ? base.replace("file://", "http://") : base;
1125
+ const result = new URL(path, tempBase).toString();
1126
+ return isFileProtocol ? result.replace("http://", "file://") : result;
1127
+ };
1128
+ const loadFontFaces = async (document2, element, spineItemUriParentPath, context, settings) => {
1129
+ if (!document2 || !document2.defaultView) return;
1130
+ const sheet = element.sheet;
1131
+ if (!sheet) return;
1132
+ try {
1133
+ const rules = Array.from(sheet.cssRules || []);
1134
+ for (let i = 0; i < rules.length; i++) {
1135
+ const rule = rules[i];
1136
+ if (document2.defaultView && rule instanceof document2.defaultView.CSSFontFaceRule) {
1137
+ const src = rule.style.getPropertyValue("src");
1138
+ const matches = src.match(/url\(['"]?([^'"]+)['"]?\)/g);
1139
+ if (matches) {
1140
+ const srcParts = src.split(",").map((part) => part.trim());
1141
+ const newSrcParts = await Promise.all(
1142
+ srcParts.map(async (part) => {
1143
+ var _a, _b;
1144
+ if (part.startsWith("local(")) {
1145
+ return part;
1146
+ }
1147
+ const urlMatch = part.match(/url\(['"]?([^'"]+)['"]?\)/);
1148
+ if (!urlMatch) return part;
1149
+ const originalSrc = urlMatch[1] ?? ``;
1150
+ const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1151
+ return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1152
+ `${href.toLowerCase()}`
1153
+ );
1154
+ });
1155
+ if (foundItem) {
1156
+ const resourceHandler = new ResourceHandler(foundItem, settings);
1157
+ try {
1158
+ const resource = await resourceHandler.getResource();
1159
+ if (resource instanceof Response) {
1160
+ const blob = await resource.blob();
1161
+ const blobUrl = (_b = document2.defaultView) == null ? void 0 : _b.URL.createObjectURL(blob);
1162
+ const newPart = part.replace(
1163
+ urlMatch[0],
1164
+ `url("${blobUrl}")`
1165
+ );
1166
+ return newPart;
1167
+ }
1168
+ } catch (e) {
1169
+ console.error("Error loading font:", e);
1170
+ }
1171
+ }
1172
+ return part;
1173
+ })
1174
+ );
1175
+ const newRule = rule.cssText.replace(
1176
+ /src:\s*[^;]+;/,
1177
+ `src: ${newSrcParts.join(", ")};`
1178
+ );
1179
+ sheet.deleteRule(i);
1180
+ sheet.insertRule(newRule, i);
1181
+ }
1182
+ }
1183
+ }
1184
+ } catch (e) {
1185
+ console.error("Could not access stylesheet rules:", e);
1080
1186
  }
1187
+ };
1188
+ const loadElementSrc = (_document, element, spineItemUriParentPath, context, settings) => {
1189
+ var _a;
1190
+ const originalSrc = element.getAttribute("src") || element.getAttribute("href");
1191
+ if (!originalSrc) return of(null);
1192
+ const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1193
+ return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1194
+ `${href.toLowerCase()}`
1195
+ );
1196
+ });
1197
+ if (!foundItem) return of(null);
1198
+ const resourceHandler = new ResourceHandler(foundItem, settings);
1199
+ return from(resourceHandler.getResource()).pipe(
1200
+ mergeMap(
1201
+ (resource) => resource instanceof Response ? from(resource.blob()) : of(void 0)
1202
+ ),
1203
+ mergeMap((blob) => {
1204
+ var _a2;
1205
+ if (!blob) {
1206
+ return of(null);
1207
+ }
1208
+ const blobUrl = ((_a2 = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a2.URL.createObjectURL(blob)) ?? ``;
1209
+ if (element.hasAttribute("src")) {
1210
+ element.setAttribute("src", blobUrl);
1211
+ } else if (element.hasAttribute("href")) {
1212
+ element.setAttribute("href", blobUrl);
1213
+ if ((_document == null ? void 0 : _document.defaultView) && element instanceof _document.defaultView.HTMLLinkElement) {
1214
+ return new Observable((observer) => {
1215
+ element.onload = async () => {
1216
+ try {
1217
+ if (element.sheet) {
1218
+ await loadFontFaces(
1219
+ _document,
1220
+ element,
1221
+ spineItemUriParentPath,
1222
+ context,
1223
+ settings
1224
+ );
1225
+ }
1226
+ observer.next();
1227
+ observer.complete();
1228
+ } catch (error) {
1229
+ observer.error(error);
1230
+ }
1231
+ };
1232
+ element.onerror = observer.error;
1233
+ });
1234
+ }
1235
+ }
1236
+ return of(null);
1237
+ })
1238
+ );
1239
+ };
1240
+ const loadAssets = ({
1241
+ settings,
1242
+ item,
1243
+ context
1244
+ }) => (stream) => stream.pipe(
1245
+ switchMap((frameElement) => {
1246
+ const elementsWithAsset = getElementsWithAssets(
1247
+ frameElement.contentDocument
1248
+ );
1249
+ const spineItemUriParentPath = getParentPath(item.href);
1250
+ const assetsLoad$ = elementsWithAsset.map(
1251
+ (element) => loadElementSrc(
1252
+ frameElement.contentDocument,
1253
+ element,
1254
+ spineItemUriParentPath,
1255
+ context,
1256
+ settings
1257
+ )
1258
+ );
1259
+ return combineLatest(assetsLoad$).pipe(map(() => frameElement));
1260
+ })
1081
1261
  );
1262
+ const unloadAssets = (frameElement) => {
1263
+ revokeDocumentBlobs(frameElement == null ? void 0 : frameElement.contentDocument);
1264
+ };
1082
1265
  const getIntrinsicDimensionsFromBase64Img = (data) => new Promise((resolve, reject) => {
1083
1266
  const image = new Image();
1084
1267
  image.src = data;
@@ -1181,6 +1364,31 @@ const attachFrameSrc = ({
1181
1364
  })
1182
1365
  );
1183
1366
  };
1367
+ const createFrameElement = Report.measurePerformance(
1368
+ `SpineItemFrame createFrame`,
1369
+ Infinity,
1370
+ () => {
1371
+ const frame = document.createElement(`iframe`);
1372
+ frame.frameBorder = `no`;
1373
+ frame.tabIndex = 0;
1374
+ frame.setAttribute(
1375
+ `sandbox`,
1376
+ `
1377
+ allow-same-origin
1378
+ allow-scripts
1379
+ allow-top-navigation-to-custom-protocols
1380
+ `
1381
+ );
1382
+ frame.style.cssText = `
1383
+ overflow: hidden;
1384
+ background-color: transparent;
1385
+ border: 0px none transparent;
1386
+ padding: 0px;
1387
+ `;
1388
+ frame.setAttribute(`role`, `main`);
1389
+ return frame;
1390
+ }
1391
+ );
1184
1392
  const getStyleForViewportDocument = () => {
1185
1393
  return `
1186
1394
  body {
@@ -1673,98 +1881,6 @@ const renderReflowable = ({
1673
1881
  latestContentHeightWhenLoaded: newLatestContentHeightWhenLoaded
1674
1882
  };
1675
1883
  };
1676
- const defaultGetResource = (item) => new URL(item.href);
1677
- class ResourceHandler {
1678
- constructor(item, settings) {
1679
- this.item = item;
1680
- this.settings = settings;
1681
- }
1682
- async getResource() {
1683
- var _a, _b;
1684
- const resource = await lastValueFrom(
1685
- ((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
1686
- );
1687
- return resource ?? defaultGetResource(this.item);
1688
- }
1689
- async fetchResource() {
1690
- const resource = await this.getResource();
1691
- if (resource instanceof Response) return resource;
1692
- if (resource instanceof URL) return fetch(resource);
1693
- return resource;
1694
- }
1695
- }
1696
- const joinPath = (base, path) => {
1697
- const isFileProtocol = base.startsWith("file://");
1698
- const tempBase = isFileProtocol ? base.replace("file://", "http://") : base;
1699
- const result = new URL(path, tempBase).toString();
1700
- return isFileProtocol ? result.replace("http://", "file://") : result;
1701
- };
1702
- const getElementsWithAssets = (document2) => {
1703
- const RESOURCE_ELEMENTS = [
1704
- "img",
1705
- // Images
1706
- "video",
1707
- // Video files
1708
- "audio",
1709
- // Audio files
1710
- "source",
1711
- // Source elements within video/audio
1712
- "link",
1713
- // Stylesheets and other linked resources
1714
- "script"
1715
- // JavaScript files
1716
- ].join(",");
1717
- return Array.from((document2 == null ? void 0 : document2.querySelectorAll(RESOURCE_ELEMENTS)) || []);
1718
- };
1719
- const loadAssets = ({
1720
- settings,
1721
- item,
1722
- context
1723
- }) => (stream) => stream.pipe(
1724
- switchMap((frameElement) => {
1725
- const elementsWithAsset = getElementsWithAssets(
1726
- frameElement.contentDocument
1727
- );
1728
- const assetsLoad$ = Array.from(elementsWithAsset).map((element) => {
1729
- var _a;
1730
- const originalSrc = element.getAttribute("src") || element.getAttribute("href");
1731
- if (!originalSrc) return of(null);
1732
- const spineItemUriParentPath = getParentPath(item.href);
1733
- const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1734
- return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1735
- `${href.toLowerCase()}`
1736
- );
1737
- });
1738
- if (!foundItem) return of(null);
1739
- const resourceHandler = new ResourceHandler(foundItem, settings);
1740
- return from(resourceHandler.getResource()).pipe(
1741
- mergeMap(
1742
- (resource) => resource instanceof Response ? from(resource.blob()) : of(void 0)
1743
- ),
1744
- tap$1((blob) => {
1745
- if (blob) {
1746
- const blobUrl = URL.createObjectURL(blob);
1747
- if (element.hasAttribute("src")) {
1748
- element.setAttribute("src", blobUrl);
1749
- } else if (element.hasAttribute("href")) {
1750
- element.setAttribute("href", blobUrl);
1751
- }
1752
- }
1753
- })
1754
- );
1755
- });
1756
- return combineLatest(assetsLoad$).pipe(map(() => frameElement));
1757
- })
1758
- );
1759
- const unloadMedias = (frameElement) => {
1760
- const elementsWithAsset = getElementsWithAssets(frameElement == null ? void 0 : frameElement.contentDocument);
1761
- elementsWithAsset.forEach((element) => {
1762
- const url = element.getAttribute("src") || element.getAttribute("href");
1763
- if (url == null ? void 0 : url.startsWith("blob:")) {
1764
- URL.revokeObjectURL(url);
1765
- }
1766
- });
1767
- };
1768
1884
  class HtmlRenderer extends DocumentRenderer {
1769
1885
  constructor() {
1770
1886
  super(...arguments);
@@ -1801,7 +1917,7 @@ class HtmlRenderer extends DocumentRenderer {
1801
1917
  );
1802
1918
  }
1803
1919
  onUnload() {
1804
- unloadMedias(this.getFrameElement());
1920
+ unloadAssets(this.getFrameElement());
1805
1921
  this.detach();
1806
1922
  return EMPTY;
1807
1923
  }
@@ -2513,7 +2629,8 @@ const mediaEnhancer = (next) => (options) => {
2513
2629
  destroy
2514
2630
  };
2515
2631
  };
2516
- const getSpineItemPositionForRightPage = ({
2632
+ const report$4 = Report.namespace(`navigation`);
2633
+ const getSpineItemPositionForLeftPage = ({
2517
2634
  position,
2518
2635
  spineItem,
2519
2636
  pageHeight,
@@ -2521,13 +2638,13 @@ const getSpineItemPositionForRightPage = ({
2521
2638
  spineItemLocator
2522
2639
  }) => {
2523
2640
  let nextPotentialPosition = {
2524
- x: position.x + pageWidth,
2641
+ x: position.x - pageWidth,
2525
2642
  y: position.y
2526
2643
  };
2527
2644
  if (spineItem.isUsingVerticalWriting()) {
2528
2645
  nextPotentialPosition = {
2529
2646
  x: position.x,
2530
- y: position.y - pageHeight
2647
+ y: position.y + pageHeight
2531
2648
  };
2532
2649
  }
2533
2650
  const navigationPosition = spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(
@@ -2536,7 +2653,7 @@ const getSpineItemPositionForRightPage = ({
2536
2653
  );
2537
2654
  return navigationPosition;
2538
2655
  };
2539
- const getNavigationForRightSinglePage = ({
2656
+ const getNavigationForLeftSinglePage = ({
2540
2657
  position,
2541
2658
  navigationResolver,
2542
2659
  computedPageTurnDirection,
@@ -2554,7 +2671,7 @@ const getNavigationForRightSinglePage = ({
2554
2671
  position,
2555
2672
  spineItem
2556
2673
  );
2557
- const spineItemNavigationForRightPage = getSpineItemPositionForRightPage({
2674
+ const spineItemNavigation = getSpineItemPositionForLeftPage({
2558
2675
  position: spineItemPosition,
2559
2676
  spineItem,
2560
2677
  pageHeight: context.getPageSize().height,
@@ -2562,21 +2679,21 @@ const getNavigationForRightSinglePage = ({
2562
2679
  spineItemLocator: spineLocator.spineItemLocator
2563
2680
  });
2564
2681
  const isNewNavigationInCurrentItem = navigationResolver.arePositionsDifferent(
2565
- spineItemNavigationForRightPage,
2682
+ spineItemNavigation,
2566
2683
  spineItemPosition
2567
2684
  );
2568
2685
  if (!isNewNavigationInCurrentItem) {
2569
2686
  return navigationResolver.getAdjustedPositionWithSafeEdge(
2570
- pageTurnDirection === `horizontal` ? { x: position.x + context.getPageSize().width, y: 0 } : { y: position.y + context.getPageSize().height, x: 0 }
2687
+ pageTurnDirection === `horizontal` ? { x: position.x - context.getPageSize().width, y: 0 } : { y: position.y - context.getPageSize().height, x: 0 }
2571
2688
  );
2572
2689
  }
2573
2690
  const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition({
2574
- spineItemPosition: spineItemNavigationForRightPage,
2691
+ spineItemPosition: spineItemNavigation,
2575
2692
  spineItem
2576
2693
  });
2577
2694
  return readingOrderPosition;
2578
2695
  };
2579
- const getNavigationForRightOrBottomPage = ({
2696
+ const getNavigationForLeftOrTopPage = ({
2580
2697
  position,
2581
2698
  spineItem,
2582
2699
  context,
@@ -2585,7 +2702,7 @@ const getNavigationForRightOrBottomPage = ({
2585
2702
  spineLocator,
2586
2703
  computedPageTurnDirection
2587
2704
  }) => {
2588
- const navigation = getNavigationForRightSinglePage({
2705
+ const navigation = getNavigationForLeftSinglePage({
2589
2706
  position,
2590
2707
  context,
2591
2708
  navigationResolver,
@@ -2600,12 +2717,9 @@ const getNavigationForRightOrBottomPage = ({
2600
2717
  if ((spineItem == null ? void 0 : spineItem.isUsingVerticalWriting()) && position.x !== navigation.x) {
2601
2718
  return navigationResolver.getAdjustedPositionForSpread(
2602
2719
  navigationResolver.getAdjustedPositionWithSafeEdge(
2603
- context.isRTL() ? {
2720
+ context.isRTL() ? { ...navigation, x: navigation.x + context.getPageSize().width } : {
2604
2721
  ...navigation,
2605
2722
  x: navigation.x - context.getPageSize().width
2606
- } : {
2607
- ...navigation,
2608
- x: navigation.x + context.getPageSize().width
2609
2723
  }
2610
2724
  )
2611
2725
  );
@@ -2613,7 +2727,7 @@ const getNavigationForRightOrBottomPage = ({
2613
2727
  if (computedPageTurnDirection === `vertical` && position.y !== navigation.y) {
2614
2728
  return navigationResolver.getAdjustedPositionForSpread(navigation);
2615
2729
  }
2616
- const doubleNavigation = getNavigationForRightSinglePage({
2730
+ const doubleNavigation = getNavigationForLeftSinglePage({
2617
2731
  position: navigation,
2618
2732
  context,
2619
2733
  navigationResolver,
@@ -2625,7 +2739,7 @@ const getNavigationForRightOrBottomPage = ({
2625
2739
  }
2626
2740
  return navigationResolver.getAdjustedPositionForSpread(navigation);
2627
2741
  };
2628
- const getSpineItemPositionForLeftPage = ({
2742
+ const getSpineItemPositionForRightPage = ({
2629
2743
  position,
2630
2744
  spineItem,
2631
2745
  pageHeight,
@@ -2633,13 +2747,13 @@ const getSpineItemPositionForLeftPage = ({
2633
2747
  spineItemLocator
2634
2748
  }) => {
2635
2749
  let nextPotentialPosition = {
2636
- x: position.x - pageWidth,
2750
+ x: position.x + pageWidth,
2637
2751
  y: position.y
2638
2752
  };
2639
2753
  if (spineItem.isUsingVerticalWriting()) {
2640
2754
  nextPotentialPosition = {
2641
2755
  x: position.x,
2642
- y: position.y + pageHeight
2756
+ y: position.y - pageHeight
2643
2757
  };
2644
2758
  }
2645
2759
  const navigationPosition = spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(
@@ -2648,7 +2762,7 @@ const getSpineItemPositionForLeftPage = ({
2648
2762
  );
2649
2763
  return navigationPosition;
2650
2764
  };
2651
- const getNavigationForLeftSinglePage = ({
2765
+ const getNavigationForRightSinglePage = ({
2652
2766
  position,
2653
2767
  navigationResolver,
2654
2768
  computedPageTurnDirection,
@@ -2666,7 +2780,7 @@ const getNavigationForLeftSinglePage = ({
2666
2780
  position,
2667
2781
  spineItem
2668
2782
  );
2669
- const spineItemNavigation = getSpineItemPositionForLeftPage({
2783
+ const spineItemNavigationForRightPage = getSpineItemPositionForRightPage({
2670
2784
  position: spineItemPosition,
2671
2785
  spineItem,
2672
2786
  pageHeight: context.getPageSize().height,
@@ -2674,21 +2788,21 @@ const getNavigationForLeftSinglePage = ({
2674
2788
  spineItemLocator: spineLocator.spineItemLocator
2675
2789
  });
2676
2790
  const isNewNavigationInCurrentItem = navigationResolver.arePositionsDifferent(
2677
- spineItemNavigation,
2791
+ spineItemNavigationForRightPage,
2678
2792
  spineItemPosition
2679
2793
  );
2680
2794
  if (!isNewNavigationInCurrentItem) {
2681
2795
  return navigationResolver.getAdjustedPositionWithSafeEdge(
2682
- pageTurnDirection === `horizontal` ? { x: position.x - context.getPageSize().width, y: 0 } : { y: position.y - context.getPageSize().height, x: 0 }
2796
+ pageTurnDirection === `horizontal` ? { x: position.x + context.getPageSize().width, y: 0 } : { y: position.y + context.getPageSize().height, x: 0 }
2683
2797
  );
2684
2798
  }
2685
2799
  const readingOrderPosition = spineLocator.getSpinePositionFromSpineItemPosition({
2686
- spineItemPosition: spineItemNavigation,
2800
+ spineItemPosition: spineItemNavigationForRightPage,
2687
2801
  spineItem
2688
2802
  });
2689
2803
  return readingOrderPosition;
2690
2804
  };
2691
- const getNavigationForLeftOrTopPage = ({
2805
+ const getNavigationForRightOrBottomPage = ({
2692
2806
  position,
2693
2807
  spineItem,
2694
2808
  context,
@@ -2697,7 +2811,7 @@ const getNavigationForLeftOrTopPage = ({
2697
2811
  spineLocator,
2698
2812
  computedPageTurnDirection
2699
2813
  }) => {
2700
- const navigation = getNavigationForLeftSinglePage({
2814
+ const navigation = getNavigationForRightSinglePage({
2701
2815
  position,
2702
2816
  context,
2703
2817
  navigationResolver,
@@ -2712,9 +2826,12 @@ const getNavigationForLeftOrTopPage = ({
2712
2826
  if ((spineItem == null ? void 0 : spineItem.isUsingVerticalWriting()) && position.x !== navigation.x) {
2713
2827
  return navigationResolver.getAdjustedPositionForSpread(
2714
2828
  navigationResolver.getAdjustedPositionWithSafeEdge(
2715
- context.isRTL() ? { ...navigation, x: navigation.x + context.getPageSize().width } : {
2829
+ context.isRTL() ? {
2716
2830
  ...navigation,
2717
2831
  x: navigation.x - context.getPageSize().width
2832
+ } : {
2833
+ ...navigation,
2834
+ x: navigation.x + context.getPageSize().width
2718
2835
  }
2719
2836
  )
2720
2837
  );
@@ -2722,7 +2839,7 @@ const getNavigationForLeftOrTopPage = ({
2722
2839
  if (computedPageTurnDirection === `vertical` && position.y !== navigation.y) {
2723
2840
  return navigationResolver.getAdjustedPositionForSpread(navigation);
2724
2841
  }
2725
- const doubleNavigation = getNavigationForLeftSinglePage({
2842
+ const doubleNavigation = getNavigationForRightSinglePage({
2726
2843
  position: navigation,
2727
2844
  context,
2728
2845
  navigationResolver,
@@ -2734,7 +2851,6 @@ const getNavigationForLeftOrTopPage = ({
2734
2851
  }
2735
2852
  return navigationResolver.getAdjustedPositionForSpread(navigation);
2736
2853
  };
2737
- const report$4 = Report.namespace(`navigation`);
2738
2854
  class ManualNavigator {
2739
2855
  constructor(reader) {
2740
2856
  this.reader = reader;
@@ -2827,7 +2943,8 @@ class ManualNavigator {
2827
2943
  }
2828
2944
  goToUrl(url) {
2829
2945
  this.reader.navigation.navigate({
2830
- url
2946
+ url,
2947
+ animation: false
2831
2948
  });
2832
2949
  }
2833
2950
  goToRightSpineItem() {
@@ -5144,20 +5261,6 @@ const resolveCfi = ({
5144
5261
  spineItem
5145
5262
  };
5146
5263
  };
5147
- const isUsingSpreadMode = ({
5148
- manifest,
5149
- visibleAreaRect,
5150
- forceSinglePageMode
5151
- }) => {
5152
- const { height, width } = visibleAreaRect;
5153
- const isLandscape = width > height;
5154
- if (forceSinglePageMode) return false;
5155
- if ((manifest == null ? void 0 : manifest.renditionFlow) === `scrolled-continuous`) return false;
5156
- if (!isLandscape && (manifest == null ? void 0 : manifest.renditionSpread) === `portrait`) {
5157
- return true;
5158
- }
5159
- return isLandscape && ((manifest == null ? void 0 : manifest.renditionSpread) === void 0 || (manifest == null ? void 0 : manifest.renditionSpread) === `auto` || (manifest == null ? void 0 : manifest.renditionSpread) === `landscape` || (manifest == null ? void 0 : manifest.renditionSpread) === `both`);
5160
- };
5161
5264
  const isFullyPrePaginated = (manifest) => (manifest == null ? void 0 : manifest.renditionLayout) === "pre-paginated" || (manifest == null ? void 0 : manifest.spineItems.every((item) => item.renditionLayout === "pre-paginated"));
5162
5265
  class BridgeEvent {
5163
5266
  constructor() {
@@ -5180,12 +5283,27 @@ class BridgeEvent {
5180
5283
  this.navigation$ = this.navigationSubject.asObservable();
5181
5284
  }
5182
5285
  }
5286
+ const isUsingSpreadMode = ({
5287
+ manifest,
5288
+ visibleAreaRect,
5289
+ forceSinglePageMode
5290
+ }) => {
5291
+ const { height, width } = visibleAreaRect;
5292
+ const isLandscape = width > height;
5293
+ if (forceSinglePageMode) return false;
5294
+ if ((manifest == null ? void 0 : manifest.renditionFlow) === `scrolled-continuous`) return false;
5295
+ if (!isLandscape && (manifest == null ? void 0 : manifest.renditionSpread) === `portrait`) {
5296
+ return true;
5297
+ }
5298
+ return isLandscape && ((manifest == null ? void 0 : manifest.renditionSpread) === void 0 || (manifest == null ? void 0 : manifest.renditionSpread) === `auto` || (manifest == null ? void 0 : manifest.renditionSpread) === `landscape` || (manifest == null ? void 0 : manifest.renditionSpread) === `both`);
5299
+ };
5183
5300
  class Context {
5184
5301
  constructor() {
5185
5302
  this._stateSubject = new BehaviorSubject({
5186
5303
  marginBottom: 0,
5187
5304
  marginTop: 0,
5188
5305
  calculatedInnerMargin: 0,
5306
+ assumedRenditionLayout: "reflowable",
5189
5307
  visibleAreaRect: {
5190
5308
  width: 0,
5191
5309
  height: 0,
@@ -5243,7 +5361,8 @@ class Context {
5243
5361
  height: newState.visibleAreaRect.height - marginTop - marginBottom
5244
5362
  },
5245
5363
  ...newState.manifest && {
5246
- isFullyPrePaginated: isFullyPrePaginated(manifest)
5364
+ isFullyPrePaginated: isFullyPrePaginated(manifest),
5365
+ assumedRenditionLayout: (manifest == null ? void 0 : manifest.renditionLayout) ?? "reflowable"
5247
5366
  },
5248
5367
  isUsingSpreadMode: isUsingSpreadMode({
5249
5368
  manifest,
@@ -6285,196 +6404,51 @@ class UserNavigator extends DestroyableClass {
6285
6404
  this.navigationSubject.next(to);
6286
6405
  }
6287
6406
  }
6288
- const isRootCfi = (cfi) => {
6289
- return cfi == null ? void 0 : cfi.startsWith(`epubcfi(/0`);
6290
- };
6291
- const restoreNavigationForControlledPageTurnMode = ({
6292
- spineLocator,
6293
- navigation,
6294
- navigationResolver,
6295
- spineItemsManager,
6296
- spineLayout
6297
- }) => {
6298
- var _a, _b;
6299
- const spineItem = spineItemsManager.get(navigation.spineItem);
6300
- if (!spineItem) {
6301
- return { x: 0, y: 0 };
6302
- }
6303
- const spineItemAbsolutePosition = spineLayout.getAbsolutePositionOf(spineItem);
6304
- const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6305
- navigation.position,
6306
- spineItem
6307
- );
6308
- const spineItemWidthDifference = spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0);
6309
- const spineItemHeighDifference = spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0);
6310
- const hasSpineItemGrewOrShrink = spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0;
6311
- if (navigation.url !== void 0) {
6312
- if (spineItemWidthDifference || spineItemHeighDifference) {
6313
- const urlResult = navigationResolver.getNavigationForUrl(navigation.url);
6314
- if (urlResult) {
6315
- return urlResult.position;
6316
- }
6317
- }
6318
- }
6319
- const cfi = navigation.cfi ?? navigation.paginationBeginCfi;
6320
- if (cfi !== void 0 && !isRootCfi(cfi)) {
6321
- if (spineItemWidthDifference || spineItemHeighDifference) {
6322
- const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi);
6323
- if (cfiResultPosition) {
6324
- return cfiResultPosition;
6325
- }
6326
- }
6327
- }
6328
- if (isPositionWithinSpineItem && hasSpineItemGrewOrShrink && navigation.directionFromLastNavigation === "backward") {
6329
- const positionInSpineItemWithDifference = {
6330
- x: (((_a = navigation.positionInSpineItem) == null ? void 0 : _a.x) ?? 0) + spineItemWidthDifference,
6331
- y: (((_b = navigation.positionInSpineItem) == null ? void 0 : _b.y) ?? 0) + spineItemHeighDifference
6332
- };
6333
- return navigationResolver.getNavigationFromSpineItemPosition({
6334
- spineItem,
6335
- spineItemPosition: positionInSpineItemWithDifference
6336
- });
6337
- }
6338
- if (navigation.positionInSpineItem && navigation.spineItemHeight && navigation.spineItemWidth) {
6339
- const pageIndex = spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({
6340
- itemWidth: navigation.spineItemWidth,
6341
- itemHeight: navigation.spineItemHeight,
6342
- isUsingVerticalWriting: !!navigation.spineItemIsUsingVerticalWriting,
6343
- position: navigation.positionInSpineItem
6344
- });
6345
- return navigationResolver.getNavigationForSpineItemPage({
6346
- pageIndex,
6347
- spineItemId: spineItem
6348
- });
6349
- }
6350
- if (isPositionWithinSpineItem) {
6351
- return navigationResolver.getNavigationForPosition(navigation.position);
6352
- }
6353
- return navigationResolver.getNavigationForSpineIndexOrId(spineItem);
6354
- };
6355
- const restoreNavigationForScrollingPageTurnMode = ({
6356
- navigation,
6357
- spineLocator,
6358
- spineItemsManager,
6359
- settings,
6360
- navigationResolver,
6361
- spineLayout
6362
- }) => {
6363
- const { spineItem } = navigation;
6364
- const foundSpineItem = spineItemsManager.get(spineItem);
6365
- if (!foundSpineItem) return { x: 0, y: 0 };
6366
- const { height, top } = spineLayout.getAbsolutePositionOf(foundSpineItem);
6367
- const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6368
- navigation.position,
6369
- foundSpineItem
6370
- );
6371
- const positionInSpineItem = navigation.positionInSpineItem ?? {
6372
- y: 0
6373
- };
6374
- if (settings.values.computedPageTurnDirection === "vertical") {
6375
- if (top === navigation.spineItemTop && height === navigation.spineItemHeight && isPositionWithinSpineItem) {
6376
- return navigation.position;
6377
- }
6378
- if (top === navigation.spineItemTop && height === navigation.spineItemHeight && !isPositionWithinSpineItem) {
6379
- return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6380
- }
6381
- if (top !== navigation.spineItemTop) {
6382
- const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6383
- navigation.positionInSpineItem ?? {
6384
- x: 0,
6385
- y: 0
6407
+ const withPaginationInfo = () => (stream) => {
6408
+ return stream.pipe(
6409
+ map(({ navigation, pagination, ...rest }) => {
6410
+ return {
6411
+ navigation: {
6412
+ ...navigation,
6413
+ paginationBeginCfi: pagination.beginCfi
6386
6414
  },
6387
- foundSpineItem
6388
- );
6389
- return spineLocator.getSpinePositionFromSpineItemPosition({
6390
- spineItemPosition: positionInSpineItem2,
6391
- spineItem: foundSpineItem
6392
- });
6393
- }
6394
- if (top === navigation.spineItemTop && height !== navigation.spineItemHeight) {
6395
- const positionYfromBottomPreviousNavigation = (navigation.spineItemHeight ?? positionInSpineItem.y) - positionInSpineItem.y;
6396
- const positionInspineItem = {
6397
- y: navigation.directionFromLastNavigation === "backward" ? height - positionYfromBottomPreviousNavigation : positionInSpineItem.y,
6398
- x: navigation.position.x
6415
+ ...rest
6399
6416
  };
6400
- if (isPositionWithinSpineItem) {
6401
- const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6402
- positionInspineItem,
6403
- foundSpineItem
6404
- );
6405
- return spineLocator.getSpinePositionFromSpineItemPosition({
6406
- spineItemPosition: positionInSpineItem2,
6407
- spineItem: foundSpineItem
6408
- });
6409
- }
6410
- if (!isPositionWithinSpineItem) {
6411
- const positionIsBeforeItem = navigation.position.y < top;
6412
- if (!positionIsBeforeItem) {
6413
- const positionInItem = {
6414
- y: height - positionYfromBottomPreviousNavigation,
6415
- x: navigation.position.x
6416
- };
6417
- return spineLocator.getSpinePositionFromSpineItemPosition({
6418
- spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6419
- positionInItem,
6420
- foundSpineItem
6421
- ),
6422
- spineItem: foundSpineItem
6423
- });
6424
- }
6425
- return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6426
- }
6427
- }
6428
- }
6429
- return navigation.position;
6430
- };
6431
- const restorePosition = ({
6432
- navigation,
6433
- spineItemsManager,
6434
- settings,
6435
- spineLocator,
6436
- navigationResolver,
6437
- spineLayout
6438
- }) => {
6439
- if (settings.values.computedPageTurnMode === "scrollable") {
6440
- return restoreNavigationForScrollingPageTurnMode({
6441
- navigation,
6442
- spineLocator,
6443
- navigationResolver,
6444
- settings,
6445
- spineItemsManager,
6446
- spineLayout
6447
- });
6448
- }
6449
- return restoreNavigationForControlledPageTurnMode({
6450
- navigation,
6451
- spineLocator,
6452
- navigationResolver,
6453
- spineItemsManager,
6454
- spineLayout
6455
- });
6417
+ })
6418
+ );
6456
6419
  };
6457
- const withRestoredPosition = ({
6458
- settings,
6459
- navigationResolver,
6460
- context,
6461
- spine
6462
- }) => (stream) => stream.pipe(
6463
- map((params) => ({
6464
- ...params,
6465
- navigation: {
6466
- ...params.navigation,
6467
- position: restorePosition({
6468
- spineLocator: spine.locator,
6469
- navigation: params.navigation,
6470
- navigationResolver,
6471
- settings,
6472
- spineItemsManager: spine.spineItemsManager,
6473
- spineItemLocator: spine.locator.spineItemLocator,
6474
- spineLayout: spine.spineLayout
6475
- })
6476
- }
6477
- }))
6420
+ const consolidateWithPagination = (context, navigation$, spine) => context.bridgeEvent.pagination$.pipe(
6421
+ withLatestFrom(navigation$),
6422
+ filter(
6423
+ ([pagination, navigation]) => pagination.navigationId === navigation.id
6424
+ ),
6425
+ /**
6426
+ * We only register the pagination cfi IF the spine item is ready.
6427
+ * Otherwise we might save something incomplete and thus restore
6428
+ * the user to an invalid location.
6429
+ */
6430
+ switchMap(([pagination, navigation]) => {
6431
+ const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6432
+ return ((spineItem == null ? void 0 : spineItem.isReady$.pipe(first$1())) ?? of(false)).pipe(
6433
+ filter((isReady) => isReady),
6434
+ map(() => ({
6435
+ pagination,
6436
+ navigation
6437
+ }))
6438
+ );
6439
+ }),
6440
+ withPaginationInfo(),
6441
+ distinctUntilChanged$1(
6442
+ (prev, curr) => prev.navigation.paginationBeginCfi === curr.navigation.paginationBeginCfi
6443
+ ),
6444
+ map(
6445
+ ({ navigation }) => ({
6446
+ ...navigation,
6447
+ meta: {
6448
+ triggeredBy: "pagination"
6449
+ }
6450
+ })
6451
+ )
6478
6452
  );
6479
6453
  const mapUserNavigationToInternal = (stream) => {
6480
6454
  return stream.pipe(
@@ -6495,6 +6469,27 @@ const mapUserNavigationToInternal = (stream) => {
6495
6469
  })
6496
6470
  );
6497
6471
  };
6472
+ const withCfiPosition = ({ navigationResolver }) => (stream) => {
6473
+ return stream.pipe(
6474
+ map((params) => {
6475
+ if (params.navigation.cfi) {
6476
+ const position = navigationResolver.getNavigationForCfi(
6477
+ params.navigation.cfi
6478
+ );
6479
+ if (position) {
6480
+ return {
6481
+ ...params,
6482
+ navigation: {
6483
+ ...params.navigation,
6484
+ position
6485
+ }
6486
+ };
6487
+ }
6488
+ }
6489
+ return params;
6490
+ })
6491
+ );
6492
+ };
6498
6493
  const getOrGuessDirection = ({
6499
6494
  navigation,
6500
6495
  previousNavigation,
@@ -6554,60 +6549,7 @@ const withDirection = ({
6554
6549
  })
6555
6550
  );
6556
6551
  };
6557
- const withSpineItemPosition = ({
6558
- settings,
6559
- spineItemsManager,
6560
- spineLocator,
6561
- navigationResolver
6562
- }) => (stream) => {
6563
- const getPosition = (navigation) => {
6564
- const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
6565
- const spineItem = spineItemsManager.get(navigation.spineItem);
6566
- if (!spineItem || !navigation.position) return void 0;
6567
- if (computedPageTurnMode === "controlled") {
6568
- const { endPageIndex, beginPageIndex } = spineLocator.getVisiblePagesFromViewportPosition({
6569
- position: navigation.position,
6570
- spineItem,
6571
- threshold: navigationSnapThreshold,
6572
- restrictToScreen: false
6573
- }) ?? {};
6574
- const farthestPageIndex = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6575
- const navigableSpinePositionForFarthestPageIndex = navigationResolver.getNavigationForSpineItemPage({
6576
- pageIndex: farthestPageIndex,
6577
- spineItemId: spineItem
6578
- });
6579
- const visiblePagesAtNavigablePosition = spineLocator.getVisiblePagesFromViewportPosition({
6580
- position: navigableSpinePositionForFarthestPageIndex,
6581
- spineItem,
6582
- threshold: 0,
6583
- restrictToScreen: true
6584
- });
6585
- const beginPageIndexForDirection = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.beginPageIndex : visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.endPageIndex) ?? 0;
6586
- const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
6587
- pageIndex: beginPageIndexForDirection,
6588
- isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
6589
- itemLayout: spineItem.getElementDimensions()
6590
- });
6591
- return positionInSpineItem;
6592
- }
6593
- return spineLocator.getSpineItemPositionFromSpinePosition(
6594
- navigation.position,
6595
- spineItem
6596
- );
6597
- };
6598
- return stream.pipe(
6599
- map(({ navigation, ...rest }) => {
6600
- return {
6601
- navigation: {
6602
- ...navigation,
6603
- positionInSpineItem: getPosition(navigation)
6604
- },
6605
- ...rest
6606
- };
6607
- })
6608
- );
6609
- };
6610
- const withFallbackPosition = ({
6552
+ const withFallbackPosition = ({
6611
6553
  spineItemsManager,
6612
6554
  navigationResolver
6613
6555
  }) => (stream) => {
@@ -6643,70 +6585,6 @@ const withFallbackPosition = ({
6643
6585
  })
6644
6586
  );
6645
6587
  };
6646
- const withSpineItemLayoutInfo = ({ spine }) => (stream) => {
6647
- return stream.pipe(
6648
- map(({ navigation, ...rest }) => {
6649
- const spineItemDimensions = spine.spineLayout.getAbsolutePositionOf(
6650
- navigation.spineItem
6651
- );
6652
- const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6653
- return {
6654
- navigation: {
6655
- ...navigation,
6656
- spineItemHeight: spineItemDimensions == null ? void 0 : spineItemDimensions.height,
6657
- spineItemWidth: spineItemDimensions == null ? void 0 : spineItemDimensions.width,
6658
- spineItemLeft: spineItemDimensions.left,
6659
- spineItemTop: spineItemDimensions.top,
6660
- spineItemIsUsingVerticalWriting: spineItem == null ? void 0 : spineItem.isUsingVerticalWriting()
6661
- },
6662
- ...rest
6663
- };
6664
- })
6665
- );
6666
- };
6667
- const withUrlInfo = ({ navigationResolver }) => (stream) => {
6668
- return stream.pipe(
6669
- map((params) => {
6670
- if (params.navigation.url) {
6671
- const result = navigationResolver.getNavigationForUrl(
6672
- params.navigation.url
6673
- );
6674
- if (result) {
6675
- return {
6676
- ...params,
6677
- navigation: {
6678
- ...params.navigation,
6679
- position: result.position,
6680
- spineItem: result.spineItemId
6681
- }
6682
- };
6683
- }
6684
- }
6685
- return params;
6686
- })
6687
- );
6688
- };
6689
- const withCfiPosition = ({ navigationResolver }) => (stream) => {
6690
- return stream.pipe(
6691
- map((params) => {
6692
- if (params.navigation.cfi) {
6693
- const position = navigationResolver.getNavigationForCfi(
6694
- params.navigation.cfi
6695
- );
6696
- if (position) {
6697
- return {
6698
- ...params,
6699
- navigation: {
6700
- ...params.navigation,
6701
- position
6702
- }
6703
- };
6704
- }
6705
- }
6706
- return params;
6707
- })
6708
- );
6709
- };
6710
6588
  const withSpineItem = ({
6711
6589
  settings,
6712
6590
  spineItemsManager,
@@ -6781,51 +6659,315 @@ const withSpineItem = ({
6781
6659
  })
6782
6660
  );
6783
6661
  };
6784
- const withPaginationInfo = () => (stream) => {
6662
+ const withSpineItemLayoutInfo = ({ spine }) => (stream) => {
6785
6663
  return stream.pipe(
6786
- map(({ navigation, pagination, ...rest }) => {
6664
+ switchMap(({ navigation, ...rest }) => {
6665
+ const spineItemDimensions = spine.spineLayout.getAbsolutePositionOf(
6666
+ navigation.spineItem
6667
+ );
6668
+ const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6669
+ return ((spineItem == null ? void 0 : spineItem.isReady$) ?? of(false)).pipe(
6670
+ first$1(),
6671
+ map(
6672
+ (isReady) => ({
6673
+ navigation: {
6674
+ ...navigation,
6675
+ spineItemHeight: spineItemDimensions == null ? void 0 : spineItemDimensions.height,
6676
+ spineItemWidth: spineItemDimensions == null ? void 0 : spineItemDimensions.width,
6677
+ spineItemLeft: spineItemDimensions.left,
6678
+ spineItemTop: spineItemDimensions.top,
6679
+ spineItemIsUsingVerticalWriting: spineItem == null ? void 0 : spineItem.isUsingVerticalWriting(),
6680
+ spineItemIsReady: isReady
6681
+ },
6682
+ ...rest
6683
+ })
6684
+ )
6685
+ );
6686
+ })
6687
+ );
6688
+ };
6689
+ const withSpineItemPosition = ({
6690
+ settings,
6691
+ spineItemsManager,
6692
+ spineLocator,
6693
+ navigationResolver
6694
+ }) => (stream) => {
6695
+ const getPosition = (navigation) => {
6696
+ const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
6697
+ const spineItem = spineItemsManager.get(navigation.spineItem);
6698
+ if (!spineItem || !navigation.position) return void 0;
6699
+ if (computedPageTurnMode === "controlled") {
6700
+ const { endPageIndex, beginPageIndex } = spineLocator.getVisiblePagesFromViewportPosition({
6701
+ position: navigation.position,
6702
+ spineItem,
6703
+ threshold: navigationSnapThreshold,
6704
+ restrictToScreen: false
6705
+ }) ?? {};
6706
+ const farthestPageIndex = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6707
+ const navigableSpinePositionForFarthestPageIndex = navigationResolver.getNavigationForSpineItemPage({
6708
+ pageIndex: farthestPageIndex,
6709
+ spineItemId: spineItem
6710
+ });
6711
+ const visiblePagesAtNavigablePosition = spineLocator.getVisiblePagesFromViewportPosition({
6712
+ position: navigableSpinePositionForFarthestPageIndex,
6713
+ spineItem,
6714
+ threshold: 0,
6715
+ restrictToScreen: true
6716
+ });
6717
+ const beginPageIndexForDirection = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.beginPageIndex : visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.endPageIndex) ?? 0;
6718
+ const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
6719
+ pageIndex: beginPageIndexForDirection,
6720
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
6721
+ itemLayout: spineItem.getElementDimensions()
6722
+ });
6723
+ return positionInSpineItem;
6724
+ }
6725
+ return spineLocator.getSpineItemPositionFromSpinePosition(
6726
+ navigation.position,
6727
+ spineItem
6728
+ );
6729
+ };
6730
+ return stream.pipe(
6731
+ map(({ navigation, ...rest }) => {
6787
6732
  return {
6788
6733
  navigation: {
6789
6734
  ...navigation,
6790
- paginationBeginCfi: pagination.beginCfi
6735
+ positionInSpineItem: getPosition(navigation)
6791
6736
  },
6792
6737
  ...rest
6793
6738
  };
6794
6739
  })
6795
6740
  );
6796
6741
  };
6797
- const consolidateWithPagination = (context, navigation$, spine) => context.bridgeEvent.pagination$.pipe(
6798
- withLatestFrom(navigation$),
6799
- filter(
6800
- ([pagination, navigation]) => pagination.navigationId === navigation.id
6801
- ),
6802
- /**
6803
- * We only register the pagination cfi IF the spine item is ready.
6804
- * Otherwise we might save something incomplete and thus restore
6805
- * the user to an invalid location.
6806
- */
6807
- switchMap(([pagination, navigation]) => {
6808
- const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6809
- return ((spineItem == null ? void 0 : spineItem.isReady$.pipe(first$1())) ?? of(false)).pipe(
6810
- filter((isReady) => isReady),
6811
- map(() => ({
6812
- pagination,
6813
- navigation
6814
- }))
6815
- );
6816
- }),
6817
- withPaginationInfo(),
6818
- distinctUntilChanged$1(
6819
- (prev, curr) => prev.navigation.paginationBeginCfi === curr.navigation.paginationBeginCfi
6820
- ),
6821
- map(
6822
- ({ navigation }) => ({
6823
- ...navigation,
6824
- meta: {
6825
- triggeredBy: "pagination"
6742
+ const withUrlInfo = ({ navigationResolver }) => (stream) => {
6743
+ return stream.pipe(
6744
+ map((params) => {
6745
+ if (params.navigation.url) {
6746
+ const result = navigationResolver.getNavigationForUrl(
6747
+ params.navigation.url
6748
+ );
6749
+ if (result) {
6750
+ return {
6751
+ ...params,
6752
+ navigation: {
6753
+ ...params.navigation,
6754
+ position: result.position,
6755
+ spineItem: result.spineItemId
6756
+ }
6757
+ };
6758
+ }
6826
6759
  }
6760
+ return params;
6827
6761
  })
6828
- )
6762
+ );
6763
+ };
6764
+ const isRootCfi = (cfi) => {
6765
+ return cfi == null ? void 0 : cfi.startsWith(`epubcfi(/0`);
6766
+ };
6767
+ const restoreNavigationForControlledPageTurnMode = ({
6768
+ spineLocator,
6769
+ navigation,
6770
+ navigationResolver,
6771
+ spineItemsManager,
6772
+ spineLayout
6773
+ }) => {
6774
+ const spineItem = spineItemsManager.get(navigation.spineItem);
6775
+ if (!spineItem) {
6776
+ return of({ x: 0, y: 0 });
6777
+ }
6778
+ return spineItem.isReady$.pipe(
6779
+ first$1(),
6780
+ map((isReady) => {
6781
+ var _a, _b;
6782
+ const spineItemAbsolutePosition = spineLayout.getAbsolutePositionOf(spineItem);
6783
+ const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6784
+ navigation.position,
6785
+ spineItem
6786
+ );
6787
+ const spineItemWidthDifference = spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0);
6788
+ const spineItemHeighDifference = spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0);
6789
+ const hasSpineItemGrewOrShrink = spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0;
6790
+ if (navigation.url !== void 0) {
6791
+ if (spineItemWidthDifference || spineItemHeighDifference || // when spine item is ready dimensions may have not changed but the position
6792
+ // of dom elements may have!
6793
+ isReady && !navigation.spineItemIsReady) {
6794
+ const urlResult = navigationResolver.getNavigationForUrl(
6795
+ navigation.url
6796
+ );
6797
+ if (urlResult) {
6798
+ return urlResult.position;
6799
+ }
6800
+ }
6801
+ }
6802
+ const cfi = navigation.cfi ?? navigation.paginationBeginCfi;
6803
+ if (cfi !== void 0 && !isRootCfi(cfi)) {
6804
+ if (spineItemWidthDifference || spineItemHeighDifference || // when spine item is ready dimensions may have not changed but the position
6805
+ // of dom elements may have!
6806
+ isReady && !navigation.spineItemIsReady) {
6807
+ const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi);
6808
+ if (cfiResultPosition) {
6809
+ return cfiResultPosition;
6810
+ }
6811
+ }
6812
+ }
6813
+ if (isPositionWithinSpineItem && hasSpineItemGrewOrShrink && navigation.directionFromLastNavigation === "backward") {
6814
+ const positionInSpineItemWithDifference = {
6815
+ x: (((_a = navigation.positionInSpineItem) == null ? void 0 : _a.x) ?? 0) + spineItemWidthDifference,
6816
+ y: (((_b = navigation.positionInSpineItem) == null ? void 0 : _b.y) ?? 0) + spineItemHeighDifference
6817
+ };
6818
+ return navigationResolver.getNavigationFromSpineItemPosition({
6819
+ spineItem,
6820
+ spineItemPosition: positionInSpineItemWithDifference
6821
+ });
6822
+ }
6823
+ if (navigation.positionInSpineItem && navigation.spineItemHeight && navigation.spineItemWidth) {
6824
+ const pageIndex = spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({
6825
+ itemWidth: navigation.spineItemWidth,
6826
+ itemHeight: navigation.spineItemHeight,
6827
+ isUsingVerticalWriting: !!navigation.spineItemIsUsingVerticalWriting,
6828
+ position: navigation.positionInSpineItem
6829
+ });
6830
+ return navigationResolver.getNavigationForSpineItemPage({
6831
+ pageIndex,
6832
+ spineItemId: spineItem
6833
+ });
6834
+ }
6835
+ if (isPositionWithinSpineItem) {
6836
+ return navigationResolver.getNavigationForPosition(navigation.position);
6837
+ }
6838
+ return navigationResolver.getNavigationForSpineIndexOrId(spineItem);
6839
+ })
6840
+ );
6841
+ };
6842
+ const restoreNavigationForScrollingPageTurnMode = ({
6843
+ navigation,
6844
+ spineLocator,
6845
+ spineItemsManager,
6846
+ settings,
6847
+ navigationResolver,
6848
+ spineLayout
6849
+ }) => {
6850
+ const { spineItem } = navigation;
6851
+ const foundSpineItem = spineItemsManager.get(spineItem);
6852
+ if (!foundSpineItem) return { x: 0, y: 0 };
6853
+ const { height, top } = spineLayout.getAbsolutePositionOf(foundSpineItem);
6854
+ const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6855
+ navigation.position,
6856
+ foundSpineItem
6857
+ );
6858
+ const positionInSpineItem = navigation.positionInSpineItem ?? {
6859
+ y: 0
6860
+ };
6861
+ if (settings.values.computedPageTurnDirection === "vertical") {
6862
+ if (top === navigation.spineItemTop && height === navigation.spineItemHeight && isPositionWithinSpineItem) {
6863
+ return navigation.position;
6864
+ }
6865
+ if (top === navigation.spineItemTop && height === navigation.spineItemHeight && !isPositionWithinSpineItem) {
6866
+ return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6867
+ }
6868
+ if (top !== navigation.spineItemTop) {
6869
+ const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6870
+ navigation.positionInSpineItem ?? {
6871
+ x: 0,
6872
+ y: 0
6873
+ },
6874
+ foundSpineItem
6875
+ );
6876
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6877
+ spineItemPosition: positionInSpineItem2,
6878
+ spineItem: foundSpineItem
6879
+ });
6880
+ }
6881
+ if (top === navigation.spineItemTop && height !== navigation.spineItemHeight) {
6882
+ const positionYfromBottomPreviousNavigation = (navigation.spineItemHeight ?? positionInSpineItem.y) - positionInSpineItem.y;
6883
+ const positionInspineItem = {
6884
+ y: navigation.directionFromLastNavigation === "backward" ? height - positionYfromBottomPreviousNavigation : positionInSpineItem.y,
6885
+ x: navigation.position.x
6886
+ };
6887
+ if (isPositionWithinSpineItem) {
6888
+ const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6889
+ positionInspineItem,
6890
+ foundSpineItem
6891
+ );
6892
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6893
+ spineItemPosition: positionInSpineItem2,
6894
+ spineItem: foundSpineItem
6895
+ });
6896
+ }
6897
+ if (!isPositionWithinSpineItem) {
6898
+ const positionIsBeforeItem = navigation.position.y < top;
6899
+ if (!positionIsBeforeItem) {
6900
+ const positionInItem = {
6901
+ y: height - positionYfromBottomPreviousNavigation,
6902
+ x: navigation.position.x
6903
+ };
6904
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6905
+ spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6906
+ positionInItem,
6907
+ foundSpineItem
6908
+ ),
6909
+ spineItem: foundSpineItem
6910
+ });
6911
+ }
6912
+ return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6913
+ }
6914
+ }
6915
+ }
6916
+ return navigation.position;
6917
+ };
6918
+ const restorePosition = ({
6919
+ navigation,
6920
+ spineItemsManager,
6921
+ settings,
6922
+ spineLocator,
6923
+ navigationResolver,
6924
+ spineLayout
6925
+ }) => {
6926
+ if (settings.values.computedPageTurnMode === "scrollable") {
6927
+ return of(
6928
+ restoreNavigationForScrollingPageTurnMode({
6929
+ navigation,
6930
+ spineLocator,
6931
+ navigationResolver,
6932
+ settings,
6933
+ spineItemsManager,
6934
+ spineLayout
6935
+ })
6936
+ );
6937
+ }
6938
+ return restoreNavigationForControlledPageTurnMode({
6939
+ navigation,
6940
+ spineLocator,
6941
+ navigationResolver,
6942
+ spineItemsManager,
6943
+ spineLayout
6944
+ });
6945
+ };
6946
+ const withRestoredPosition = ({
6947
+ settings,
6948
+ navigationResolver,
6949
+ context,
6950
+ spine
6951
+ }) => (stream) => stream.pipe(
6952
+ switchMap((params) => {
6953
+ return restorePosition({
6954
+ spineLocator: spine.locator,
6955
+ navigation: params.navigation,
6956
+ navigationResolver,
6957
+ settings,
6958
+ spineItemsManager: spine.spineItemsManager,
6959
+ spineItemLocator: spine.locator.spineItemLocator,
6960
+ spineLayout: spine.spineLayout
6961
+ }).pipe(
6962
+ map((restoredPosition) => ({
6963
+ ...params,
6964
+ navigation: {
6965
+ ...params.navigation,
6966
+ position: restoredPosition
6967
+ }
6968
+ }))
6969
+ );
6970
+ })
6829
6971
  );
6830
6972
  const NAMESPACE$2 = `navigation/InternalNavigator`;
6831
6973
  const report$1 = Report.namespace(NAMESPACE$2);
@@ -6846,6 +6988,7 @@ class InternalNavigator extends DestroyableClass {
6846
6988
  meta: {
6847
6989
  triggeredBy: "user"
6848
6990
  },
6991
+ spineItemIsReady: false,
6849
6992
  type: "api",
6850
6993
  id: Symbol()
6851
6994
  });
@@ -6861,10 +7004,6 @@ class InternalNavigator extends DestroyableClass {
6861
7004
  shareReplay$1(1)
6862
7005
  );
6863
7006
  this.locker = new Locker();
6864
- const layoutHasChanged$ = merge(
6865
- viewportController.layout$,
6866
- spine.spineLayout.layout$.pipe(filter(({ hasChanged }) => hasChanged))
6867
- );
6868
7007
  const navigationFromUser$ = userNavigation$.pipe(
6869
7008
  withLatestFrom(this.navigationSubject),
6870
7009
  mapUserNavigationToInternal,
@@ -6946,7 +7085,10 @@ class InternalNavigator extends DestroyableClass {
6946
7085
  }),
6947
7086
  share()
6948
7087
  );
6949
- const navigationUpateFromLayout$ = layoutHasChanged$.pipe(
7088
+ const navigationUpateFromLayout$ = merge(
7089
+ viewportController.layout$,
7090
+ spine.spineLayout.layout$
7091
+ ).pipe(
6950
7092
  switchMap(() => {
6951
7093
  return of(null).pipe(
6952
7094
  switchMap(