@prose-reader/core 1.127.0 → 1.129.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/createReaderWithEnhancer.d.ts +2 -7
- package/dist/enhancers/html/renderer/HtmlRenderer.d.ts +4 -4
- package/dist/enhancers/media/ImageRenderer.d.ts +4 -4
- package/dist/enhancers/pagination/pagination.d.ts +1 -1
- package/dist/enhancers/progression.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +517 -412
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +515 -410
- package/dist/index.umd.cjs.map +1 -1
- package/dist/navigation/tests/SpineItemsManagerMock.d.ts +4 -1
- package/dist/reader.d.ts +1 -6
- package/dist/settings/types.d.ts +1 -1
- package/dist/spine/SpineLayout.d.ts +9 -7
- package/dist/spine/layout/layoutItem.d.ts +20 -0
- package/dist/spineItem/SpineItem.d.ts +14 -20
- package/dist/spineItem/renderer/DefaultRenderer.d.ts +8 -0
- package/dist/spineItem/{DocumentRenderer.d.ts → renderer/DocumentRenderer.d.ts} +17 -20
- package/dist/utils/rxjs.d.ts +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { takeUntil, Subject, combineLatest, map as map$1,
|
|
2
|
-
import { startWith, map, shareReplay, tap, pairwise, switchMap as switchMap$1, take, distinctUntilChanged, takeUntil as takeUntil$1, first, filter, delay, debounceTime, skip, withLatestFrom as withLatestFrom$1, share as share$1, mergeMap as mergeMap$1, catchError } from "rxjs/operators";
|
|
1
|
+
import { takeUntil, Subject, combineLatest, switchMap, fromEvent, take, map as map$1, from, of, merge, EMPTY, withLatestFrom, NEVER, Observable, scheduled, animationFrameScheduler, distinctUntilChanged as distinctUntilChanged$1, tap as tap$1, throttleTime, finalize, startWith as startWith$1, debounceTime as debounceTime$1, BehaviorSubject, combineLatestWith, shareReplay as shareReplay$1, ReplaySubject, filter as filter$1, share, mergeMap, delay as delay$1, identity, timer, skip as skip$1, exhaustMap, first as first$1, lastValueFrom, endWith, defer, reduce, concatMap, forkJoin, catchError as catchError$1 } from "rxjs";
|
|
2
|
+
import { startWith, map, shareReplay, tap, pairwise, switchMap as switchMap$1, take as take$1, distinctUntilChanged, takeUntil as takeUntil$1, first, filter, delay, debounceTime, skip, withLatestFrom as withLatestFrom$1, share as share$1, mergeMap as mergeMap$1, catchError } from "rxjs/operators";
|
|
3
3
|
import { shallowMergeIfDefined, isShallowEqual, detectMimeTypeFromName, parseContentType } from "@prose-reader/shared";
|
|
4
4
|
import { isShallowEqual as isShallowEqual2 } from "@prose-reader/shared";
|
|
5
5
|
const chromeEnhancer = (next) => (options) => {
|
|
@@ -112,6 +112,78 @@ let SettingsManager$2 = class SettingsManager extends SettingsManagerOverload {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
};
|
|
115
|
+
const getAttributeValueFromString = (string, key) => {
|
|
116
|
+
const regExp = new RegExp(key + `\\s*=\\s*([0-9.]+)`, `i`);
|
|
117
|
+
const match = string.match(regExp) || [];
|
|
118
|
+
const firstMatch = match[1] || `0`;
|
|
119
|
+
return match && parseFloat(firstMatch) || 0;
|
|
120
|
+
};
|
|
121
|
+
const injectCSS = (frameElement, id, style, prepend) => {
|
|
122
|
+
if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
|
|
123
|
+
const userStyle = document.createElement(`style`);
|
|
124
|
+
userStyle.id = id;
|
|
125
|
+
userStyle.innerHTML = style;
|
|
126
|
+
if (prepend) {
|
|
127
|
+
frameElement.contentDocument.head.prepend(userStyle);
|
|
128
|
+
} else {
|
|
129
|
+
frameElement.contentDocument.head.appendChild(userStyle);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const removeCSS = (frameElement, id) => {
|
|
134
|
+
if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
|
|
135
|
+
const styleElement = frameElement.contentDocument.getElementById(id);
|
|
136
|
+
if (styleElement) {
|
|
137
|
+
styleElement.remove();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const upsertCSS = (frameElement, id, style, prepend) => {
|
|
142
|
+
if (!frameElement) return;
|
|
143
|
+
removeCSS(frameElement, id);
|
|
144
|
+
injectCSS(frameElement, id, style, prepend);
|
|
145
|
+
};
|
|
146
|
+
const getFrameViewportInfo = (frame) => {
|
|
147
|
+
if (frame && (frame == null ? void 0 : frame.contentDocument)) {
|
|
148
|
+
const doc = frame.contentDocument;
|
|
149
|
+
const viewportMetaElement = doc.querySelector(`meta[name='viewport']`);
|
|
150
|
+
if (viewportMetaElement) {
|
|
151
|
+
const viewportContent = viewportMetaElement.getAttribute(`content`);
|
|
152
|
+
if (viewportContent) {
|
|
153
|
+
const width = getAttributeValueFromString(viewportContent, `width`);
|
|
154
|
+
const height = getAttributeValueFromString(viewportContent, `height`);
|
|
155
|
+
if (width > 0 && height > 0) {
|
|
156
|
+
return {
|
|
157
|
+
hasViewport: true,
|
|
158
|
+
width,
|
|
159
|
+
height
|
|
160
|
+
};
|
|
161
|
+
} else {
|
|
162
|
+
return { hasViewport: true };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { hasViewport: false };
|
|
168
|
+
};
|
|
169
|
+
const waitForFrameLoad = (stream) => stream.pipe(
|
|
170
|
+
switchMap(
|
|
171
|
+
(frame) => fromEvent(frame, `load`).pipe(
|
|
172
|
+
take(1),
|
|
173
|
+
map$1(() => frame)
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
);
|
|
177
|
+
const waitForFrameReady = (stream) => stream.pipe(
|
|
178
|
+
switchMap(
|
|
179
|
+
(frame) => {
|
|
180
|
+
var _a;
|
|
181
|
+
return from(((_a = frame == null ? void 0 : frame.contentDocument) == null ? void 0 : _a.fonts.ready) || of(void 0)).pipe(
|
|
182
|
+
map$1(() => frame)
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
);
|
|
115
187
|
const fontsEnhancer = (next) => (options) => {
|
|
116
188
|
const { fontScale, lineHeight, fontWeight, fontJustification } = options;
|
|
117
189
|
const changes$ = new Subject();
|
|
@@ -144,9 +216,12 @@ const fontsEnhancer = (next) => (options) => {
|
|
|
144
216
|
`;
|
|
145
217
|
const applyChangeToSpineItems = (requireLayout) => {
|
|
146
218
|
reader.spineItemsManager.items.forEach((item) => {
|
|
147
|
-
var _a;
|
|
148
219
|
if (item.item.renditionLayout !== `pre-paginated`) {
|
|
149
|
-
|
|
220
|
+
item.renderer.layers.forEach((layer) => {
|
|
221
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
222
|
+
upsertCSS(layer.element, `prose-reader-fonts`, getStyle());
|
|
223
|
+
}
|
|
224
|
+
});
|
|
150
225
|
}
|
|
151
226
|
});
|
|
152
227
|
if (requireLayout) {
|
|
@@ -156,7 +231,11 @@ const fontsEnhancer = (next) => (options) => {
|
|
|
156
231
|
reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {
|
|
157
232
|
const item = reader.spineItemsManager.get(itemId);
|
|
158
233
|
if ((item == null ? void 0 : item.item.renditionLayout) !== `pre-paginated`) {
|
|
159
|
-
item == null ? void 0 : item.
|
|
234
|
+
item == null ? void 0 : item.renderer.layers.forEach((layer) => {
|
|
235
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
236
|
+
upsertCSS(layer.element, `prose-reader-fonts`, getStyle());
|
|
237
|
+
}
|
|
238
|
+
});
|
|
160
239
|
}
|
|
161
240
|
});
|
|
162
241
|
const shouldRequireLayout = (source) => source.pipe(
|
|
@@ -266,7 +345,7 @@ const createMovingSafePan$ = (reader) => {
|
|
|
266
345
|
);
|
|
267
346
|
const resetLockViewportFree$ = createResetLock$(
|
|
268
347
|
reader.viewportFree$
|
|
269
|
-
).pipe(take(1));
|
|
348
|
+
).pipe(take$1(1));
|
|
270
349
|
const pageTurnMode$ = reader.settings.values$.pipe(
|
|
271
350
|
map(() => reader.settings.values.computedPageTurnMode),
|
|
272
351
|
distinctUntilChanged()
|
|
@@ -314,78 +393,19 @@ const waitForSwitch = (waitForStream) => (stream) => stream.pipe(
|
|
|
314
393
|
)
|
|
315
394
|
)
|
|
316
395
|
);
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
userStyle.id = id;
|
|
327
|
-
userStyle.innerHTML = style;
|
|
328
|
-
if (prepend) {
|
|
329
|
-
frameElement.contentDocument.head.prepend(userStyle);
|
|
330
|
-
} else {
|
|
331
|
-
frameElement.contentDocument.head.appendChild(userStyle);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
const removeCSS = (frameElement, id) => {
|
|
336
|
-
if (frameElement && frameElement.contentDocument && frameElement.contentDocument.head) {
|
|
337
|
-
const styleElement = frameElement.contentDocument.getElementById(id);
|
|
338
|
-
if (styleElement) {
|
|
339
|
-
styleElement.remove();
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
const upsertCSS = (frameElement, id, style, prepend) => {
|
|
344
|
-
if (!frameElement) return;
|
|
345
|
-
removeCSS(frameElement, id);
|
|
346
|
-
injectCSS(frameElement, id, style, prepend);
|
|
347
|
-
};
|
|
348
|
-
const getFrameViewportInfo = (frame) => {
|
|
349
|
-
if (frame && (frame == null ? void 0 : frame.contentDocument)) {
|
|
350
|
-
const doc = frame.contentDocument;
|
|
351
|
-
const viewportMetaElement = doc.querySelector(`meta[name='viewport']`);
|
|
352
|
-
if (viewportMetaElement) {
|
|
353
|
-
const viewportContent = viewportMetaElement.getAttribute(`content`);
|
|
354
|
-
if (viewportContent) {
|
|
355
|
-
const width = getAttributeValueFromString(viewportContent, `width`);
|
|
356
|
-
const height = getAttributeValueFromString(viewportContent, `height`);
|
|
357
|
-
if (width > 0 && height > 0) {
|
|
358
|
-
return {
|
|
359
|
-
hasViewport: true,
|
|
360
|
-
width,
|
|
361
|
-
height
|
|
362
|
-
};
|
|
363
|
-
} else {
|
|
364
|
-
return { hasViewport: true };
|
|
365
|
-
}
|
|
366
|
-
}
|
|
396
|
+
const deferNextResult = (stream) => {
|
|
397
|
+
let value;
|
|
398
|
+
const sub = stream.subscribe((result) => {
|
|
399
|
+
value = { result };
|
|
400
|
+
});
|
|
401
|
+
return () => {
|
|
402
|
+
sub.unsubscribe();
|
|
403
|
+
if (value) {
|
|
404
|
+
return of(value.result);
|
|
367
405
|
}
|
|
368
|
-
|
|
369
|
-
|
|
406
|
+
return stream;
|
|
407
|
+
};
|
|
370
408
|
};
|
|
371
|
-
const waitForFrameLoad = (stream) => stream.pipe(
|
|
372
|
-
switchMap(
|
|
373
|
-
(frame) => fromEvent(frame, `load`).pipe(
|
|
374
|
-
take$1(1),
|
|
375
|
-
map$1(() => frame)
|
|
376
|
-
)
|
|
377
|
-
)
|
|
378
|
-
);
|
|
379
|
-
const waitForFrameReady = (stream) => stream.pipe(
|
|
380
|
-
switchMap(
|
|
381
|
-
(frame) => {
|
|
382
|
-
var _a;
|
|
383
|
-
return from(((_a = frame == null ? void 0 : frame.contentDocument) == null ? void 0 : _a.fonts.ready) || of(void 0)).pipe(
|
|
384
|
-
map$1(() => frame)
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
)
|
|
388
|
-
);
|
|
389
409
|
const fixReflowable = (reader) => {
|
|
390
410
|
reader.hookManager.register(
|
|
391
411
|
`item.onAfterLayout`,
|
|
@@ -479,28 +499,33 @@ const layoutEnhancer = (next) => (options) => {
|
|
|
479
499
|
columnWidth = columnHeight;
|
|
480
500
|
columnGap = pageVerticalMargin2 * 2;
|
|
481
501
|
}
|
|
482
|
-
spineItem == null ? void 0 : spineItem.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
502
|
+
spineItem == null ? void 0 : spineItem.renderer.layers.forEach((layer) => {
|
|
503
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
504
|
+
upsertCSS(
|
|
505
|
+
layer.element,
|
|
506
|
+
`prose-layout-enhancer-css`,
|
|
507
|
+
`
|
|
508
|
+
body {
|
|
509
|
+
width: ${width}px !important;
|
|
510
|
+
margin: ${pageVerticalMargin2}px ${pageHorizontalMargin2}px !important;
|
|
511
|
+
column-gap: ${columnGap}px !important;
|
|
512
|
+
column-width: ${columnWidth}px !important;
|
|
513
|
+
height: ${columnHeight}px !important;
|
|
514
|
+
}
|
|
515
|
+
img, video, audio, object, svg {
|
|
516
|
+
max-width: ${columnWidth}px !important;
|
|
517
|
+
max-height: ${columnHeight}px !important;
|
|
518
|
+
}
|
|
519
|
+
table {
|
|
520
|
+
max-width: ${columnWidth}px !important;
|
|
521
|
+
}
|
|
522
|
+
td {
|
|
523
|
+
max-width: ${columnWidth}px;
|
|
524
|
+
}
|
|
525
|
+
`
|
|
526
|
+
);
|
|
501
527
|
}
|
|
502
|
-
|
|
503
|
-
);
|
|
528
|
+
});
|
|
504
529
|
}
|
|
505
530
|
});
|
|
506
531
|
fixReflowable(reader);
|
|
@@ -1350,66 +1375,79 @@ const trackTotalPages = (reader) => {
|
|
|
1350
1375
|
);
|
|
1351
1376
|
return totalPages$;
|
|
1352
1377
|
};
|
|
1353
|
-
const mapPaginationInfoToExtendedInfo = (reader
|
|
1378
|
+
const mapPaginationInfoToExtendedInfo = (reader, paginationInfo, chaptersInfo) => {
|
|
1354
1379
|
const context = reader.context;
|
|
1355
1380
|
const beginItem = paginationInfo.beginSpineItemIndex !== void 0 ? reader.spineItemsManager.get(paginationInfo.beginSpineItemIndex) : void 0;
|
|
1356
1381
|
const endItem = paginationInfo.endSpineItemIndex !== void 0 ? reader.spineItemsManager.get(paginationInfo.endSpineItemIndex) : void 0;
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1382
|
+
const endItemProgression$ = endItem ? reader.progression.getPercentageEstimate(
|
|
1383
|
+
context,
|
|
1384
|
+
paginationInfo.endSpineItemIndex ?? 0,
|
|
1385
|
+
paginationInfo.endNumberOfPagesInSpineItem,
|
|
1386
|
+
paginationInfo.endPageIndexInSpineItem || 0,
|
|
1387
|
+
reader.navigation.getNavigation().position,
|
|
1388
|
+
endItem
|
|
1389
|
+
) : of(0);
|
|
1390
|
+
return endItemProgression$.pipe(
|
|
1391
|
+
map$1((percentageEstimateOfBook) => ({
|
|
1392
|
+
...paginationInfo,
|
|
1393
|
+
beginChapterInfo: beginItem ? chaptersInfo[beginItem.item.id] : void 0,
|
|
1394
|
+
// chapterIndex: number;
|
|
1395
|
+
// pages: number;
|
|
1396
|
+
// pageIndexInBook: number;
|
|
1397
|
+
// pageIndexInChapter: number;
|
|
1398
|
+
// pagesOfChapter: number;
|
|
1399
|
+
// pagePercentageInChapter: number;
|
|
1400
|
+
// offsetPercentageInChapter: number;
|
|
1401
|
+
// domIndex: number;
|
|
1402
|
+
// charOffset: number;
|
|
1403
|
+
// serializeString?: string;
|
|
1404
|
+
beginSpineItemReadingDirection: beginItem == null ? void 0 : beginItem.readingDirection,
|
|
1405
|
+
endChapterInfo: endItem ? chaptersInfo[endItem.item.id] : void 0,
|
|
1406
|
+
endSpineItemReadingDirection: endItem == null ? void 0 : endItem.readingDirection,
|
|
1407
|
+
// spineItemReadingDirection: focusedSpineItem?.getReadingDirection(),
|
|
1408
|
+
/**
|
|
1409
|
+
* This percentage is based of the weight (kb) of every items and the number of pages.
|
|
1410
|
+
* It is not accurate but gives a general good idea of the overall progress.
|
|
1411
|
+
* It is recommended to use this progress only for reflow books. For pre-paginated books
|
|
1412
|
+
* the number of pages and current index can be used instead since 1 page = 1 chapter.
|
|
1413
|
+
*/
|
|
1414
|
+
percentageEstimateOfBook,
|
|
1415
|
+
isUsingSpread: context.state.isUsingSpreadMode ?? false
|
|
1416
|
+
// hasNextChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),
|
|
1417
|
+
// hasPreviousChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),
|
|
1418
|
+
// numberOfSpineItems: context.manifest?.readingOrder.length,
|
|
1419
|
+
}))
|
|
1420
|
+
);
|
|
1393
1421
|
};
|
|
1394
1422
|
const trackPaginationInfo = (reader) => {
|
|
1395
1423
|
const chaptersInfo$ = trackChapterInfo(reader);
|
|
1396
1424
|
const totalPages$ = trackTotalPages(reader);
|
|
1397
1425
|
const currentValue = new BehaviorSubject({
|
|
1398
1426
|
...reader.pagination.getState(),
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1427
|
+
beginChapterInfo: void 0,
|
|
1428
|
+
beginCfi: void 0,
|
|
1429
|
+
beginPageIndexInSpineItem: void 0,
|
|
1430
|
+
isUsingSpread: false,
|
|
1403
1431
|
beginAbsolutePageIndex: 0,
|
|
1404
1432
|
endAbsolutePageIndex: 0,
|
|
1405
|
-
numberOfTotalPages: 0
|
|
1433
|
+
numberOfTotalPages: 0,
|
|
1434
|
+
beginSpineItemReadingDirection: void 0,
|
|
1435
|
+
beginSpineItemIndex: void 0,
|
|
1436
|
+
endCfi: void 0,
|
|
1437
|
+
endChapterInfo: void 0,
|
|
1438
|
+
endSpineItemReadingDirection: void 0,
|
|
1439
|
+
percentageEstimateOfBook: 0
|
|
1406
1440
|
});
|
|
1407
1441
|
const extandedBasePagination$ = reader.pagination.state$.pipe(
|
|
1408
1442
|
combineLatestWith(chaptersInfo$),
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1443
|
+
switchMap(
|
|
1444
|
+
([info, chaptersInfo]) => mapPaginationInfoToExtendedInfo(reader, info, chaptersInfo).pipe(
|
|
1445
|
+
map$1((extendedInfo) => ({
|
|
1446
|
+
...info,
|
|
1447
|
+
...extendedInfo
|
|
1448
|
+
}))
|
|
1449
|
+
)
|
|
1450
|
+
),
|
|
1413
1451
|
distinctUntilChanged$1(isShallowEqual)
|
|
1414
1452
|
);
|
|
1415
1453
|
const paginationInfo$ = combineLatest([
|
|
@@ -1508,15 +1546,22 @@ const themeEnhancer = (next) => (options) => {
|
|
|
1508
1546
|
};
|
|
1509
1547
|
const applyChangeToSpineItem = () => {
|
|
1510
1548
|
reader.spineItemsManager.items.forEach((item) => {
|
|
1511
|
-
|
|
1512
|
-
|
|
1549
|
+
item.renderer.layers.forEach((layer) => {
|
|
1550
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
1551
|
+
upsertCSS(layer.element, `prose-reader-theme`, getStyle());
|
|
1552
|
+
}
|
|
1553
|
+
});
|
|
1513
1554
|
applyChangeToSpineItemElement({ container: item.element });
|
|
1514
1555
|
});
|
|
1515
1556
|
};
|
|
1516
1557
|
reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {
|
|
1517
1558
|
const item = reader.spineItemsManager.get(itemId);
|
|
1518
1559
|
if ((item == null ? void 0 : item.item.renditionLayout) !== "pre-paginated") {
|
|
1519
|
-
item == null ? void 0 : item.
|
|
1560
|
+
item == null ? void 0 : item.renderer.layers.forEach((layer) => {
|
|
1561
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
1562
|
+
upsertCSS(layer.element, `prose-reader-theme`, getStyle());
|
|
1563
|
+
}
|
|
1564
|
+
});
|
|
1520
1565
|
}
|
|
1521
1566
|
});
|
|
1522
1567
|
reader.spineItemsManager.items$.pipe(
|
|
@@ -1923,7 +1968,8 @@ const isHtmlElement = (element) => {
|
|
|
1923
1968
|
function createRangeOrCaretFromPoint(doc, startX, startY) {
|
|
1924
1969
|
if (`caretPositionFromPoint` in doc) {
|
|
1925
1970
|
return doc.caretPositionFromPoint(startX, startY);
|
|
1926
|
-
} else if (
|
|
1971
|
+
} else if ("caretRangeFromPoint" in doc && // @ts-expect-error limited availability
|
|
1972
|
+
typeof doc.caretRangeFromPoint !== `undefined`) {
|
|
1927
1973
|
return doc.caretRangeFromPoint(startX, startY);
|
|
1928
1974
|
}
|
|
1929
1975
|
}
|
|
@@ -5070,7 +5116,7 @@ class PaginationController extends DestroyableClass {
|
|
|
5070
5116
|
threshold: 0.5
|
|
5071
5117
|
});
|
|
5072
5118
|
return this.context.bridgeEvent.navigationUnlocked$.pipe(
|
|
5073
|
-
take
|
|
5119
|
+
take(1),
|
|
5074
5120
|
withLatestFrom(this.context.bridgeEvent.navigation$),
|
|
5075
5121
|
tap$1(([, navigation]) => {
|
|
5076
5122
|
const { position } = navigation;
|
|
@@ -5169,14 +5215,35 @@ const generateCfiFromRange = ({
|
|
|
5169
5215
|
const endCFI = generateCfi(endNode, end, item);
|
|
5170
5216
|
return { start: startCFI, end: endCFI };
|
|
5171
5217
|
};
|
|
5172
|
-
|
|
5218
|
+
const defaultGetResource = (item) => new URL(item.href);
|
|
5219
|
+
class ResourceHandler {
|
|
5220
|
+
constructor(item, settings) {
|
|
5221
|
+
this.item = item;
|
|
5222
|
+
this.settings = settings;
|
|
5223
|
+
}
|
|
5224
|
+
async getResource() {
|
|
5225
|
+
var _a, _b;
|
|
5226
|
+
const resource = await lastValueFrom(
|
|
5227
|
+
((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
|
|
5228
|
+
);
|
|
5229
|
+
return resource ?? defaultGetResource(this.item);
|
|
5230
|
+
}
|
|
5231
|
+
async fetchResource() {
|
|
5232
|
+
const resource = await this.getResource();
|
|
5233
|
+
if (resource instanceof Response) return resource;
|
|
5234
|
+
if (resource instanceof URL) return fetch(resource);
|
|
5235
|
+
return resource;
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
class DocumentRenderer extends DestroyableClass {
|
|
5173
5239
|
constructor(params) {
|
|
5240
|
+
super();
|
|
5174
5241
|
this.triggerSubject = new Subject();
|
|
5175
5242
|
this.stateSubject = new BehaviorSubject(`idle`);
|
|
5176
5243
|
this.unload$ = this.triggerSubject.pipe(
|
|
5177
5244
|
withLatestFrom(this.stateSubject),
|
|
5178
5245
|
filter$1(
|
|
5179
|
-
([trigger, state]) => trigger === `unload` && state !== "idle" && state !== "unloading"
|
|
5246
|
+
([trigger, state]) => trigger.type === `unload` && state !== "idle" && state !== "unloading"
|
|
5180
5247
|
),
|
|
5181
5248
|
map$1(() => void 0),
|
|
5182
5249
|
share()
|
|
@@ -5184,21 +5251,26 @@ class DocumentRenderer {
|
|
|
5184
5251
|
this.load$ = this.triggerSubject.pipe(
|
|
5185
5252
|
withLatestFrom(this.stateSubject),
|
|
5186
5253
|
filter$1(
|
|
5187
|
-
([trigger, state]) => trigger === `load` && state !== "
|
|
5254
|
+
([trigger, state]) => trigger.type === `load` && state !== "loaded" && state !== "loading"
|
|
5188
5255
|
),
|
|
5189
5256
|
map$1(() => void 0),
|
|
5190
5257
|
share()
|
|
5191
5258
|
);
|
|
5192
5259
|
this.layers = [];
|
|
5193
|
-
this.destroy$ = this.triggerSubject.pipe(
|
|
5194
|
-
filter$1((trigger) => trigger === `destroy`)
|
|
5195
|
-
);
|
|
5196
5260
|
this.context = params.context;
|
|
5197
5261
|
this.settings = params.settings;
|
|
5198
5262
|
this.hookManager = params.hookManager;
|
|
5199
5263
|
this.item = params.item;
|
|
5200
5264
|
this.containerElement = params.containerElement;
|
|
5201
5265
|
this.resourcesHandler = params.resourcesHandler;
|
|
5266
|
+
const unloadTrigger$ = this.triggerSubject.pipe(
|
|
5267
|
+
withLatestFrom(this.stateSubject),
|
|
5268
|
+
filter$1(
|
|
5269
|
+
([trigger, state]) => trigger.type === `unload` && state !== "idle" && state !== "unloading"
|
|
5270
|
+
),
|
|
5271
|
+
map$1(() => void 0),
|
|
5272
|
+
share()
|
|
5273
|
+
);
|
|
5202
5274
|
this.load$.pipe(
|
|
5203
5275
|
switchMap(() => {
|
|
5204
5276
|
this.stateSubject.next(`loading`);
|
|
@@ -5232,13 +5304,12 @@ class DocumentRenderer {
|
|
|
5232
5304
|
}),
|
|
5233
5305
|
tap$1(() => {
|
|
5234
5306
|
this.stateSubject.next(`loaded`);
|
|
5235
|
-
this.stateSubject.next(`ready`);
|
|
5236
5307
|
}),
|
|
5237
|
-
takeUntil(merge(this.destroy$,
|
|
5308
|
+
takeUntil(merge(this.destroy$, unloadTrigger$))
|
|
5238
5309
|
);
|
|
5239
5310
|
})
|
|
5240
5311
|
).subscribe();
|
|
5241
|
-
|
|
5312
|
+
const unload$ = unloadTrigger$.pipe(
|
|
5242
5313
|
switchMap(() => {
|
|
5243
5314
|
this.stateSubject.next(`unloading`);
|
|
5244
5315
|
return this.context.bridgeEvent.viewportFree$.pipe(
|
|
@@ -5247,29 +5318,32 @@ class DocumentRenderer {
|
|
|
5247
5318
|
this.hookManager.destroy(`item.onDocumentLoad`, this.item.id);
|
|
5248
5319
|
}),
|
|
5249
5320
|
switchMap(() => {
|
|
5250
|
-
const
|
|
5251
|
-
return
|
|
5321
|
+
const onUnload$ = this.onUnload().pipe(endWith(null), first$1());
|
|
5322
|
+
return onUnload$;
|
|
5252
5323
|
}),
|
|
5253
5324
|
tap$1(() => {
|
|
5254
5325
|
this.stateSubject.next(`idle`);
|
|
5255
5326
|
}),
|
|
5256
|
-
takeUntil(
|
|
5327
|
+
takeUntil(this.load$)
|
|
5257
5328
|
);
|
|
5258
5329
|
})
|
|
5259
|
-
)
|
|
5330
|
+
);
|
|
5331
|
+
merge(unload$).pipe(takeUntil(this.destroy$)).subscribe();
|
|
5260
5332
|
}
|
|
5261
5333
|
get state$() {
|
|
5262
5334
|
return this.stateSubject;
|
|
5263
5335
|
}
|
|
5336
|
+
get isLoaded$() {
|
|
5337
|
+
return this.state$.pipe(map$1((state) => state === `loaded`));
|
|
5338
|
+
}
|
|
5264
5339
|
load() {
|
|
5265
|
-
this.triggerSubject.next(`load`);
|
|
5340
|
+
this.triggerSubject.next({ type: `load` });
|
|
5266
5341
|
}
|
|
5267
5342
|
unload() {
|
|
5268
|
-
this.triggerSubject.next(`unload`);
|
|
5343
|
+
this.triggerSubject.next({ type: `unload` });
|
|
5269
5344
|
}
|
|
5270
5345
|
destroy() {
|
|
5271
|
-
|
|
5272
|
-
this.triggerSubject.complete();
|
|
5346
|
+
super.destroy();
|
|
5273
5347
|
this.stateSubject.complete();
|
|
5274
5348
|
}
|
|
5275
5349
|
get writingMode() {
|
|
@@ -5289,39 +5363,21 @@ class DefaultRenderer extends DocumentRenderer {
|
|
|
5289
5363
|
onLoadDocument() {
|
|
5290
5364
|
return EMPTY;
|
|
5291
5365
|
}
|
|
5292
|
-
|
|
5293
|
-
return void 0;
|
|
5294
|
-
}
|
|
5295
|
-
}
|
|
5296
|
-
const defaultGetResource = (item) => new URL(item.href);
|
|
5297
|
-
class ResourceHandler {
|
|
5298
|
-
constructor(item, settings) {
|
|
5299
|
-
this.item = item;
|
|
5300
|
-
this.settings = settings;
|
|
5301
|
-
}
|
|
5302
|
-
async getResource() {
|
|
5303
|
-
var _a, _b;
|
|
5304
|
-
const resource = await lastValueFrom(
|
|
5305
|
-
((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
|
|
5306
|
-
);
|
|
5307
|
-
return resource ?? defaultGetResource(this.item);
|
|
5308
|
-
}
|
|
5309
|
-
async fetchResource() {
|
|
5310
|
-
const resource = await this.getResource();
|
|
5311
|
-
if (resource instanceof Response) return resource;
|
|
5312
|
-
if (resource instanceof URL) return fetch(resource);
|
|
5313
|
-
return resource;
|
|
5366
|
+
onLayout() {
|
|
5367
|
+
return of(void 0);
|
|
5314
5368
|
}
|
|
5315
5369
|
}
|
|
5316
|
-
class SpineItem {
|
|
5370
|
+
class SpineItem extends DestroyableClass {
|
|
5317
5371
|
constructor(item, parentElement, context, settings, hookManager, index) {
|
|
5318
5372
|
var _a, _b;
|
|
5373
|
+
super();
|
|
5319
5374
|
this.item = item;
|
|
5320
5375
|
this.parentElement = parentElement;
|
|
5321
5376
|
this.context = context;
|
|
5322
5377
|
this.settings = settings;
|
|
5323
5378
|
this.hookManager = hookManager;
|
|
5324
5379
|
this.index = index;
|
|
5380
|
+
this.layoutTriggerSubject = new Subject();
|
|
5325
5381
|
this.adjustPositionOfElement = ({
|
|
5326
5382
|
right,
|
|
5327
5383
|
left,
|
|
@@ -5353,31 +5409,10 @@ class SpineItem {
|
|
|
5353
5409
|
return (_e = (_d = frameElement.contentDocument) == null ? void 0 : _d.querySelector(selector)) == null ? void 0 : _e.getBoundingClientRect();
|
|
5354
5410
|
}
|
|
5355
5411
|
};
|
|
5356
|
-
this.layout = ({
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
}) => {
|
|
5361
|
-
this.hookManager.execute(`item.onBeforeLayout`, void 0, {
|
|
5362
|
-
blankPagePosition,
|
|
5363
|
-
item: this.item,
|
|
5364
|
-
minimumWidth
|
|
5365
|
-
});
|
|
5366
|
-
const { height, width } = this.renderer.layout({
|
|
5367
|
-
blankPagePosition,
|
|
5368
|
-
minPageSpread: minimumWidth / this.context.getPageSize().width,
|
|
5369
|
-
spreadPosition
|
|
5370
|
-
}) ?? { width: 0, height: 0 };
|
|
5371
|
-
const minHeight = Math.max(height, this.context.getPageSize().height);
|
|
5372
|
-
const minWidth = Math.max(width, minimumWidth);
|
|
5373
|
-
this.containerElement.style.width = `${minWidth}px`;
|
|
5374
|
-
this.containerElement.style.height = `${minHeight}px`;
|
|
5375
|
-
this.hookManager.execute(`item.onAfterLayout`, void 0, {
|
|
5376
|
-
blankPagePosition,
|
|
5377
|
-
item: this.item,
|
|
5378
|
-
minimumWidth
|
|
5379
|
-
});
|
|
5380
|
-
return { width: minWidth, height: minHeight };
|
|
5412
|
+
this.layout = (params) => {
|
|
5413
|
+
const nextResult = deferNextResult(this.layout$.pipe(first()));
|
|
5414
|
+
this.layoutTriggerSubject.next(params);
|
|
5415
|
+
return nextResult();
|
|
5381
5416
|
};
|
|
5382
5417
|
this.load = () => this.renderer.load();
|
|
5383
5418
|
this.unload = () => {
|
|
@@ -5395,16 +5430,14 @@ class SpineItem {
|
|
|
5395
5430
|
return normalizedValues;
|
|
5396
5431
|
};
|
|
5397
5432
|
this.destroy = () => {
|
|
5398
|
-
|
|
5433
|
+
super.destroy();
|
|
5399
5434
|
this.containerElement.remove();
|
|
5400
|
-
this.destroySubject$.complete();
|
|
5401
5435
|
this.renderer.destroy();
|
|
5402
5436
|
};
|
|
5403
5437
|
this.isUsingVerticalWriting = () => {
|
|
5404
5438
|
var _a2;
|
|
5405
5439
|
return !!((_a2 = this.renderer.writingMode) == null ? void 0 : _a2.startsWith(`vertical`));
|
|
5406
5440
|
};
|
|
5407
|
-
this.destroySubject$ = new Subject();
|
|
5408
5441
|
this.containerElement = createContainerElement(
|
|
5409
5442
|
parentElement,
|
|
5410
5443
|
item,
|
|
@@ -5422,17 +5455,62 @@ class SpineItem {
|
|
|
5422
5455
|
resourcesHandler: this.resourcesHandler
|
|
5423
5456
|
};
|
|
5424
5457
|
this.renderer = rendererFactory ? rendererFactory(rendererParams) : new DefaultRenderer(rendererParams);
|
|
5425
|
-
const
|
|
5426
|
-
|
|
5427
|
-
|
|
5458
|
+
const layoutProcess$ = this.layoutTriggerSubject.pipe(
|
|
5459
|
+
switchMap$1(({ blankPagePosition, minimumWidth, spreadPosition }) => {
|
|
5460
|
+
this.hookManager.execute(`item.onBeforeLayout`, void 0, {
|
|
5461
|
+
blankPagePosition,
|
|
5462
|
+
item: this.item,
|
|
5463
|
+
minimumWidth
|
|
5464
|
+
});
|
|
5465
|
+
const layout$ = defer(
|
|
5466
|
+
() => this.renderer.onLayout({
|
|
5467
|
+
blankPagePosition,
|
|
5468
|
+
minPageSpread: minimumWidth / this.context.getPageSize().width,
|
|
5469
|
+
minimumWidth,
|
|
5470
|
+
spreadPosition
|
|
5471
|
+
})
|
|
5472
|
+
);
|
|
5473
|
+
return merge(
|
|
5474
|
+
of({ type: "start" }),
|
|
5475
|
+
layout$.pipe(
|
|
5476
|
+
map((dims) => {
|
|
5477
|
+
const { height, width } = dims ?? { height: 0, width: 0 };
|
|
5478
|
+
const minHeight = Math.max(
|
|
5479
|
+
height,
|
|
5480
|
+
this.context.getPageSize().height
|
|
5481
|
+
);
|
|
5482
|
+
const minWidth = Math.max(width, minimumWidth);
|
|
5483
|
+
this.containerElement.style.width = `${minWidth}px`;
|
|
5484
|
+
this.containerElement.style.height = `${minHeight}px`;
|
|
5485
|
+
this.hookManager.execute(`item.onAfterLayout`, void 0, {
|
|
5486
|
+
blankPagePosition,
|
|
5487
|
+
item: this.item,
|
|
5488
|
+
minimumWidth
|
|
5489
|
+
});
|
|
5490
|
+
return {
|
|
5491
|
+
type: "end",
|
|
5492
|
+
data: { width: minWidth, height: minHeight }
|
|
5493
|
+
};
|
|
5494
|
+
})
|
|
5495
|
+
)
|
|
5496
|
+
);
|
|
5497
|
+
}),
|
|
5498
|
+
share$1()
|
|
5428
5499
|
);
|
|
5429
|
-
this.
|
|
5430
|
-
|
|
5431
|
-
map((
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5500
|
+
this.layout$ = layoutProcess$.pipe(
|
|
5501
|
+
filter((event) => event.type === `end`),
|
|
5502
|
+
map((event) => event.data),
|
|
5503
|
+
share$1()
|
|
5504
|
+
);
|
|
5505
|
+
this.isReady$ = layoutProcess$.pipe(
|
|
5506
|
+
withLatestFrom$1(this.renderer.isLoaded$),
|
|
5507
|
+
map(([event, loaded]) => !!(event.type === `end` && loaded)),
|
|
5508
|
+
startWith(false),
|
|
5509
|
+
distinctUntilChanged(),
|
|
5510
|
+
shareReplay({ refCount: true })
|
|
5435
5511
|
);
|
|
5512
|
+
this.needsLayout$ = merge(this.unloaded$, this.loaded$);
|
|
5513
|
+
merge(this.layout$, this.isReady$).pipe(takeUntil$1(this.destroy$)).subscribe();
|
|
5436
5514
|
}
|
|
5437
5515
|
get element() {
|
|
5438
5516
|
return this.containerElement;
|
|
@@ -5448,15 +5526,6 @@ class SpineItem {
|
|
|
5448
5526
|
get readingDirection() {
|
|
5449
5527
|
return this.renderer.readingDirection;
|
|
5450
5528
|
}
|
|
5451
|
-
get isReady() {
|
|
5452
|
-
return this.renderer.state$.getValue() === "ready";
|
|
5453
|
-
}
|
|
5454
|
-
get ready$() {
|
|
5455
|
-
return this.renderer.state$.pipe(
|
|
5456
|
-
distinctUntilChanged(),
|
|
5457
|
-
filter((state) => state === "ready")
|
|
5458
|
-
);
|
|
5459
|
-
}
|
|
5460
5529
|
get loaded$() {
|
|
5461
5530
|
return this.renderer.state$.pipe(
|
|
5462
5531
|
distinctUntilChanged(),
|
|
@@ -5475,22 +5544,6 @@ class SpineItem {
|
|
|
5475
5544
|
)
|
|
5476
5545
|
);
|
|
5477
5546
|
}
|
|
5478
|
-
get isReady$() {
|
|
5479
|
-
return this.renderer.state$.pipe(map((state) => state === "ready"));
|
|
5480
|
-
}
|
|
5481
|
-
/**
|
|
5482
|
-
* Helper that will inject CSS into the document frame.
|
|
5483
|
-
*
|
|
5484
|
-
* @important
|
|
5485
|
-
* The document needs to be detected as a frame.
|
|
5486
|
-
*/
|
|
5487
|
-
upsertCSS(id, style, prepend) {
|
|
5488
|
-
this.renderer.layers.forEach((layer) => {
|
|
5489
|
-
if (layer.element instanceof HTMLIFrameElement) {
|
|
5490
|
-
upsertCSS(layer.element, id, style, prepend);
|
|
5491
|
-
}
|
|
5492
|
-
});
|
|
5493
|
-
}
|
|
5494
5547
|
}
|
|
5495
5548
|
const createContainerElement = (containerElement, item, hookManager) => {
|
|
5496
5549
|
const element = containerElement.ownerDocument.createElement(`div`);
|
|
@@ -6071,6 +6124,103 @@ const convertSpinePositionToLayoutPosition = ({
|
|
|
6071
6124
|
right: position.x + pageSize.width
|
|
6072
6125
|
};
|
|
6073
6126
|
};
|
|
6127
|
+
const layoutItem = ({
|
|
6128
|
+
horizontalOffset,
|
|
6129
|
+
verticalOffset,
|
|
6130
|
+
context,
|
|
6131
|
+
spineItemsManager,
|
|
6132
|
+
isGloballyPrePaginated,
|
|
6133
|
+
settings,
|
|
6134
|
+
index,
|
|
6135
|
+
item,
|
|
6136
|
+
newItemLayoutInformation
|
|
6137
|
+
}) => {
|
|
6138
|
+
let minimumWidth = context.getPageSize().width;
|
|
6139
|
+
let blankPagePosition = `none`;
|
|
6140
|
+
const itemStartOnNewScreen = horizontalOffset % context.state.visibleAreaRect.width === 0;
|
|
6141
|
+
const isLastItem = index === spineItemsManager.items.length - 1;
|
|
6142
|
+
if (context.state.isUsingSpreadMode) {
|
|
6143
|
+
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && !isLastItem) {
|
|
6144
|
+
minimumWidth = context.getPageSize().width * 2;
|
|
6145
|
+
}
|
|
6146
|
+
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && isLastItem && itemStartOnNewScreen) {
|
|
6147
|
+
minimumWidth = context.getPageSize().width * 2;
|
|
6148
|
+
}
|
|
6149
|
+
const lastItemStartOnNewScreenInAPrepaginatedBook = itemStartOnNewScreen && isLastItem && isGloballyPrePaginated;
|
|
6150
|
+
if (item.item.pageSpreadRight && itemStartOnNewScreen && !context.isRTL()) {
|
|
6151
|
+
blankPagePosition = `before`;
|
|
6152
|
+
minimumWidth = context.getPageSize().width * 2;
|
|
6153
|
+
} else if (item.item.pageSpreadLeft && itemStartOnNewScreen && context.isRTL()) {
|
|
6154
|
+
blankPagePosition = `before`;
|
|
6155
|
+
minimumWidth = context.getPageSize().width * 2;
|
|
6156
|
+
} else if (lastItemStartOnNewScreenInAPrepaginatedBook) {
|
|
6157
|
+
if (context.isRTL()) {
|
|
6158
|
+
blankPagePosition = `before`;
|
|
6159
|
+
} else {
|
|
6160
|
+
blankPagePosition = `after`;
|
|
6161
|
+
}
|
|
6162
|
+
minimumWidth = context.getPageSize().width * 2;
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
const itemLayout$ = item.layout({
|
|
6166
|
+
minimumWidth,
|
|
6167
|
+
blankPagePosition,
|
|
6168
|
+
spreadPosition: context.state.isUsingSpreadMode ? itemStartOnNewScreen ? context.isRTL() ? `right` : `left` : context.isRTL() ? `left` : `right` : `none`
|
|
6169
|
+
});
|
|
6170
|
+
return itemLayout$.pipe(
|
|
6171
|
+
map$1(({ width, height }) => {
|
|
6172
|
+
if (settings.values.computedPageTurnDirection === `vertical`) {
|
|
6173
|
+
const currentValidEdgeYForVerticalPositioning = itemStartOnNewScreen ? verticalOffset : verticalOffset - context.state.visibleAreaRect.height;
|
|
6174
|
+
const currentValidEdgeXForVerticalPositioning = itemStartOnNewScreen ? 0 : horizontalOffset;
|
|
6175
|
+
if (context.isRTL()) {
|
|
6176
|
+
item.adjustPositionOfElement({
|
|
6177
|
+
top: currentValidEdgeYForVerticalPositioning,
|
|
6178
|
+
left: currentValidEdgeXForVerticalPositioning
|
|
6179
|
+
});
|
|
6180
|
+
} else {
|
|
6181
|
+
item.adjustPositionOfElement({
|
|
6182
|
+
top: currentValidEdgeYForVerticalPositioning,
|
|
6183
|
+
left: currentValidEdgeXForVerticalPositioning
|
|
6184
|
+
});
|
|
6185
|
+
}
|
|
6186
|
+
const newEdgeX = width + currentValidEdgeXForVerticalPositioning;
|
|
6187
|
+
const newEdgeY = height + currentValidEdgeYForVerticalPositioning;
|
|
6188
|
+
newItemLayoutInformation.push({
|
|
6189
|
+
left: currentValidEdgeXForVerticalPositioning,
|
|
6190
|
+
right: newEdgeX,
|
|
6191
|
+
top: currentValidEdgeYForVerticalPositioning,
|
|
6192
|
+
bottom: newEdgeY,
|
|
6193
|
+
height,
|
|
6194
|
+
width,
|
|
6195
|
+
x: currentValidEdgeXForVerticalPositioning,
|
|
6196
|
+
y: currentValidEdgeYForVerticalPositioning
|
|
6197
|
+
});
|
|
6198
|
+
return {
|
|
6199
|
+
horizontalOffset: newEdgeX,
|
|
6200
|
+
verticalOffset: newEdgeY
|
|
6201
|
+
};
|
|
6202
|
+
}
|
|
6203
|
+
item.adjustPositionOfElement(
|
|
6204
|
+
context.isRTL() ? { right: horizontalOffset, top: 0 } : { left: horizontalOffset, top: 0 }
|
|
6205
|
+
);
|
|
6206
|
+
const left = context.isRTL() ? context.state.visibleAreaRect.width - horizontalOffset - width : horizontalOffset;
|
|
6207
|
+
newItemLayoutInformation.push({
|
|
6208
|
+
right: context.isRTL() ? context.state.visibleAreaRect.width - horizontalOffset : horizontalOffset + width,
|
|
6209
|
+
left,
|
|
6210
|
+
x: left,
|
|
6211
|
+
top: verticalOffset,
|
|
6212
|
+
bottom: height,
|
|
6213
|
+
height,
|
|
6214
|
+
width,
|
|
6215
|
+
y: verticalOffset
|
|
6216
|
+
});
|
|
6217
|
+
return {
|
|
6218
|
+
horizontalOffset: horizontalOffset + width,
|
|
6219
|
+
verticalOffset: 0
|
|
6220
|
+
};
|
|
6221
|
+
})
|
|
6222
|
+
);
|
|
6223
|
+
};
|
|
6074
6224
|
const NAMESPACE = `SpineLayout`;
|
|
6075
6225
|
class SpineLayout extends DestroyableClass {
|
|
6076
6226
|
constructor(spineItemsManager, context, settings) {
|
|
@@ -6082,8 +6232,8 @@ class SpineLayout extends DestroyableClass {
|
|
|
6082
6232
|
this.layoutSubject = new Subject();
|
|
6083
6233
|
spineItemsManager.items$.pipe(
|
|
6084
6234
|
switchMap((items) => {
|
|
6085
|
-
const
|
|
6086
|
-
(spineItem) => spineItem.
|
|
6235
|
+
const needsLayouts$ = items.map(
|
|
6236
|
+
(spineItem) => spineItem.needsLayout$.pipe(
|
|
6087
6237
|
tap$1(() => {
|
|
6088
6238
|
this.layout();
|
|
6089
6239
|
})
|
|
@@ -6104,12 +6254,60 @@ class SpineLayout extends DestroyableClass {
|
|
|
6104
6254
|
})
|
|
6105
6255
|
)
|
|
6106
6256
|
);
|
|
6107
|
-
return merge(...
|
|
6257
|
+
return merge(...needsLayouts$, ...writingModeUpdate$);
|
|
6108
6258
|
})
|
|
6109
6259
|
).pipe(takeUntil(this.destroy$)).subscribe();
|
|
6260
|
+
const layoutInProgress = new BehaviorSubject(false);
|
|
6110
6261
|
this.layout$ = this.layoutSubject.pipe(
|
|
6111
|
-
|
|
6112
|
-
|
|
6262
|
+
debounceTime$1(50),
|
|
6263
|
+
// queue layout until previous layout is done
|
|
6264
|
+
exhaustMap(
|
|
6265
|
+
() => layoutInProgress.pipe(
|
|
6266
|
+
filter$1((value) => !value),
|
|
6267
|
+
first$1()
|
|
6268
|
+
)
|
|
6269
|
+
),
|
|
6270
|
+
exhaustMap(() => {
|
|
6271
|
+
layoutInProgress.next(true);
|
|
6272
|
+
const manifest = this.context.manifest;
|
|
6273
|
+
const newItemLayoutInformation = [];
|
|
6274
|
+
const isGloballyPrePaginated = (manifest == null ? void 0 : manifest.renditionLayout) === `pre-paginated`;
|
|
6275
|
+
return from(this.spineItemsManager.items).pipe(
|
|
6276
|
+
reduce(
|
|
6277
|
+
(acc$, item, index) => acc$.pipe(
|
|
6278
|
+
concatMap(
|
|
6279
|
+
({ horizontalOffset, verticalOffset }) => layoutItem({
|
|
6280
|
+
context: this.context,
|
|
6281
|
+
horizontalOffset,
|
|
6282
|
+
index,
|
|
6283
|
+
isGloballyPrePaginated,
|
|
6284
|
+
item,
|
|
6285
|
+
settings: this.settings,
|
|
6286
|
+
spineItemsManager: this.spineItemsManager,
|
|
6287
|
+
verticalOffset,
|
|
6288
|
+
newItemLayoutInformation
|
|
6289
|
+
})
|
|
6290
|
+
)
|
|
6291
|
+
),
|
|
6292
|
+
of({ horizontalOffset: 0, verticalOffset: 0 })
|
|
6293
|
+
),
|
|
6294
|
+
concatMap((layout$) => layout$),
|
|
6295
|
+
map$1(() => {
|
|
6296
|
+
const hasChanged = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
|
|
6297
|
+
(old, index) => !isShallowEqual(old, newItemLayoutInformation[index])
|
|
6298
|
+
);
|
|
6299
|
+
this.itemLayoutInformation = newItemLayoutInformation;
|
|
6300
|
+
Report.log(NAMESPACE, `layout`, {
|
|
6301
|
+
hasChanged,
|
|
6302
|
+
itemLayoutInformation: this.itemLayoutInformation
|
|
6303
|
+
});
|
|
6304
|
+
return { hasChanged };
|
|
6305
|
+
}),
|
|
6306
|
+
finalize(() => {
|
|
6307
|
+
layoutInProgress.next(false);
|
|
6308
|
+
})
|
|
6309
|
+
);
|
|
6310
|
+
}),
|
|
6113
6311
|
map$1(({ hasChanged }) => {
|
|
6114
6312
|
const items = spineItemsManager.items;
|
|
6115
6313
|
const spineItemsPagesAbsolutePositions = items.map((item) => {
|
|
@@ -6159,116 +6357,13 @@ class SpineLayout extends DestroyableClass {
|
|
|
6159
6357
|
pages
|
|
6160
6358
|
};
|
|
6161
6359
|
}),
|
|
6162
|
-
|
|
6360
|
+
share()
|
|
6163
6361
|
);
|
|
6362
|
+
this.info$ = this.layout$.pipe(shareReplay$1({ refCount: true }));
|
|
6363
|
+
merge(this.layout$, this.info$).pipe(takeUntil(this.destroy$)).subscribe();
|
|
6164
6364
|
}
|
|
6165
|
-
/**
|
|
6166
|
-
* @todo
|
|
6167
|
-
* move this logic to the spine
|
|
6168
|
-
*
|
|
6169
|
-
* @todo
|
|
6170
|
-
* make sure to check how many times it is being called and try to reduce number of layouts
|
|
6171
|
-
* it is called eery time an item is being unload (which can adds up quickly for big books)
|
|
6172
|
-
*/
|
|
6173
6365
|
layout() {
|
|
6174
|
-
|
|
6175
|
-
const newItemLayoutInformation = [];
|
|
6176
|
-
const isGloballyPrePaginated = (manifest == null ? void 0 : manifest.renditionLayout) === `pre-paginated`;
|
|
6177
|
-
this.spineItemsManager.items.reduce(
|
|
6178
|
-
({ horizontalOffset, verticalOffset }, item, index) => {
|
|
6179
|
-
let minimumWidth = this.context.getPageSize().width;
|
|
6180
|
-
let blankPagePosition = `none`;
|
|
6181
|
-
const itemStartOnNewScreen = horizontalOffset % this.context.state.visibleAreaRect.width === 0;
|
|
6182
|
-
const isLastItem = index === this.spineItemsManager.items.length - 1;
|
|
6183
|
-
if (this.context.state.isUsingSpreadMode) {
|
|
6184
|
-
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && !isLastItem) {
|
|
6185
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
6186
|
-
}
|
|
6187
|
-
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && isLastItem && itemStartOnNewScreen) {
|
|
6188
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
6189
|
-
}
|
|
6190
|
-
const lastItemStartOnNewScreenInAPrepaginatedBook = itemStartOnNewScreen && isLastItem && isGloballyPrePaginated;
|
|
6191
|
-
if (item.item.pageSpreadRight && itemStartOnNewScreen && !this.context.isRTL()) {
|
|
6192
|
-
blankPagePosition = `before`;
|
|
6193
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
6194
|
-
} else if (item.item.pageSpreadLeft && itemStartOnNewScreen && this.context.isRTL()) {
|
|
6195
|
-
blankPagePosition = `before`;
|
|
6196
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
6197
|
-
} else if (lastItemStartOnNewScreenInAPrepaginatedBook) {
|
|
6198
|
-
if (this.context.isRTL()) {
|
|
6199
|
-
blankPagePosition = `before`;
|
|
6200
|
-
} else {
|
|
6201
|
-
blankPagePosition = `after`;
|
|
6202
|
-
}
|
|
6203
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
6204
|
-
}
|
|
6205
|
-
}
|
|
6206
|
-
const { width, height } = item.layout({
|
|
6207
|
-
minimumWidth,
|
|
6208
|
-
blankPagePosition,
|
|
6209
|
-
spreadPosition: this.context.state.isUsingSpreadMode ? itemStartOnNewScreen ? this.context.isRTL() ? `right` : `left` : this.context.isRTL() ? `left` : `right` : `none`
|
|
6210
|
-
});
|
|
6211
|
-
if (this.settings.values.computedPageTurnDirection === `vertical`) {
|
|
6212
|
-
const currentValidEdgeYForVerticalPositioning = itemStartOnNewScreen ? verticalOffset : verticalOffset - this.context.state.visibleAreaRect.height;
|
|
6213
|
-
const currentValidEdgeXForVerticalPositioning = itemStartOnNewScreen ? 0 : horizontalOffset;
|
|
6214
|
-
if (this.context.isRTL()) {
|
|
6215
|
-
item.adjustPositionOfElement({
|
|
6216
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
6217
|
-
left: currentValidEdgeXForVerticalPositioning
|
|
6218
|
-
});
|
|
6219
|
-
} else {
|
|
6220
|
-
item.adjustPositionOfElement({
|
|
6221
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
6222
|
-
left: currentValidEdgeXForVerticalPositioning
|
|
6223
|
-
});
|
|
6224
|
-
}
|
|
6225
|
-
const newEdgeX = width + currentValidEdgeXForVerticalPositioning;
|
|
6226
|
-
const newEdgeY = height + currentValidEdgeYForVerticalPositioning;
|
|
6227
|
-
newItemLayoutInformation.push({
|
|
6228
|
-
left: currentValidEdgeXForVerticalPositioning,
|
|
6229
|
-
right: newEdgeX,
|
|
6230
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
6231
|
-
bottom: newEdgeY,
|
|
6232
|
-
height,
|
|
6233
|
-
width,
|
|
6234
|
-
x: currentValidEdgeXForVerticalPositioning,
|
|
6235
|
-
y: currentValidEdgeYForVerticalPositioning
|
|
6236
|
-
});
|
|
6237
|
-
return {
|
|
6238
|
-
horizontalOffset: newEdgeX,
|
|
6239
|
-
verticalOffset: newEdgeY
|
|
6240
|
-
};
|
|
6241
|
-
}
|
|
6242
|
-
item.adjustPositionOfElement(
|
|
6243
|
-
this.context.isRTL() ? { right: horizontalOffset, top: 0 } : { left: horizontalOffset, top: 0 }
|
|
6244
|
-
);
|
|
6245
|
-
const left = this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset - width : horizontalOffset;
|
|
6246
|
-
newItemLayoutInformation.push({
|
|
6247
|
-
right: this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset : horizontalOffset + width,
|
|
6248
|
-
left,
|
|
6249
|
-
x: left,
|
|
6250
|
-
top: verticalOffset,
|
|
6251
|
-
bottom: height,
|
|
6252
|
-
height,
|
|
6253
|
-
width,
|
|
6254
|
-
y: verticalOffset
|
|
6255
|
-
});
|
|
6256
|
-
return {
|
|
6257
|
-
horizontalOffset: horizontalOffset + width,
|
|
6258
|
-
verticalOffset: 0
|
|
6259
|
-
};
|
|
6260
|
-
},
|
|
6261
|
-
{ horizontalOffset: 0, verticalOffset: 0 }
|
|
6262
|
-
);
|
|
6263
|
-
const hasLayoutChanges = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
|
|
6264
|
-
(old, index) => !isShallowEqual(old, newItemLayoutInformation[index])
|
|
6265
|
-
);
|
|
6266
|
-
this.itemLayoutInformation = newItemLayoutInformation;
|
|
6267
|
-
Report.log(NAMESPACE, `layout`, {
|
|
6268
|
-
hasLayoutChanges,
|
|
6269
|
-
itemLayoutInformation: this.itemLayoutInformation
|
|
6270
|
-
});
|
|
6271
|
-
this.layoutSubject.next(hasLayoutChanges);
|
|
6366
|
+
this.layoutSubject.next(void 0);
|
|
6272
6367
|
}
|
|
6273
6368
|
/**
|
|
6274
6369
|
* It's important to not use x,y since we need the absolute position of each element. Otherwise x,y would be relative to
|
|
@@ -6851,7 +6946,7 @@ class ImageRenderer extends DocumentRenderer {
|
|
|
6851
6946
|
this.layers = [];
|
|
6852
6947
|
return EMPTY;
|
|
6853
6948
|
}
|
|
6854
|
-
|
|
6949
|
+
onLayout({
|
|
6855
6950
|
spreadPosition
|
|
6856
6951
|
}) {
|
|
6857
6952
|
var _a, _b;
|
|
@@ -6871,10 +6966,10 @@ class ImageRenderer extends DocumentRenderer {
|
|
|
6871
6966
|
element.style.width = `${width}px`;
|
|
6872
6967
|
element.style.objectPosition = spreadPosition === "left" ? `right` : spreadPosition === `right` ? `left` : `center`;
|
|
6873
6968
|
}
|
|
6874
|
-
return {
|
|
6969
|
+
return of({
|
|
6875
6970
|
width,
|
|
6876
6971
|
height
|
|
6877
|
-
};
|
|
6972
|
+
});
|
|
6878
6973
|
}
|
|
6879
6974
|
}
|
|
6880
6975
|
const mediaEnhancer = (next) => (options) => {
|
|
@@ -6970,36 +7065,41 @@ const mediaEnhancer = (next) => (options) => {
|
|
|
6970
7065
|
const progressionEnhancer = (next) => (options) => {
|
|
6971
7066
|
const reader = next(options);
|
|
6972
7067
|
const getPercentageEstimate = (context, currentSpineIndex, numberOfPages, pageIndex, currentPosition, currentItem) => {
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7068
|
+
return currentItem.isReady$.pipe(
|
|
7069
|
+
first$1(),
|
|
7070
|
+
map$1((itemIsReady) => {
|
|
7071
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7072
|
+
const isGloballyPrePaginated = ((_a = context.manifest) == null ? void 0 : _a.renditionLayout) === `pre-paginated`;
|
|
7073
|
+
const readingOrderLength = ((_b = context.manifest) == null ? void 0 : _b.spineItems.length) || 0;
|
|
7074
|
+
const estimateBeforeThisItem = ((_c = context.manifest) == null ? void 0 : _c.spineItems.slice(0, currentSpineIndex).reduce((acc, item) => acc + (item.progressionWeight ?? 0), 0)) || 0;
|
|
7075
|
+
const currentItemWeight = ((_e = (_d = context.manifest) == null ? void 0 : _d.spineItems[currentSpineIndex]) == null ? void 0 : _e.progressionWeight) || 0;
|
|
7076
|
+
let progressWithinThisItem = (pageIndex + 1) * (currentItemWeight / numberOfPages);
|
|
7077
|
+
if (!isGloballyPrePaginated && currentItem.item.renditionLayout === `reflowable` && !itemIsReady) {
|
|
7078
|
+
progressWithinThisItem = 0;
|
|
7079
|
+
}
|
|
7080
|
+
let totalProgress = estimateBeforeThisItem + progressWithinThisItem;
|
|
7081
|
+
if (((_f = context.manifest) == null ? void 0 : _f.renditionFlow) === `scrolled-continuous`) {
|
|
7082
|
+
if (itemIsReady) {
|
|
7083
|
+
progressWithinThisItem = getScrollPercentageWithinItem(
|
|
7084
|
+
context,
|
|
7085
|
+
currentPosition,
|
|
7086
|
+
currentItem
|
|
7087
|
+
);
|
|
7088
|
+
} else {
|
|
7089
|
+
progressWithinThisItem = 0;
|
|
7090
|
+
}
|
|
7091
|
+
totalProgress = getTotalProgressFromPercentages(
|
|
7092
|
+
estimateBeforeThisItem,
|
|
7093
|
+
currentItemWeight,
|
|
7094
|
+
progressWithinThisItem
|
|
7095
|
+
);
|
|
7096
|
+
}
|
|
7097
|
+
if (currentSpineIndex === readingOrderLength - 1 && pageIndex === numberOfPages - 1 && totalProgress > 0.99) {
|
|
7098
|
+
return 1;
|
|
7099
|
+
}
|
|
7100
|
+
return totalProgress;
|
|
7101
|
+
})
|
|
7102
|
+
);
|
|
7003
7103
|
};
|
|
7004
7104
|
const getTotalProgressFromPercentages = (estimateBeforeThisItem, currentItemWeight, progressWithinThisItem) => {
|
|
7005
7105
|
return estimateBeforeThisItem + currentItemWeight * progressWithinThisItem;
|
|
@@ -7052,19 +7152,24 @@ const accessibilityEnhancer = (next) => (options) => {
|
|
|
7052
7152
|
if (!(frame instanceof HTMLIFrameElement)) return;
|
|
7053
7153
|
const item = reader.spineItemsManager.get(itemId);
|
|
7054
7154
|
if (!item) return;
|
|
7055
|
-
item.
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7155
|
+
item.renderer.layers.forEach((layer) => {
|
|
7156
|
+
if (layer.element instanceof HTMLIFrameElement) {
|
|
7157
|
+
upsertCSS(
|
|
7158
|
+
layer.element,
|
|
7159
|
+
`prose-reader-accessibility`,
|
|
7160
|
+
`
|
|
7161
|
+
:focus-visible {
|
|
7162
|
+
${/*
|
|
7163
|
+
Some epubs remove the outline, this is not good practice since it reduce accessibility.
|
|
7164
|
+
We will try to restore it by force.
|
|
7165
|
+
*/
|
|
7166
|
+
``}
|
|
7167
|
+
outline: -webkit-focus-ring-color auto 1px;
|
|
7168
|
+
}
|
|
7169
|
+
`
|
|
7170
|
+
);
|
|
7065
7171
|
}
|
|
7066
|
-
|
|
7067
|
-
);
|
|
7172
|
+
});
|
|
7068
7173
|
const links = (_b = frame.contentDocument) == null ? void 0 : _b.body.querySelectorAll(`a`);
|
|
7069
7174
|
links == null ? void 0 : links.forEach((link) => {
|
|
7070
7175
|
observer.observe(link);
|
|
@@ -8028,7 +8133,7 @@ class HtmlRenderer extends DocumentRenderer {
|
|
|
8028
8133
|
this.layers = [];
|
|
8029
8134
|
return EMPTY;
|
|
8030
8135
|
}
|
|
8031
|
-
|
|
8136
|
+
onLayout({
|
|
8032
8137
|
minPageSpread,
|
|
8033
8138
|
blankPagePosition,
|
|
8034
8139
|
spreadPosition
|
|
@@ -8036,10 +8141,10 @@ class HtmlRenderer extends DocumentRenderer {
|
|
|
8036
8141
|
var _a;
|
|
8037
8142
|
const { width: pageWidth, height: pageHeight } = this.context.getPageSize();
|
|
8038
8143
|
const frameElement = this.getFrameElement();
|
|
8039
|
-
if (!frameElement) return { width: pageWidth, height: pageHeight };
|
|
8144
|
+
if (!frameElement) return of({ width: pageWidth, height: pageHeight });
|
|
8040
8145
|
const isUsingVerticalWriting = !!((_a = this.writingMode) == null ? void 0 : _a.startsWith(`vertical`));
|
|
8041
8146
|
if (this.item.renditionLayout === `pre-paginated`) {
|
|
8042
|
-
|
|
8147
|
+
const dims = renderPrePaginated({
|
|
8043
8148
|
blankPagePosition,
|
|
8044
8149
|
enableTouch: this.settings.values.computedPageTurnMode !== `scrollable`,
|
|
8045
8150
|
frameElement,
|
|
@@ -8049,6 +8154,7 @@ class HtmlRenderer extends DocumentRenderer {
|
|
|
8049
8154
|
pageWidth,
|
|
8050
8155
|
spreadPosition
|
|
8051
8156
|
});
|
|
8157
|
+
return of(dims);
|
|
8052
8158
|
}
|
|
8053
8159
|
const { latestContentHeightWhenLoaded, ...rest } = renderReflowable({
|
|
8054
8160
|
pageHeight,
|
|
@@ -8064,7 +8170,7 @@ class HtmlRenderer extends DocumentRenderer {
|
|
|
8064
8170
|
enableTouch: this.settings.values.computedPageTurnMode !== `scrollable`
|
|
8065
8171
|
});
|
|
8066
8172
|
this.latestContentHeightWhenLoaded = latestContentHeightWhenLoaded;
|
|
8067
|
-
return rest;
|
|
8173
|
+
return of(rest);
|
|
8068
8174
|
}
|
|
8069
8175
|
getFrameElement() {
|
|
8070
8176
|
var _a;
|
|
@@ -8146,7 +8252,6 @@ const createRangeFromSelection = ({
|
|
|
8146
8252
|
selection,
|
|
8147
8253
|
spineItem
|
|
8148
8254
|
}) => {
|
|
8149
|
-
if (!spineItem.isReady) return void 0;
|
|
8150
8255
|
const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
|
|
8151
8256
|
if (!anchorNode || !focusNode) {
|
|
8152
8257
|
return void 0;
|