@prose-reader/core 1.120.0 → 1.121.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.
@@ -518,14 +518,19 @@
518
518
  }
519
519
  });
520
520
  });
521
- reader.hookManager.register(`item.onAfterLayout`, ({ item }) => {
522
- const spineItem = reader.spineItemsManager.get(item.id);
523
- if (spineItem == null ? void 0 : spineItem.isReady) {
524
- spineItem == null ? void 0 : spineItem.renderer.layers.forEach(({ element }) => {
521
+ const revealItemOnReady$ = reader.spineItemsObserver.itemIsReady$.pipe(
522
+ operators.filter(({ isReady }) => isReady),
523
+ /**
524
+ * Make sure that even if the document was loaded instantly, the layout is applied first
525
+ * and therefore the transition played. eg: pdf are loaded before attached to the dom.
526
+ */
527
+ operators.delay(1, rxjs.animationFrameScheduler),
528
+ operators.tap(({ item }) => {
529
+ item.renderer.layers.forEach(({ element }) => {
525
530
  element.style.opacity = `1`;
526
531
  });
527
- }
528
- });
532
+ })
533
+ );
529
534
  const observeContainerResize = (container) => new rxjs.Observable((observer) => {
530
535
  const resizeObserver = new ResizeObserver(() => {
531
536
  observer.next();
@@ -546,7 +551,6 @@
546
551
  })
547
552
  );
548
553
  const movingSafePan$ = createMovingSafePan$(reader);
549
- movingSafePan$.subscribe();
550
554
  settingsManager.values$.pipe(
551
555
  mapKeysTo([`pageHorizontalMargin`, `pageVerticalMargin`]),
552
556
  operators.distinctUntilChanged(shared.isShallowEqual),
@@ -556,7 +560,7 @@
556
560
  }),
557
561
  operators.takeUntil(reader.$.destroy$)
558
562
  ).subscribe();
559
- rxjs.merge(layoutOnContainerResize$).pipe(operators.takeUntil(reader.$.destroy$)).subscribe();
563
+ rxjs.merge(revealItemOnReady$, movingSafePan$, layoutOnContainerResize$).pipe(operators.takeUntil(reader.$.destroy$)).subscribe();
560
564
  return {
561
565
  ...reader,
562
566
  destroy: () => {
@@ -3126,7 +3130,7 @@
3126
3130
  let i, child;
3127
3131
  for (i = 0; i < children.length; i++) {
3128
3132
  child = children[i];
3129
- switch (child.nodeType) {
3133
+ switch (child == null ? void 0 : child.nodeType) {
3130
3134
  case ELEMENT_NODE:
3131
3135
  if (cfiCount % 2 === 0) {
3132
3136
  cfiCount += 2;
@@ -3162,12 +3166,11 @@
3162
3166
  cfiCount += 1;
3163
3167
  }
3164
3168
  if (cfiCount === index) {
3165
- const trueLength = this.trueLength(dom, child.textContent);
3166
- if (offset >= trueLength) {
3167
- offset -= trueLength;
3168
- } else {
3169
+ const trueLength = this.trueLength(dom, child.textContent || "");
3170
+ if (offset <= trueLength) {
3169
3171
  return { node: child, offset };
3170
3172
  }
3173
+ offset -= trueLength;
3171
3174
  }
3172
3175
  lastChild = child;
3173
3176
  break;
@@ -3175,6 +3178,10 @@
3175
3178
  continue;
3176
3179
  }
3177
3180
  }
3181
+ if (lastChild && (lastChild.nodeType === TEXT_NODE || lastChild.nodeType === CDATA_SECTION_NODE)) {
3182
+ const trueLength = this.trueLength(dom, lastChild.textContent || "");
3183
+ return { node: lastChild, offset: Math.min(offset, trueLength) };
3184
+ }
3178
3185
  if (index > cfiCount) {
3179
3186
  const o = { relativeToNode: `after`, offset: 0 };
3180
3187
  if (!lastChild) {
@@ -5958,83 +5965,6 @@
5958
5965
  this.layoutSubject.complete();
5959
5966
  }
5960
5967
  }
5961
- const createFingerTracker = () => {
5962
- const fingerPositionInIframe = { x: void 0, y: void 0 };
5963
- const subject = new rxjs.Subject();
5964
- let isMouseDown = false;
5965
- const track = (frame) => {
5966
- var _a, _b, _c;
5967
- fingerPositionInIframe.x = void 0;
5968
- fingerPositionInIframe.y = void 0;
5969
- (_a = frame.contentDocument) == null ? void 0 : _a.addEventListener(`mousedown`, (e) => {
5970
- isMouseDown = true;
5971
- fingerPositionInIframe.x = e.x;
5972
- fingerPositionInIframe.y = e.y;
5973
- subject.next({ event: `fingermove`, data: { x: e.x, y: e.y } });
5974
- });
5975
- (_b = frame.contentDocument) == null ? void 0 : _b.addEventListener(`mouseup`, () => {
5976
- isMouseDown = false;
5977
- fingerPositionInIframe.x = void 0;
5978
- fingerPositionInIframe.y = void 0;
5979
- subject.next({ event: `fingerout`, data: void 0 });
5980
- });
5981
- (_c = frame.contentDocument) == null ? void 0 : _c.addEventListener(`mousemove`, (e) => {
5982
- if (isMouseDown) {
5983
- subject.next({ event: `fingermove`, data: { x: e.x, y: e.y } });
5984
- }
5985
- });
5986
- };
5987
- return {
5988
- track,
5989
- getFingerPositionInIframe() {
5990
- return fingerPositionInIframe.x === void 0 || fingerPositionInIframe.y === void 0 ? void 0 : fingerPositionInIframe;
5991
- },
5992
- destroy: () => {
5993
- },
5994
- $: subject.asObservable()
5995
- };
5996
- };
5997
- const createSelectionTracker = () => {
5998
- let isSelecting = false;
5999
- let frame;
6000
- const subject = new rxjs.Subject();
6001
- const mouseUpEvents = [`mouseup`, `pointerup`];
6002
- const track = (frameToTrack) => {
6003
- var _a, _b;
6004
- frame = frameToTrack;
6005
- mouseUpEvents.forEach((eventName) => {
6006
- var _a2;
6007
- (_a2 = frameToTrack.contentWindow) == null ? void 0 : _a2.addEventListener(eventName, () => {
6008
- isSelecting = false;
6009
- });
6010
- });
6011
- (_a = frameToTrack.contentDocument) == null ? void 0 : _a.addEventListener(`selectionchange`, () => {
6012
- var _a2;
6013
- subject.next({
6014
- event: `selectionchange`,
6015
- data: ((_a2 = frame == null ? void 0 : frame.contentWindow) == null ? void 0 : _a2.getSelection()) || null
6016
- });
6017
- });
6018
- (_b = frameToTrack.contentWindow) == null ? void 0 : _b.addEventListener(`selectstart`, () => {
6019
- isSelecting = true;
6020
- });
6021
- };
6022
- const destroy = () => {
6023
- };
6024
- return {
6025
- track,
6026
- destroy,
6027
- isSelecting: () => isSelecting,
6028
- getSelection: () => {
6029
- var _a;
6030
- const selection = (_a = frame == null ? void 0 : frame.contentWindow) == null ? void 0 : _a.getSelection();
6031
- if (!(selection == null ? void 0 : selection.anchorNode) || selection.type === `None` || selection.type === `Caret`)
6032
- return void 0;
6033
- return selection;
6034
- },
6035
- $: subject.asObservable()
6036
- };
6037
- };
6038
5968
  class DocumentRenderer {
6039
5969
  constructor(context, settings, hookManager, item, containerElement, resourcesHandler) {
6040
5970
  this.context = context;
@@ -6065,9 +5995,6 @@
6065
5995
  this.destroy$ = this.triggerSubject.pipe(
6066
5996
  rxjs.filter((trigger) => trigger === `destroy`)
6067
5997
  );
6068
- this.stateSubject.subscribe((state) => {
6069
- console.log(`FOOO`, item.id, `state`, state);
6070
- });
6071
5998
  this.load$.pipe(
6072
5999
  rxjs.switchMap(() => {
6073
6000
  this.stateSubject.next(`loading`);
@@ -6266,8 +6193,6 @@
6266
6193
  this.destroy = () => {
6267
6194
  this.destroySubject$.next();
6268
6195
  this.containerElement.remove();
6269
- this.fingerTracker.destroy();
6270
- this.selectionTracker.destroy();
6271
6196
  this.destroySubject$.complete();
6272
6197
  this.renderer.destroy();
6273
6198
  };
@@ -6281,8 +6206,6 @@
6281
6206
  item,
6282
6207
  hookManager
6283
6208
  );
6284
- this.fingerTracker = createFingerTracker();
6285
- this.selectionTracker = createSelectionTracker();
6286
6209
  parentElement.appendChild(this.containerElement);
6287
6210
  const RendererClass = ((_b = (_a = this.settings.values).getRenderer) == null ? void 0 : _b.call(_a, item)) ?? DefaultRenderer;
6288
6211
  this.resourcesHandler = new ResourceHandler(item, this.settings);
@@ -6445,15 +6368,6 @@
6445
6368
  layout() {
6446
6369
  this.spineLayout.layout();
6447
6370
  }
6448
- isSelecting() {
6449
- return this.spineItemsManager.items.some(
6450
- (item) => item.selectionTracker.isSelecting()
6451
- );
6452
- }
6453
- getSelection() {
6454
- var _a;
6455
- return (_a = this.spineItemsManager.items.find((item) => item.selectionTracker.getSelection())) == null ? void 0 : _a.selectionTracker.getSelection();
6456
- }
6457
6371
  destroy() {
6458
6372
  super.destroy();
6459
6373
  this.spineItemsLoader.destroy();
@@ -7424,8 +7338,6 @@
7424
7338
  (_a3 = frame.contentDocument) == null ? void 0 : _a3.removeEventListener(event, listener);
7425
7339
  };
7426
7340
  });
7427
- item.selectionTracker.track(frame);
7428
- item.fingerTracker.track(frame);
7429
7341
  destroy(() => {
7430
7342
  unregister.forEach((cb) => cb());
7431
7343
  });
@@ -8199,28 +8111,158 @@
8199
8111
  });
8200
8112
  return reader;
8201
8113
  };
8114
+ const generateCfis = ({
8115
+ itemId,
8116
+ selection
8117
+ }) => {
8118
+ const anchorCfi = selection.anchorNode ? CfiHandler.generate(
8119
+ selection.anchorNode,
8120
+ selection.anchorOffset,
8121
+ `|[prose~anchor~${encodeURIComponent(itemId)}]`
8122
+ ) : void 0;
8123
+ const focusCfi = selection.focusNode ? CfiHandler.generate(
8124
+ selection.focusNode,
8125
+ selection.focusOffset,
8126
+ `|[prose~anchor~${encodeURIComponent(itemId)}]`
8127
+ ) : void 0;
8128
+ return {
8129
+ anchorCfi,
8130
+ focusCfi
8131
+ };
8132
+ };
8133
+ class SelectionTracker extends DestroyableClass {
8134
+ constructor(document2) {
8135
+ super();
8136
+ this.selectionChange$ = rxjs.fromEvent(document2, "selectionchange").pipe(
8137
+ rxjs.map(() => document2.getSelection())
8138
+ );
8139
+ this.selectionAfterPointerUp$ = rxjs.fromEvent(document2, "pointerup").pipe(
8140
+ /**
8141
+ * The selection is still valid during the event even if it will
8142
+ * be discarded. The timeout make sure to detect this edge case.
8143
+ */
8144
+ rxjs.delay(0),
8145
+ rxjs.map((event) => {
8146
+ const selection = document2.getSelection();
8147
+ return selection && !selection.isCollapsed ? [event, selection] : void 0;
8148
+ }),
8149
+ rxjs.filter(isDefined)
8150
+ );
8151
+ }
8152
+ }
8153
+ const selectionEnhancer = (next) => (options) => {
8154
+ const reader = next(options);
8155
+ const selectionSubject = new rxjs.BehaviorSubject(
8156
+ void 0
8157
+ );
8158
+ const selectionWithPointerUpSubject = new rxjs.Subject();
8159
+ reader.hookManager.register(
8160
+ `item.onDocumentLoad`,
8161
+ ({ itemId, layers, destroy$, destroy }) => {
8162
+ var _a, _b;
8163
+ const frame = (_a = layers[0]) == null ? void 0 : _a.element;
8164
+ if (frame instanceof HTMLIFrameElement) {
8165
+ const frameDoc = frame.contentDocument || ((_b = frame.contentWindow) == null ? void 0 : _b.document);
8166
+ if (frameDoc) {
8167
+ const selectionTracker = new SelectionTracker(frameDoc);
8168
+ rxjs.merge(
8169
+ selectionTracker.selectionChange$.pipe(
8170
+ rxjs.tap((selection) => {
8171
+ if (selection == null ? void 0 : selection.toString()) {
8172
+ selectionSubject.next({
8173
+ document: frameDoc,
8174
+ selection,
8175
+ itemId
8176
+ });
8177
+ } else {
8178
+ selectionSubject.next(void 0);
8179
+ }
8180
+ })
8181
+ ),
8182
+ selectionTracker.selectionAfterPointerUp$.pipe(
8183
+ rxjs.tap(([event, selection]) => {
8184
+ selectionWithPointerUpSubject.next([
8185
+ event,
8186
+ {
8187
+ document: frameDoc,
8188
+ selection,
8189
+ itemId
8190
+ }
8191
+ ]);
8192
+ })
8193
+ )
8194
+ ).pipe(rxjs.takeUntil(destroy$)).subscribe();
8195
+ destroy(() => {
8196
+ selectionTracker.destroy();
8197
+ });
8198
+ }
8199
+ }
8200
+ }
8201
+ );
8202
+ const selection$ = selectionSubject.pipe(
8203
+ rxjs.distinctUntilChanged(),
8204
+ rxjs.shareReplay(1),
8205
+ rxjs.takeUntil(reader.$.destroy$)
8206
+ );
8207
+ const selectionStart$ = selectionSubject.pipe(
8208
+ rxjs.map((selection) => !!selection),
8209
+ rxjs.distinctUntilChanged(),
8210
+ rxjs.filter((isSelecting) => isSelecting),
8211
+ rxjs.share()
8212
+ );
8213
+ const selectionEnd$ = selectionStart$.pipe(
8214
+ rxjs.switchMap(() => selection$),
8215
+ rxjs.distinctUntilChanged(),
8216
+ rxjs.filter((selection) => !selection),
8217
+ rxjs.share()
8218
+ );
8219
+ const selectionAfterPointerUp$ = selectionWithPointerUpSubject.asObservable();
8220
+ const lastSelectionOnPointerdown$ = reader.context.containerElement$.pipe(
8221
+ rxjs.switchMap((container) => rxjs.fromEvent(container, "pointerdown")),
8222
+ rxjs.withLatestFrom(selection$),
8223
+ rxjs.map(([, selection]) => selection),
8224
+ rxjs.startWith(void 0)
8225
+ );
8226
+ return {
8227
+ ...reader,
8228
+ selection: {
8229
+ selection$,
8230
+ selectionStart$,
8231
+ selectionEnd$,
8232
+ selectionAfterPointerUp$,
8233
+ lastSelectionOnPointerdown$,
8234
+ generateCfis
8235
+ },
8236
+ destroy: () => {
8237
+ selectionSubject.complete();
8238
+ reader.destroy();
8239
+ }
8240
+ };
8241
+ };
8202
8242
  const createReaderWithEnhancers = (
8203
8243
  //__
8204
- hotkeysEnhancer(
8205
- loadingEnhancer(
8206
- webkitEnhancer(
8207
- fontsEnhancer(
8208
- linksEnhancer(
8209
- accessibilityEnhancer(
8210
- resourcesEnhancer(
8211
- utilsEnhancer(
8212
- layoutEnhancer(
8213
- zoomEnhancer(
8214
- mediaEnhancer(
8215
- chromeEnhancer(
8216
- navigationEnhancer(
8217
- themeEnhancer(
8218
- paginationEnhancer(
8219
- progressionEnhancer(
8220
- eventsEnhancer(
8221
- htmlEnhancer(
8222
- // __
8223
- createReader
8244
+ selectionEnhancer(
8245
+ hotkeysEnhancer(
8246
+ loadingEnhancer(
8247
+ webkitEnhancer(
8248
+ fontsEnhancer(
8249
+ linksEnhancer(
8250
+ accessibilityEnhancer(
8251
+ resourcesEnhancer(
8252
+ utilsEnhancer(
8253
+ layoutEnhancer(
8254
+ zoomEnhancer(
8255
+ mediaEnhancer(
8256
+ chromeEnhancer(
8257
+ navigationEnhancer(
8258
+ themeEnhancer(
8259
+ paginationEnhancer(
8260
+ progressionEnhancer(
8261
+ eventsEnhancer(
8262
+ htmlEnhancer(
8263
+ // __
8264
+ createReader
8265
+ )
8224
8266
  )
8225
8267
  )
8226
8268
  )
@@ -8244,11 +8286,13 @@
8244
8286
  enumerable: true,
8245
8287
  get: () => shared.isShallowEqual
8246
8288
  });
8289
+ exports2.DestroyableClass = DestroyableClass;
8247
8290
  exports2.DocumentRenderer = DocumentRenderer;
8248
8291
  exports2.HookManager = HookManager;
8249
8292
  exports2.Report = Report;
8250
8293
  exports2.ResourceHandler = ResourceHandler;
8251
8294
  exports2.SettingsManager = SettingsManager;
8295
+ exports2.SpineItem = SpineItem;
8252
8296
  exports2.createReader = createReaderWithEnhancers;
8253
8297
  exports2.isHtmlElement = isHtmlElement;
8254
8298
  exports2.waitForSwitch = waitForSwitch;