@prose-reader/core 1.124.0 → 1.126.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/cfi/generate/generateCfi.d.ts +2 -0
- package/dist/cfi/generate/generateCfiFronSelection.d.ts +8 -0
- package/dist/cfi/generate/getItemAnchor.d.ts +2 -2
- package/dist/cfi/lookup/parseCfi.d.ts +5 -0
- package/dist/cfi/lookup/resolveCfi.d.ts +0 -2
- package/dist/createReaderWithEnhancer.d.ts +27 -14
- package/dist/enhancers/html/renderer/HtmlRenderer.d.ts +0 -6
- package/dist/enhancers/selection/selection.d.ts +17 -7
- package/dist/enhancers/selection/selectionEnhancer.d.ts +11 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1172 -1130
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1172 -1130
- package/dist/index.umd.cjs.map +1 -1
- package/dist/reader.d.ts +13 -3
- package/dist/settings/types.d.ts +3 -5
- package/dist/spine/SpineItemsManager.d.ts +1 -1
- package/dist/spineItem/DocumentRenderer.d.ts +18 -3
- package/package.json +3 -3
- package/dist/cfi/lookup/extractProseMetadataFromCfi.d.ts +0 -5
package/dist/index.js
CHANGED
|
@@ -265,7 +265,7 @@ const createMovingSafePan$ = (reader) => {
|
|
|
265
265
|
})
|
|
266
266
|
);
|
|
267
267
|
const resetLockViewportFree$ = createResetLock$(
|
|
268
|
-
reader.
|
|
268
|
+
reader.viewportFree$
|
|
269
269
|
).pipe(take(1));
|
|
270
270
|
const pageTurnMode$ = reader.settings.values$.pipe(
|
|
271
271
|
map(() => reader.settings.values.computedPageTurnMode),
|
|
@@ -1515,7 +1515,9 @@ const themeEnhancer = (next) => (options) => {
|
|
|
1515
1515
|
};
|
|
1516
1516
|
reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {
|
|
1517
1517
|
const item = reader.spineItemsManager.get(itemId);
|
|
1518
|
-
item == null ? void 0 : item.
|
|
1518
|
+
if ((item == null ? void 0 : item.item.renditionLayout) !== "pre-paginated") {
|
|
1519
|
+
item == null ? void 0 : item.upsertCSS(`prose-reader-theme`, getStyle());
|
|
1520
|
+
}
|
|
1519
1521
|
});
|
|
1520
1522
|
reader.spineItemsManager.items$.pipe(
|
|
1521
1523
|
tap(
|
|
@@ -3417,15 +3419,16 @@ class CfiHandler {
|
|
|
3417
3419
|
return this.resolveLast(doc, opts);
|
|
3418
3420
|
}
|
|
3419
3421
|
}
|
|
3420
|
-
const
|
|
3422
|
+
const parseCfi = (cfi) => {
|
|
3421
3423
|
var _a, _b;
|
|
3422
|
-
const [
|
|
3424
|
+
const [itemIndex] = ((_a = cfi.match(/\|(\[prose\~anchor[^\]]*\])+/gi)) == null ? void 0 : _a.map((s) => s.replace(/\|\[prose\~anchor\~/, ``).replace(/\]/, ``))) || [];
|
|
3423
3425
|
const [offset] = ((_b = cfi.match(/\|(\[prose\~offset[^\]]*\])+/gi)) == null ? void 0 : _b.map((s) => s.replace(/\|\[prose\~offset\~/, ``).replace(/\]/, ``))) || [];
|
|
3424
3426
|
const cleanedCfi = cfi.replace(/\|(\[prose\~[^\]]*\~[^\]]*\])+/gi, ``);
|
|
3425
3427
|
const foundOffset = parseInt(offset || ``);
|
|
3428
|
+
const foundItemIndex = parseInt(itemIndex || ``);
|
|
3426
3429
|
return {
|
|
3427
3430
|
cleanedCfi,
|
|
3428
|
-
|
|
3431
|
+
itemIndex: isNaN(foundItemIndex) ? void 0 : foundItemIndex,
|
|
3429
3432
|
offset: isNaN(foundOffset) ? void 0 : foundOffset
|
|
3430
3433
|
};
|
|
3431
3434
|
};
|
|
@@ -3436,9 +3439,8 @@ const resolveCfi = ({
|
|
|
3436
3439
|
var _a, _b;
|
|
3437
3440
|
if (!cfi) return void 0;
|
|
3438
3441
|
const spineItem = spineItemsManager.getSpineItemFromCfi(cfi);
|
|
3439
|
-
const spineItemIndex = spineItemsManager.getSpineItemIndex(spineItem) || 0;
|
|
3440
3442
|
if (!spineItem) return void 0;
|
|
3441
|
-
const { cleanedCfi, offset } =
|
|
3443
|
+
const { cleanedCfi, offset } = parseCfi(cfi);
|
|
3442
3444
|
const cfiHandler = new CfiHandler(cleanedCfi, {});
|
|
3443
3445
|
const rendererElement = (_a = spineItem.renderer.layers[0]) == null ? void 0 : _a.element;
|
|
3444
3446
|
if (rendererElement instanceof HTMLIFrameElement) {
|
|
@@ -3449,20 +3451,17 @@ const resolveCfi = ({
|
|
|
3449
3451
|
return {
|
|
3450
3452
|
node,
|
|
3451
3453
|
offset: offset ?? resolvedOffset,
|
|
3452
|
-
spineItemIndex,
|
|
3453
3454
|
spineItem
|
|
3454
3455
|
};
|
|
3455
3456
|
} catch (e) {
|
|
3456
3457
|
Report.error(e);
|
|
3457
3458
|
return {
|
|
3458
|
-
spineItemIndex,
|
|
3459
3459
|
spineItem
|
|
3460
3460
|
};
|
|
3461
3461
|
}
|
|
3462
3462
|
}
|
|
3463
3463
|
}
|
|
3464
3464
|
return {
|
|
3465
|
-
spineItemIndex,
|
|
3466
3465
|
spineItem
|
|
3467
3466
|
};
|
|
3468
3467
|
};
|
|
@@ -5011,11 +5010,19 @@ class HookManager {
|
|
|
5011
5010
|
return combineLatest(destroyFns);
|
|
5012
5011
|
}
|
|
5013
5012
|
}
|
|
5014
|
-
const getItemAnchor = (
|
|
5013
|
+
const getItemAnchor = (item) => `|[prose~anchor~${encodeURIComponent(item.index)}]`;
|
|
5015
5014
|
const getRootCfi = (spineItem) => {
|
|
5016
|
-
const itemAnchor = getItemAnchor(spineItem);
|
|
5015
|
+
const itemAnchor = getItemAnchor(spineItem.item);
|
|
5017
5016
|
return `epubcfi(/0${itemAnchor})`;
|
|
5018
5017
|
};
|
|
5018
|
+
const generateCfi = (node, offset, item) => {
|
|
5019
|
+
const offsetAnchor = `[prose~offset~${offset || 0}]`;
|
|
5020
|
+
return CfiHandler.generate(
|
|
5021
|
+
node,
|
|
5022
|
+
offset,
|
|
5023
|
+
`${getItemAnchor(item)}|${offsetAnchor}`
|
|
5024
|
+
);
|
|
5025
|
+
};
|
|
5019
5026
|
const generateCfiForSpineItemPage = Report.measurePerformance(
|
|
5020
5027
|
`getCfi`,
|
|
5021
5028
|
10,
|
|
@@ -5030,13 +5037,11 @@ const generateCfiForSpineItemPage = Report.measurePerformance(
|
|
|
5030
5037
|
spineItem
|
|
5031
5038
|
);
|
|
5032
5039
|
const rendererElement = (_a = spineItem.renderer.layers[0]) == null ? void 0 : _a.element;
|
|
5033
|
-
const itemAnchor = getItemAnchor(spineItem);
|
|
5034
|
-
const offset = `|[prose~offset~${(nodeOrRange == null ? void 0 : nodeOrRange.offset) || 0}]`;
|
|
5035
5040
|
if (nodeOrRange && rendererElement instanceof HTMLIFrameElement && ((_b = rendererElement.contentWindow) == null ? void 0 : _b.document)) {
|
|
5036
|
-
const cfiString =
|
|
5041
|
+
const cfiString = generateCfi(
|
|
5037
5042
|
nodeOrRange.node,
|
|
5038
|
-
|
|
5039
|
-
|
|
5043
|
+
nodeOrRange.offset,
|
|
5044
|
+
spineItem.item
|
|
5040
5045
|
);
|
|
5041
5046
|
return cfiString.trim();
|
|
5042
5047
|
}
|
|
@@ -5160,1144 +5165,1136 @@ const generateCfiFromRange = ({
|
|
|
5160
5165
|
end,
|
|
5161
5166
|
endNode
|
|
5162
5167
|
}, item) => {
|
|
5163
|
-
const startCFI =
|
|
5164
|
-
|
|
5165
|
-
start,
|
|
5166
|
-
`|[prose~anchor~${encodeURIComponent(item.id)}]`
|
|
5167
|
-
);
|
|
5168
|
-
const endCFI = CfiHandler.generate(
|
|
5169
|
-
endNode,
|
|
5170
|
-
end,
|
|
5171
|
-
`|[prose~anchor~${encodeURIComponent(item.id)}]`
|
|
5172
|
-
);
|
|
5168
|
+
const startCFI = generateCfi(startNode, start, item);
|
|
5169
|
+
const endCFI = generateCfi(endNode, end, item);
|
|
5173
5170
|
return { start: startCFI, end: endCFI };
|
|
5174
5171
|
};
|
|
5175
|
-
class
|
|
5176
|
-
constructor(
|
|
5177
|
-
|
|
5178
|
-
this.
|
|
5179
|
-
this.
|
|
5180
|
-
|
|
5181
|
-
|
|
5172
|
+
class DocumentRenderer {
|
|
5173
|
+
constructor(params) {
|
|
5174
|
+
this.triggerSubject = new Subject();
|
|
5175
|
+
this.stateSubject = new BehaviorSubject(`idle`);
|
|
5176
|
+
this.unload$ = this.triggerSubject.pipe(
|
|
5177
|
+
withLatestFrom(this.stateSubject),
|
|
5178
|
+
filter$1(
|
|
5179
|
+
([trigger, state]) => trigger === `unload` && state !== "idle" && state !== "unloading"
|
|
5180
|
+
),
|
|
5181
|
+
map$1(() => void 0),
|
|
5182
|
+
share()
|
|
5183
|
+
);
|
|
5184
|
+
this.load$ = this.triggerSubject.pipe(
|
|
5185
|
+
withLatestFrom(this.stateSubject),
|
|
5186
|
+
filter$1(
|
|
5187
|
+
([trigger, state]) => trigger === `load` && state !== "ready" && state !== "loaded" && state !== "loading"
|
|
5188
|
+
),
|
|
5189
|
+
map$1(() => void 0),
|
|
5190
|
+
share()
|
|
5191
|
+
);
|
|
5192
|
+
this.layers = [];
|
|
5193
|
+
this.destroy$ = this.triggerSubject.pipe(
|
|
5194
|
+
filter$1((trigger) => trigger === `destroy`)
|
|
5195
|
+
);
|
|
5196
|
+
this.context = params.context;
|
|
5197
|
+
this.settings = params.settings;
|
|
5198
|
+
this.hookManager = params.hookManager;
|
|
5199
|
+
this.item = params.item;
|
|
5200
|
+
this.containerElement = params.containerElement;
|
|
5201
|
+
this.resourcesHandler = params.resourcesHandler;
|
|
5202
|
+
this.load$.pipe(
|
|
5203
|
+
switchMap(() => {
|
|
5204
|
+
this.stateSubject.next(`loading`);
|
|
5205
|
+
const createDocument$ = this.onCreateDocument().pipe(
|
|
5206
|
+
endWith(null),
|
|
5207
|
+
first$1()
|
|
5208
|
+
);
|
|
5209
|
+
return createDocument$.pipe(
|
|
5210
|
+
tap$1(() => {
|
|
5211
|
+
this.hookManager.execute(`item.onDocumentCreated`, this.item.id, {
|
|
5212
|
+
itemId: this.item.id,
|
|
5213
|
+
layers: this.layers
|
|
5214
|
+
});
|
|
5215
|
+
}),
|
|
5216
|
+
switchMap(() => {
|
|
5217
|
+
const loadDocument$ = this.onLoadDocument().pipe(
|
|
5218
|
+
endWith(null),
|
|
5219
|
+
first$1()
|
|
5220
|
+
);
|
|
5221
|
+
return loadDocument$;
|
|
5222
|
+
}),
|
|
5223
|
+
waitForSwitch(this.context.bridgeEvent.viewportFree$),
|
|
5224
|
+
switchMap(() => {
|
|
5225
|
+
const hookResults = this.hookManager.execute(`item.onDocumentLoad`, this.item.id, {
|
|
5226
|
+
itemId: this.item.id,
|
|
5227
|
+
layers: this.layers
|
|
5228
|
+
}).filter(
|
|
5229
|
+
(result) => result instanceof Observable
|
|
5230
|
+
);
|
|
5231
|
+
return combineLatest([of(null), ...hookResults]).pipe(first$1());
|
|
5232
|
+
}),
|
|
5233
|
+
tap$1(() => {
|
|
5234
|
+
this.stateSubject.next(`loaded`);
|
|
5235
|
+
this.stateSubject.next(`ready`);
|
|
5236
|
+
}),
|
|
5237
|
+
takeUntil(merge(this.destroy$, this.unload$))
|
|
5238
|
+
);
|
|
5239
|
+
})
|
|
5240
|
+
).subscribe();
|
|
5241
|
+
this.unload$.pipe(
|
|
5242
|
+
switchMap(() => {
|
|
5243
|
+
this.stateSubject.next(`unloading`);
|
|
5244
|
+
return this.context.bridgeEvent.viewportFree$.pipe(
|
|
5245
|
+
first$1(),
|
|
5246
|
+
tap$1(() => {
|
|
5247
|
+
this.hookManager.destroy(`item.onDocumentLoad`, this.item.id);
|
|
5248
|
+
}),
|
|
5249
|
+
switchMap(() => {
|
|
5250
|
+
const unload$ = this.onUnload().pipe(endWith(null), first$1());
|
|
5251
|
+
return unload$;
|
|
5252
|
+
}),
|
|
5253
|
+
tap$1(() => {
|
|
5254
|
+
this.stateSubject.next(`idle`);
|
|
5255
|
+
}),
|
|
5256
|
+
takeUntil(merge(this.destroy$, this.load$))
|
|
5257
|
+
);
|
|
5258
|
+
})
|
|
5259
|
+
).subscribe();
|
|
5182
5260
|
}
|
|
5183
|
-
get(
|
|
5184
|
-
|
|
5185
|
-
return this.orderedSpineItemsSubject.value[indexOrId];
|
|
5186
|
-
}
|
|
5187
|
-
if (typeof indexOrId === `string`) {
|
|
5188
|
-
return this.orderedSpineItemsSubject.value.find(
|
|
5189
|
-
({ item }) => item.id === indexOrId
|
|
5190
|
-
);
|
|
5191
|
-
}
|
|
5192
|
-
return indexOrId;
|
|
5261
|
+
get state$() {
|
|
5262
|
+
return this.stateSubject;
|
|
5193
5263
|
}
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
const withIndex = this.getSpineItemIndex(withItem) ?? 0;
|
|
5197
|
-
return toCompareIndex > withIndex ? `after` : toCompareIndex === withIndex ? `same` : `before`;
|
|
5264
|
+
load() {
|
|
5265
|
+
this.triggerSubject.next(`load`);
|
|
5198
5266
|
}
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
const index = this.orderedSpineItemsSubject.value.indexOf(spineItem);
|
|
5202
|
-
return index < 0 ? void 0 : index;
|
|
5267
|
+
unload() {
|
|
5268
|
+
this.triggerSubject.next(`unload`);
|
|
5203
5269
|
}
|
|
5204
|
-
|
|
5205
|
-
this.
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
]);
|
|
5270
|
+
destroy() {
|
|
5271
|
+
this.triggerSubject.next(`destroy`);
|
|
5272
|
+
this.triggerSubject.complete();
|
|
5273
|
+
this.stateSubject.complete();
|
|
5209
5274
|
}
|
|
5210
|
-
|
|
5211
|
-
getSpineItemFromCfi(cfi) {
|
|
5212
|
-
const { itemId } = extractProseMetadataFromCfi(cfi);
|
|
5213
|
-
if (itemId) {
|
|
5214
|
-
const { itemId: itemId2 } = extractProseMetadataFromCfi(cfi);
|
|
5215
|
-
const spineItem = (itemId2 ? this.get(itemId2) : void 0) || this.get(0);
|
|
5216
|
-
return spineItem;
|
|
5217
|
-
}
|
|
5275
|
+
get writingMode() {
|
|
5218
5276
|
return void 0;
|
|
5219
5277
|
}
|
|
5220
|
-
get
|
|
5221
|
-
return
|
|
5278
|
+
get readingDirection() {
|
|
5279
|
+
return void 0;
|
|
5222
5280
|
}
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5281
|
+
}
|
|
5282
|
+
class DefaultRenderer extends DocumentRenderer {
|
|
5283
|
+
onUnload() {
|
|
5284
|
+
return EMPTY;
|
|
5285
|
+
}
|
|
5286
|
+
onCreateDocument() {
|
|
5287
|
+
return EMPTY;
|
|
5288
|
+
}
|
|
5289
|
+
onLoadDocument() {
|
|
5290
|
+
return EMPTY;
|
|
5291
|
+
}
|
|
5292
|
+
layout() {
|
|
5293
|
+
return void 0;
|
|
5228
5294
|
}
|
|
5229
5295
|
}
|
|
5230
|
-
const
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
}) => {
|
|
5236
|
-
const spineItem = spineItemsManager.items.find((item) => {
|
|
5237
|
-
const { left, right, bottom, top } = spineLayout.getAbsolutePositionOf(item);
|
|
5238
|
-
const isWithinXAxis = position.x >= left && position.x < right;
|
|
5239
|
-
if (settings.values.computedPageTurnDirection === `horizontal`) {
|
|
5240
|
-
return isWithinXAxis;
|
|
5241
|
-
} else {
|
|
5242
|
-
return isWithinXAxis && position.y >= top && position.y < bottom;
|
|
5243
|
-
}
|
|
5244
|
-
});
|
|
5245
|
-
if (position.x === 0 && !spineItem) {
|
|
5246
|
-
return spineItemsManager.items[0];
|
|
5296
|
+
const defaultGetResource = (item) => new URL(item.href);
|
|
5297
|
+
class ResourceHandler {
|
|
5298
|
+
constructor(item, settings) {
|
|
5299
|
+
this.item = item;
|
|
5300
|
+
this.settings = settings;
|
|
5247
5301
|
}
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
const
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
visibleHeightOfItem,
|
|
5255
|
-
threshold
|
|
5256
|
-
}) => {
|
|
5257
|
-
const visibleWidthRatioOfSpineItem = visibleWidthOfItem / itemWidth;
|
|
5258
|
-
const visibleHeightRatioOfSpineItem = visibleHeightOfItem / itemHeight;
|
|
5259
|
-
const isItemVisibleEnough = visibleWidthRatioOfSpineItem >= threshold && visibleHeightRatioOfSpineItem >= threshold;
|
|
5260
|
-
return isItemVisibleEnough;
|
|
5261
|
-
};
|
|
5262
|
-
const isItemVisibleOnScreenByThresholdForPosition = ({
|
|
5263
|
-
visibleWidthOfItem,
|
|
5264
|
-
visibleHeightOfItem,
|
|
5265
|
-
threshold,
|
|
5266
|
-
context
|
|
5267
|
-
}) => {
|
|
5268
|
-
const widthRatioOfSpaceTakenInScreen = visibleWidthOfItem / context.state.visibleAreaRect.width;
|
|
5269
|
-
const heightRatioOfSpaceTakenInScreen = visibleHeightOfItem / context.state.visibleAreaRect.height;
|
|
5270
|
-
const isItemVisibleEnoughOnScreen = heightRatioOfSpaceTakenInScreen >= threshold && widthRatioOfSpaceTakenInScreen >= threshold;
|
|
5271
|
-
return isItemVisibleEnoughOnScreen;
|
|
5272
|
-
};
|
|
5273
|
-
const getItemVisibilityForPosition = ({
|
|
5274
|
-
itemPosition: {
|
|
5275
|
-
bottom,
|
|
5276
|
-
left,
|
|
5277
|
-
right,
|
|
5278
|
-
top,
|
|
5279
|
-
width: itemWidth,
|
|
5280
|
-
height: itemHeight
|
|
5281
|
-
},
|
|
5282
|
-
threshold,
|
|
5283
|
-
viewportPosition,
|
|
5284
|
-
restrictToScreen,
|
|
5285
|
-
context
|
|
5286
|
-
}) => {
|
|
5287
|
-
const viewportLeft = viewportPosition.x;
|
|
5288
|
-
const viewportRight = viewportPosition.x + (context.state.visibleAreaRect.width - 1);
|
|
5289
|
-
const viewportTop = viewportPosition.y;
|
|
5290
|
-
const viewportBottom = Math.max(
|
|
5291
|
-
viewportPosition.y + (context.state.visibleAreaRect.height - 1),
|
|
5292
|
-
0
|
|
5293
|
-
);
|
|
5294
|
-
const visibleWidthOfItem = Math.max(
|
|
5295
|
-
0,
|
|
5296
|
-
Math.min(right, viewportRight) - Math.max(left, viewportLeft)
|
|
5297
|
-
);
|
|
5298
|
-
const visibleHeightOfItem = Math.max(
|
|
5299
|
-
0,
|
|
5300
|
-
Math.min(bottom, viewportBottom) - Math.max(top, viewportTop)
|
|
5301
|
-
);
|
|
5302
|
-
const itemIsOnTheOuterEdge = visibleWidthOfItem <= 0 || visibleHeightOfItem <= 0;
|
|
5303
|
-
if (itemIsOnTheOuterEdge) return { visible: false };
|
|
5304
|
-
const isItemVisibleEnoughOnScreen = isItemVisibleOnScreenByThresholdForPosition({
|
|
5305
|
-
threshold,
|
|
5306
|
-
visibleHeightOfItem,
|
|
5307
|
-
visibleWidthOfItem,
|
|
5308
|
-
context
|
|
5309
|
-
});
|
|
5310
|
-
if (restrictToScreen) {
|
|
5311
|
-
return { visible: isItemVisibleEnoughOnScreen };
|
|
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);
|
|
5312
5308
|
}
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
}) || spineItemsManager.get(0);
|
|
5339
|
-
const spineItemsVisible = spineItemsManager.items.reduce(
|
|
5340
|
-
(acc, spineItem) => {
|
|
5341
|
-
const itemPosition = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5342
|
-
const { visible } = getItemVisibilityForPosition({
|
|
5343
|
-
itemPosition,
|
|
5344
|
-
threshold,
|
|
5345
|
-
viewportPosition: position,
|
|
5346
|
-
restrictToScreen,
|
|
5347
|
-
context
|
|
5348
|
-
});
|
|
5349
|
-
if (visible) {
|
|
5350
|
-
return [...acc, spineItem];
|
|
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;
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5316
|
+
class SpineItem {
|
|
5317
|
+
constructor(item, parentElement, context, settings, hookManager, index) {
|
|
5318
|
+
var _a, _b;
|
|
5319
|
+
this.item = item;
|
|
5320
|
+
this.parentElement = parentElement;
|
|
5321
|
+
this.context = context;
|
|
5322
|
+
this.settings = settings;
|
|
5323
|
+
this.hookManager = hookManager;
|
|
5324
|
+
this.index = index;
|
|
5325
|
+
this.adjustPositionOfElement = ({
|
|
5326
|
+
right,
|
|
5327
|
+
left,
|
|
5328
|
+
top
|
|
5329
|
+
}) => {
|
|
5330
|
+
if (right !== void 0) {
|
|
5331
|
+
this.containerElement.style.right = `${right}px`;
|
|
5332
|
+
} else {
|
|
5333
|
+
this.containerElement.style.removeProperty(`right`);
|
|
5351
5334
|
}
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
return {
|
|
5362
|
-
beginIndex: beginItemIndex ?? 0,
|
|
5363
|
-
endIndex: endItemIndex ?? 0
|
|
5364
|
-
};
|
|
5365
|
-
};
|
|
5366
|
-
const getSpinePositionFromSpineItemPosition = ({
|
|
5367
|
-
spineItemPosition,
|
|
5368
|
-
itemLayout: { left, top }
|
|
5369
|
-
}) => {
|
|
5370
|
-
return {
|
|
5371
|
-
x: left + spineItemPosition.x,
|
|
5372
|
-
y: top + spineItemPosition.y
|
|
5373
|
-
};
|
|
5374
|
-
};
|
|
5375
|
-
const getSpineInfoFromAbsolutePageIndex = ({
|
|
5376
|
-
absolutePageIndex,
|
|
5377
|
-
spineLayout,
|
|
5378
|
-
spineItemsManager,
|
|
5379
|
-
context,
|
|
5380
|
-
settings
|
|
5381
|
-
}) => {
|
|
5382
|
-
const items = spineItemsManager.items;
|
|
5383
|
-
const { found, currentAbsolutePage } = items.reduce(
|
|
5384
|
-
(acc, item) => {
|
|
5385
|
-
if (acc.found) return acc;
|
|
5386
|
-
const itemLayout = spineLayout.getAbsolutePositionOf(item);
|
|
5387
|
-
const numberOfPages = getSpineItemNumberOfPages({
|
|
5388
|
-
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
5389
|
-
itemHeight: itemLayout.height,
|
|
5390
|
-
itemWidth: itemLayout.width,
|
|
5391
|
-
context,
|
|
5392
|
-
settings
|
|
5393
|
-
});
|
|
5394
|
-
const possiblePageIndex = absolutePageIndex - acc.currentAbsolutePage;
|
|
5395
|
-
const currentAbsolutePage2 = acc.currentAbsolutePage + numberOfPages;
|
|
5396
|
-
if (possiblePageIndex <= numberOfPages - 1) {
|
|
5397
|
-
return {
|
|
5398
|
-
...acc,
|
|
5399
|
-
currentAbsolutePage: currentAbsolutePage2,
|
|
5400
|
-
found: { item, pageIndex: possiblePageIndex }
|
|
5401
|
-
};
|
|
5335
|
+
if (left !== void 0) {
|
|
5336
|
+
this.containerElement.style.left = `${left}px`;
|
|
5337
|
+
} else {
|
|
5338
|
+
this.containerElement.style.removeProperty(`left`);
|
|
5339
|
+
}
|
|
5340
|
+
if (top !== void 0) {
|
|
5341
|
+
this.containerElement.style.top = `${top}px`;
|
|
5342
|
+
} else {
|
|
5343
|
+
this.containerElement.style.removeProperty(`top`);
|
|
5402
5344
|
}
|
|
5403
|
-
return {
|
|
5404
|
-
...acc,
|
|
5405
|
-
currentAbsolutePage: currentAbsolutePage2
|
|
5406
|
-
};
|
|
5407
|
-
},
|
|
5408
|
-
{ currentAbsolutePage: 0 }
|
|
5409
|
-
);
|
|
5410
|
-
if (found) {
|
|
5411
|
-
return {
|
|
5412
|
-
spineItem: found.item,
|
|
5413
|
-
pageIndex: found.pageIndex,
|
|
5414
|
-
itemIndex: spineItemsManager.getSpineItemIndex(found.item) ?? 0,
|
|
5415
|
-
currentAbsolutePage
|
|
5416
5345
|
};
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
spineLayout,
|
|
5424
|
-
spineItemsManager,
|
|
5425
|
-
context,
|
|
5426
|
-
settings
|
|
5427
|
-
}) => {
|
|
5428
|
-
const items = spineItemsManager.items;
|
|
5429
|
-
const spineItem = spineItemsManager.get(spineItemOrId);
|
|
5430
|
-
if (!spineItem) return void 0;
|
|
5431
|
-
const { currentAbsolutePage } = items.reduce(
|
|
5432
|
-
(acc, item) => {
|
|
5433
|
-
if (acc.found) return acc;
|
|
5434
|
-
const itemLayout = spineLayout.getAbsolutePositionOf(item);
|
|
5435
|
-
const numberOfPages = getSpineItemNumberOfPages({
|
|
5436
|
-
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
5437
|
-
itemHeight: itemLayout.height,
|
|
5438
|
-
itemWidth: itemLayout.width,
|
|
5439
|
-
context,
|
|
5440
|
-
settings
|
|
5441
|
-
});
|
|
5442
|
-
if (spineItem === item) {
|
|
5443
|
-
if (pageIndex <= numberOfPages - 1) {
|
|
5444
|
-
return {
|
|
5445
|
-
currentAbsolutePage: acc.currentAbsolutePage + pageIndex,
|
|
5446
|
-
found: true
|
|
5447
|
-
};
|
|
5346
|
+
this.getBoundingRectOfElementFromSelector = (selector) => {
|
|
5347
|
+
var _a2, _b2, _c, _d, _e;
|
|
5348
|
+
const frameElement = (_a2 = this.renderer.layers[0]) == null ? void 0 : _a2.element;
|
|
5349
|
+
if (frameElement && frameElement instanceof HTMLIFrameElement && selector) {
|
|
5350
|
+
if (selector.startsWith(`#`)) {
|
|
5351
|
+
return (_c = (_b2 = frameElement.contentDocument) == null ? void 0 : _b2.getElementById(selector.replace(`#`, ``))) == null ? void 0 : _c.getBoundingClientRect();
|
|
5448
5352
|
}
|
|
5353
|
+
return (_e = (_d = frameElement.contentDocument) == null ? void 0 : _d.querySelector(selector)) == null ? void 0 : _e.getBoundingClientRect();
|
|
5449
5354
|
}
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
spineItemsManager,
|
|
5461
|
-
context,
|
|
5462
|
-
spineItemLocator,
|
|
5463
|
-
settings,
|
|
5464
|
-
spineLayout
|
|
5465
|
-
}) => {
|
|
5466
|
-
const getSpineItemPositionFromSpinePosition = Report.measurePerformance(
|
|
5467
|
-
`getSpineItemPositionFromSpinePosition`,
|
|
5468
|
-
10,
|
|
5469
|
-
(position, spineItem) => {
|
|
5470
|
-
const { left, top } = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5471
|
-
return {
|
|
5472
|
-
/**
|
|
5473
|
-
* when using spread the item could be on the right and therefore will be negative
|
|
5474
|
-
* @example
|
|
5475
|
-
* 400 (position = viewport), page of 200
|
|
5476
|
-
* 400 - 600 = -200.
|
|
5477
|
-
* However we can assume we are at 0, because we in fact can see the beginning of the item
|
|
5478
|
-
*/
|
|
5479
|
-
x: Math.max(position.x - left, 0),
|
|
5480
|
-
y: Math.max(position.y - top, 0)
|
|
5481
|
-
};
|
|
5482
|
-
},
|
|
5483
|
-
{ disable: true }
|
|
5484
|
-
);
|
|
5485
|
-
const getSpinePositionFromSpineItem = (spineItem) => {
|
|
5486
|
-
return getSpinePositionFromSpineItemPosition({
|
|
5487
|
-
spineItemPosition: { x: 0, y: 0 },
|
|
5488
|
-
itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
|
|
5489
|
-
});
|
|
5490
|
-
};
|
|
5491
|
-
const getSpineItemFromIframe = (iframe) => {
|
|
5492
|
-
return spineItemsManager.items.find((item) => {
|
|
5493
|
-
var _a;
|
|
5494
|
-
return ((_a = item.renderer.layers[0]) == null ? void 0 : _a.element) === iframe;
|
|
5495
|
-
});
|
|
5496
|
-
};
|
|
5497
|
-
const getSpineItemPageIndexFromNode = (node, offset, spineItemOrIndex) => {
|
|
5498
|
-
if (typeof spineItemOrIndex === `number`) {
|
|
5499
|
-
const spineItem = spineItemsManager.get(spineItemOrIndex);
|
|
5500
|
-
return spineItem ? spineItemLocator.getSpineItemPageIndexFromNode(
|
|
5501
|
-
node,
|
|
5502
|
-
offset || 0,
|
|
5503
|
-
spineItem
|
|
5504
|
-
) : void 0;
|
|
5505
|
-
}
|
|
5506
|
-
return spineItemLocator.getSpineItemPageIndexFromNode(
|
|
5507
|
-
node,
|
|
5508
|
-
offset || 0,
|
|
5509
|
-
spineItemOrIndex
|
|
5510
|
-
);
|
|
5511
|
-
};
|
|
5512
|
-
const getVisiblePagesFromViewportPosition = ({
|
|
5513
|
-
position,
|
|
5514
|
-
threshold,
|
|
5515
|
-
spineItem,
|
|
5516
|
-
restrictToScreen
|
|
5517
|
-
}) => {
|
|
5518
|
-
const { height, width } = spineItem.getElementDimensions();
|
|
5519
|
-
const numberOfPages = spineItemLocator.getSpineItemNumberOfPages({
|
|
5520
|
-
isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
|
|
5521
|
-
itemHeight: height,
|
|
5522
|
-
itemWidth: width
|
|
5523
|
-
});
|
|
5524
|
-
const pages = Array.from(Array(numberOfPages)).map((_, index) => {
|
|
5525
|
-
const spineItemPosition = spineItemLocator.getSpineItemPositionFromPageIndex({
|
|
5526
|
-
pageIndex: index,
|
|
5527
|
-
isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
|
|
5528
|
-
itemLayout: spineItem.getElementDimensions()
|
|
5529
|
-
});
|
|
5530
|
-
const spinePosition = getSpinePositionFromSpineItemPosition({
|
|
5531
|
-
spineItemPosition,
|
|
5532
|
-
itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
|
|
5355
|
+
};
|
|
5356
|
+
this.layout = ({
|
|
5357
|
+
blankPagePosition,
|
|
5358
|
+
minimumWidth,
|
|
5359
|
+
spreadPosition
|
|
5360
|
+
}) => {
|
|
5361
|
+
this.hookManager.execute(`item.onBeforeLayout`, void 0, {
|
|
5362
|
+
blankPagePosition,
|
|
5363
|
+
item: this.item,
|
|
5364
|
+
minimumWidth
|
|
5533
5365
|
});
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
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 };
|
|
5381
|
+
};
|
|
5382
|
+
this.load = () => this.renderer.load();
|
|
5383
|
+
this.unload = () => {
|
|
5384
|
+
this.renderer.unload();
|
|
5385
|
+
};
|
|
5386
|
+
this.getElementDimensions = () => {
|
|
5387
|
+
const rect = this.containerElement.getBoundingClientRect();
|
|
5388
|
+
const normalizedValues = {
|
|
5389
|
+
...rect,
|
|
5390
|
+
// we want to round to first decimal because it's possible to have half pixel
|
|
5391
|
+
// however browser engine can also gives back x.yyyy based on their precision
|
|
5392
|
+
width: Math.round(rect.width * 10) / 10,
|
|
5393
|
+
height: Math.round(rect.height * 10) / 10
|
|
5544
5394
|
};
|
|
5545
|
-
|
|
5546
|
-
const pagesVisible = pages.reduce(
|
|
5547
|
-
(acc, { absolutePosition, index }) => {
|
|
5548
|
-
const { visible } = getItemVisibilityForPosition({
|
|
5549
|
-
context,
|
|
5550
|
-
viewportPosition: position,
|
|
5551
|
-
restrictToScreen,
|
|
5552
|
-
threshold,
|
|
5553
|
-
itemPosition: absolutePosition
|
|
5554
|
-
});
|
|
5555
|
-
if (visible) {
|
|
5556
|
-
return [...acc, index];
|
|
5557
|
-
}
|
|
5558
|
-
return acc;
|
|
5559
|
-
},
|
|
5560
|
-
[]
|
|
5561
|
-
);
|
|
5562
|
-
const beginPageIndex = pagesVisible[0];
|
|
5563
|
-
const endPageIndex = pagesVisible[pagesVisible.length - 1] ?? beginPageIndex;
|
|
5564
|
-
if (beginPageIndex === void 0 || endPageIndex === void 0)
|
|
5565
|
-
return void 0;
|
|
5566
|
-
return {
|
|
5567
|
-
beginPageIndex,
|
|
5568
|
-
endPageIndex
|
|
5395
|
+
return normalizedValues;
|
|
5569
5396
|
};
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
const getSafeSpineItemPositionFromUnsafeSpineItemPosition = (unsafePosition, spineItem) => {
|
|
5576
|
-
const { height, width } = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5577
|
-
return {
|
|
5578
|
-
x: Math.min(Math.max(0, unsafePosition.x), width),
|
|
5579
|
-
y: Math.min(Math.max(0, unsafePosition.y), height)
|
|
5397
|
+
this.destroy = () => {
|
|
5398
|
+
this.destroySubject$.next();
|
|
5399
|
+
this.containerElement.remove();
|
|
5400
|
+
this.destroySubject$.complete();
|
|
5401
|
+
this.renderer.destroy();
|
|
5580
5402
|
};
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
context,
|
|
5596
|
-
settings,
|
|
5597
|
-
spineItemsManager,
|
|
5598
|
-
spineLayout
|
|
5599
|
-
}),
|
|
5600
|
-
getSpineInfoFromAbsolutePageIndex: (params) => getSpineInfoFromAbsolutePageIndex({
|
|
5601
|
-
...params,
|
|
5602
|
-
context,
|
|
5603
|
-
settings,
|
|
5604
|
-
spineItemsManager,
|
|
5605
|
-
spineLayout
|
|
5606
|
-
}),
|
|
5607
|
-
getSpinePositionFromSpineItem,
|
|
5608
|
-
getSpineItemPositionFromSpinePosition,
|
|
5609
|
-
getSpineItemFromPosition: (position) => getSpineItemFromPosition({
|
|
5610
|
-
position,
|
|
5611
|
-
settings,
|
|
5612
|
-
spineItemsManager,
|
|
5613
|
-
spineLayout
|
|
5614
|
-
}),
|
|
5615
|
-
getSpineItemFromIframe,
|
|
5616
|
-
getSpineItemPageIndexFromNode,
|
|
5617
|
-
getVisibleSpineItemsFromPosition: (params) => getVisibleSpineItemsFromPosition({
|
|
5403
|
+
this.isUsingVerticalWriting = () => {
|
|
5404
|
+
var _a2;
|
|
5405
|
+
return !!((_a2 = this.renderer.writingMode) == null ? void 0 : _a2.startsWith(`vertical`));
|
|
5406
|
+
};
|
|
5407
|
+
this.destroySubject$ = new Subject();
|
|
5408
|
+
this.containerElement = createContainerElement(
|
|
5409
|
+
parentElement,
|
|
5410
|
+
item,
|
|
5411
|
+
hookManager
|
|
5412
|
+
);
|
|
5413
|
+
parentElement.appendChild(this.containerElement);
|
|
5414
|
+
const rendererFactory = (_b = (_a = this.settings.values).getRenderer) == null ? void 0 : _b.call(_a, item);
|
|
5415
|
+
this.resourcesHandler = new ResourceHandler(item, this.settings);
|
|
5416
|
+
const rendererParams = {
|
|
5618
5417
|
context,
|
|
5619
5418
|
settings,
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
};
|
|
5630
|
-
const loadItems = ({
|
|
5631
|
-
spineItemsManager,
|
|
5632
|
-
settings
|
|
5633
|
-
}) => (stream) => stream.pipe(
|
|
5634
|
-
tap$1(([beginIndex, endIndex]) => {
|
|
5635
|
-
const { numberOfAdjacentSpineItemToPreLoad } = settings.values;
|
|
5636
|
-
const leftMaximumIndex = beginIndex - numberOfAdjacentSpineItemToPreLoad;
|
|
5637
|
-
const rightMaximumIndex = endIndex + numberOfAdjacentSpineItemToPreLoad;
|
|
5638
|
-
spineItemsManager.items.forEach((orderedSpineItem, index) => {
|
|
5639
|
-
const isWithinRange = index >= leftMaximumIndex && index <= rightMaximumIndex;
|
|
5640
|
-
if (isWithinRange) {
|
|
5641
|
-
orderedSpineItem.load();
|
|
5642
|
-
} else {
|
|
5643
|
-
orderedSpineItem.unload();
|
|
5644
|
-
}
|
|
5645
|
-
});
|
|
5646
|
-
})
|
|
5647
|
-
);
|
|
5648
|
-
const mapToItemsToLoad = ({ spineLocator }) => (stream) => stream.pipe(
|
|
5649
|
-
map$1((position) => {
|
|
5650
|
-
const { beginIndex = 0, endIndex = 0 } = spineLocator.getVisibleSpineItemsFromPosition({
|
|
5651
|
-
position,
|
|
5652
|
-
threshold: 0
|
|
5653
|
-
}) || {};
|
|
5654
|
-
return [beginIndex, endIndex];
|
|
5655
|
-
})
|
|
5656
|
-
);
|
|
5657
|
-
class SpineItemsLoader extends DestroyableClass {
|
|
5658
|
-
constructor(context, spineItemsManager, spineLocator, settings, spineLayout) {
|
|
5659
|
-
super();
|
|
5660
|
-
this.context = context;
|
|
5661
|
-
this.spineItemsManager = spineItemsManager;
|
|
5662
|
-
this.spineLocator = spineLocator;
|
|
5663
|
-
this.settings = settings;
|
|
5664
|
-
this.spineLayout = spineLayout;
|
|
5665
|
-
const navigationUpdate$ = this.context.bridgeEvent.navigation$;
|
|
5666
|
-
const layoutHasChanged$ = this.spineLayout.layout$.pipe(
|
|
5667
|
-
filter$1(({ hasChanged }) => hasChanged)
|
|
5419
|
+
hookManager,
|
|
5420
|
+
item,
|
|
5421
|
+
containerElement: this.containerElement,
|
|
5422
|
+
resourcesHandler: this.resourcesHandler
|
|
5423
|
+
};
|
|
5424
|
+
this.renderer = rendererFactory ? rendererFactory(rendererParams) : new DefaultRenderer(rendererParams);
|
|
5425
|
+
const contentLayoutChange$ = merge(
|
|
5426
|
+
this.unloaded$.pipe(map(() => ({ isFirstLayout: false }))),
|
|
5427
|
+
this.ready$.pipe(map(() => ({ isFirstLayout: true })))
|
|
5668
5428
|
);
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5429
|
+
this.contentLayout$ = contentLayoutChange$.pipe(
|
|
5430
|
+
withLatestFrom$1(this.isReady$),
|
|
5431
|
+
map(([data, isReady]) => ({
|
|
5432
|
+
isFirstLayout: data.isFirstLayout,
|
|
5433
|
+
isReady
|
|
5434
|
+
}))
|
|
5675
5435
|
);
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5436
|
+
}
|
|
5437
|
+
get element() {
|
|
5438
|
+
return this.containerElement;
|
|
5439
|
+
}
|
|
5440
|
+
/**
|
|
5441
|
+
* @important
|
|
5442
|
+
* Do not use this value for layout and navigation. It will be in possible conflict
|
|
5443
|
+
* with the global reading direction. A book should not mix them anyway. A page can have
|
|
5444
|
+
* a different reading direction for style reason but it should be in theory pre-paginated.
|
|
5445
|
+
* For example an english page in a japanese manga. That's expected and will
|
|
5446
|
+
* be confined to a single page.
|
|
5447
|
+
*/
|
|
5448
|
+
get readingDirection() {
|
|
5449
|
+
return this.renderer.readingDirection;
|
|
5450
|
+
}
|
|
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")
|
|
5690
5458
|
);
|
|
5691
|
-
loadSpineItems$.pipe(takeUntil(this.destroy$)).subscribe();
|
|
5692
5459
|
}
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
this.spineItemsManager = spineItemsManager;
|
|
5698
|
-
this.spineLocator = spineLocator;
|
|
5699
|
-
this.itemIsReady$ = this.spineItemsManager.items$.pipe(
|
|
5700
|
-
switchMap((items) => {
|
|
5701
|
-
const itemsIsReady$ = items.map(
|
|
5702
|
-
(item) => item.isReady$.pipe(map$1((isReady) => ({ item, isReady })))
|
|
5703
|
-
);
|
|
5704
|
-
return merge(...itemsIsReady$);
|
|
5705
|
-
}),
|
|
5706
|
-
share()
|
|
5460
|
+
get loaded$() {
|
|
5461
|
+
return this.renderer.state$.pipe(
|
|
5462
|
+
distinctUntilChanged(),
|
|
5463
|
+
filter((state) => state === "loaded")
|
|
5707
5464
|
);
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
)
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
this.itemLoaded$ = this.spineItemsManager.items$.pipe(
|
|
5720
|
-
switchMap((items) => {
|
|
5721
|
-
const itemsIsReady$ = items.map(
|
|
5722
|
-
(item) => item.loaded$.pipe(map$1(() => item))
|
|
5723
|
-
);
|
|
5724
|
-
return merge(...itemsIsReady$);
|
|
5725
|
-
})
|
|
5465
|
+
}
|
|
5466
|
+
get unloaded$() {
|
|
5467
|
+
return this.renderer.state$.pipe(
|
|
5468
|
+
distinctUntilChanged(),
|
|
5469
|
+
filter((state) => state !== "idle"),
|
|
5470
|
+
switchMap$1(
|
|
5471
|
+
() => this.renderer.state$.pipe(
|
|
5472
|
+
filter((state) => state === `idle`),
|
|
5473
|
+
first()
|
|
5474
|
+
)
|
|
5475
|
+
)
|
|
5726
5476
|
);
|
|
5727
5477
|
}
|
|
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
|
+
}
|
|
5728
5494
|
}
|
|
5729
|
-
const
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
})
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
height: pageSize.height,
|
|
5740
|
-
bottom: position.y + pageSize.height,
|
|
5741
|
-
right: position.x + pageSize.width
|
|
5742
|
-
};
|
|
5495
|
+
const createContainerElement = (containerElement, item, hookManager) => {
|
|
5496
|
+
const element = containerElement.ownerDocument.createElement(`div`);
|
|
5497
|
+
element.classList.add(`spineItem`);
|
|
5498
|
+
element.classList.add(`spineItem-${item.renditionLayout}`);
|
|
5499
|
+
element.style.cssText = `
|
|
5500
|
+
position: absolute;
|
|
5501
|
+
overflow: hidden;
|
|
5502
|
+
`;
|
|
5503
|
+
hookManager.execute("item.onBeforeContainerCreated", void 0, { element });
|
|
5504
|
+
return element;
|
|
5743
5505
|
};
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
constructor(spineItemsManager, context, settings) {
|
|
5506
|
+
class SpineItemsManager extends DestroyableClass {
|
|
5507
|
+
constructor(context, settings) {
|
|
5747
5508
|
super();
|
|
5748
|
-
this.spineItemsManager = spineItemsManager;
|
|
5749
5509
|
this.context = context;
|
|
5750
5510
|
this.settings = settings;
|
|
5751
|
-
this.
|
|
5752
|
-
this.
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
settings
|
|
5793
|
-
});
|
|
5794
|
-
const pages2 = new Array(numberOfPages).fill(void 0);
|
|
5795
|
-
return pages2.map(
|
|
5796
|
-
(_, pageIndex) => convertSpinePositionToLayoutPosition({
|
|
5797
|
-
pageSize: this.context.getPageSize(),
|
|
5798
|
-
position: getSpinePositionFromSpineItemPosition({
|
|
5799
|
-
itemLayout,
|
|
5800
|
-
spineItemPosition: getSpineItemPositionFromPageIndex({
|
|
5801
|
-
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
5802
|
-
itemLayout,
|
|
5803
|
-
pageIndex,
|
|
5804
|
-
context
|
|
5805
|
-
})
|
|
5806
|
-
})
|
|
5807
|
-
})
|
|
5808
|
-
);
|
|
5809
|
-
});
|
|
5810
|
-
const pages = spineItemsPagesAbsolutePositions.reduce(
|
|
5811
|
-
(acc, itemPages, itemIndex) => {
|
|
5812
|
-
const itemPagesInfo = itemPages.map(
|
|
5813
|
-
(absolutePosition, pageIndex) => ({
|
|
5814
|
-
itemIndex,
|
|
5815
|
-
absolutePageIndex: itemIndex + pageIndex,
|
|
5816
|
-
absolutePosition
|
|
5817
|
-
})
|
|
5818
|
-
);
|
|
5819
|
-
return [...acc, ...itemPagesInfo];
|
|
5820
|
-
},
|
|
5821
|
-
[]
|
|
5822
|
-
);
|
|
5823
|
-
return {
|
|
5824
|
-
hasChanged,
|
|
5825
|
-
spineItemsAbsolutePositions: items.map(
|
|
5826
|
-
(item) => this.getAbsolutePositionOf(item)
|
|
5827
|
-
),
|
|
5828
|
-
spineItemsPagesAbsolutePositions,
|
|
5829
|
-
pages
|
|
5830
|
-
};
|
|
5831
|
-
}),
|
|
5832
|
-
shareReplay$1(1)
|
|
5833
|
-
);
|
|
5511
|
+
this.orderedSpineItemsSubject = new BehaviorSubject([]);
|
|
5512
|
+
this.items$ = this.orderedSpineItemsSubject.asObservable();
|
|
5513
|
+
}
|
|
5514
|
+
get(indexOrId) {
|
|
5515
|
+
if (typeof indexOrId === `number`) {
|
|
5516
|
+
return this.orderedSpineItemsSubject.value[indexOrId];
|
|
5517
|
+
}
|
|
5518
|
+
if (typeof indexOrId === `string`) {
|
|
5519
|
+
return this.orderedSpineItemsSubject.value.find(
|
|
5520
|
+
({ item }) => item.id === indexOrId
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5523
|
+
return indexOrId;
|
|
5524
|
+
}
|
|
5525
|
+
comparePositionOf(toCompare, withItem) {
|
|
5526
|
+
const toCompareIndex = this.getSpineItemIndex(toCompare) ?? 0;
|
|
5527
|
+
const withIndex = this.getSpineItemIndex(withItem) ?? 0;
|
|
5528
|
+
return toCompareIndex > withIndex ? `after` : toCompareIndex === withIndex ? `same` : `before`;
|
|
5529
|
+
}
|
|
5530
|
+
getSpineItemIndex(spineItemOrId) {
|
|
5531
|
+
const spineItem = spineItemOrId instanceof SpineItem ? spineItemOrId : this.get(spineItemOrId);
|
|
5532
|
+
if (!spineItem) return void 0;
|
|
5533
|
+
const index = this.orderedSpineItemsSubject.value.indexOf(spineItem);
|
|
5534
|
+
return index < 0 ? void 0 : index;
|
|
5535
|
+
}
|
|
5536
|
+
addMany(spineItems) {
|
|
5537
|
+
this.orderedSpineItemsSubject.next([
|
|
5538
|
+
...this.orderedSpineItemsSubject.getValue(),
|
|
5539
|
+
...spineItems
|
|
5540
|
+
]);
|
|
5541
|
+
}
|
|
5542
|
+
// @todo move
|
|
5543
|
+
getSpineItemFromCfi(cfi) {
|
|
5544
|
+
const { itemIndex } = parseCfi(cfi);
|
|
5545
|
+
if (itemIndex !== void 0) {
|
|
5546
|
+
return this.get(itemIndex);
|
|
5547
|
+
}
|
|
5548
|
+
return void 0;
|
|
5549
|
+
}
|
|
5550
|
+
get items() {
|
|
5551
|
+
return this.orderedSpineItemsSubject.value;
|
|
5834
5552
|
}
|
|
5835
5553
|
/**
|
|
5836
|
-
* @todo
|
|
5837
|
-
* move this logic to the spine
|
|
5838
|
-
*
|
|
5839
|
-
* @todo
|
|
5840
|
-
* make sure to check how many times it is being called and try to reduce number of layouts
|
|
5841
|
-
* it is called eery time an item is being unload (which can adds up quickly for big books)
|
|
5554
|
+
* @todo handle reload, remove subscription to each items etc. See add()
|
|
5842
5555
|
*/
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
const newItemLayoutInformation = [];
|
|
5846
|
-
const isGloballyPrePaginated = (manifest == null ? void 0 : manifest.renditionLayout) === `pre-paginated`;
|
|
5847
|
-
this.spineItemsManager.items.reduce(
|
|
5848
|
-
({ horizontalOffset, verticalOffset }, item, index) => {
|
|
5849
|
-
let minimumWidth = this.context.getPageSize().width;
|
|
5850
|
-
let blankPagePosition = `none`;
|
|
5851
|
-
const itemStartOnNewScreen = horizontalOffset % this.context.state.visibleAreaRect.width === 0;
|
|
5852
|
-
const isLastItem = index === this.spineItemsManager.items.length - 1;
|
|
5853
|
-
if (this.context.state.isUsingSpreadMode) {
|
|
5854
|
-
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && !isLastItem) {
|
|
5855
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
5856
|
-
}
|
|
5857
|
-
if (!isGloballyPrePaginated && item.item.renditionLayout === `reflowable` && isLastItem && itemStartOnNewScreen) {
|
|
5858
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
5859
|
-
}
|
|
5860
|
-
const lastItemStartOnNewScreenInAPrepaginatedBook = itemStartOnNewScreen && isLastItem && isGloballyPrePaginated;
|
|
5861
|
-
if (item.item.pageSpreadRight && itemStartOnNewScreen && !this.context.isRTL()) {
|
|
5862
|
-
blankPagePosition = `before`;
|
|
5863
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
5864
|
-
} else if (item.item.pageSpreadLeft && itemStartOnNewScreen && this.context.isRTL()) {
|
|
5865
|
-
blankPagePosition = `before`;
|
|
5866
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
5867
|
-
} else if (lastItemStartOnNewScreenInAPrepaginatedBook) {
|
|
5868
|
-
if (this.context.isRTL()) {
|
|
5869
|
-
blankPagePosition = `before`;
|
|
5870
|
-
} else {
|
|
5871
|
-
blankPagePosition = `after`;
|
|
5872
|
-
}
|
|
5873
|
-
minimumWidth = this.context.getPageSize().width * 2;
|
|
5874
|
-
}
|
|
5875
|
-
}
|
|
5876
|
-
const { width, height } = item.layout({
|
|
5877
|
-
minimumWidth,
|
|
5878
|
-
blankPagePosition,
|
|
5879
|
-
spreadPosition: this.context.state.isUsingSpreadMode ? itemStartOnNewScreen ? this.context.isRTL() ? `right` : `left` : this.context.isRTL() ? `left` : `right` : `none`
|
|
5880
|
-
});
|
|
5881
|
-
if (this.settings.values.computedPageTurnDirection === `vertical`) {
|
|
5882
|
-
const currentValidEdgeYForVerticalPositioning = itemStartOnNewScreen ? verticalOffset : verticalOffset - this.context.state.visibleAreaRect.height;
|
|
5883
|
-
const currentValidEdgeXForVerticalPositioning = itemStartOnNewScreen ? 0 : horizontalOffset;
|
|
5884
|
-
if (this.context.isRTL()) {
|
|
5885
|
-
item.adjustPositionOfElement({
|
|
5886
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
5887
|
-
left: currentValidEdgeXForVerticalPositioning
|
|
5888
|
-
});
|
|
5889
|
-
} else {
|
|
5890
|
-
item.adjustPositionOfElement({
|
|
5891
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
5892
|
-
left: currentValidEdgeXForVerticalPositioning
|
|
5893
|
-
});
|
|
5894
|
-
}
|
|
5895
|
-
const newEdgeX = width + currentValidEdgeXForVerticalPositioning;
|
|
5896
|
-
const newEdgeY = height + currentValidEdgeYForVerticalPositioning;
|
|
5897
|
-
newItemLayoutInformation.push({
|
|
5898
|
-
left: currentValidEdgeXForVerticalPositioning,
|
|
5899
|
-
right: newEdgeX,
|
|
5900
|
-
top: currentValidEdgeYForVerticalPositioning,
|
|
5901
|
-
bottom: newEdgeY,
|
|
5902
|
-
height,
|
|
5903
|
-
width,
|
|
5904
|
-
x: currentValidEdgeXForVerticalPositioning,
|
|
5905
|
-
y: currentValidEdgeYForVerticalPositioning
|
|
5906
|
-
});
|
|
5907
|
-
return {
|
|
5908
|
-
horizontalOffset: newEdgeX,
|
|
5909
|
-
verticalOffset: newEdgeY
|
|
5910
|
-
};
|
|
5911
|
-
}
|
|
5912
|
-
item.adjustPositionOfElement(
|
|
5913
|
-
this.context.isRTL() ? { right: horizontalOffset, top: 0 } : { left: horizontalOffset, top: 0 }
|
|
5914
|
-
);
|
|
5915
|
-
const left = this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset - width : horizontalOffset;
|
|
5916
|
-
newItemLayoutInformation.push({
|
|
5917
|
-
right: this.context.isRTL() ? this.context.state.visibleAreaRect.width - horizontalOffset : horizontalOffset + width,
|
|
5918
|
-
left,
|
|
5919
|
-
x: left,
|
|
5920
|
-
top: verticalOffset,
|
|
5921
|
-
bottom: height,
|
|
5922
|
-
height,
|
|
5923
|
-
width,
|
|
5924
|
-
y: verticalOffset
|
|
5925
|
-
});
|
|
5926
|
-
return {
|
|
5927
|
-
horizontalOffset: horizontalOffset + width,
|
|
5928
|
-
verticalOffset: 0
|
|
5929
|
-
};
|
|
5930
|
-
},
|
|
5931
|
-
{ horizontalOffset: 0, verticalOffset: 0 }
|
|
5932
|
-
);
|
|
5933
|
-
const hasLayoutChanges = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
|
|
5934
|
-
(old, index) => !isShallowEqual(old, newItemLayoutInformation[index])
|
|
5935
|
-
);
|
|
5936
|
-
this.itemLayoutInformation = newItemLayoutInformation;
|
|
5937
|
-
Report.log(NAMESPACE, `layout`, {
|
|
5938
|
-
hasLayoutChanges,
|
|
5939
|
-
itemLayoutInformation: this.itemLayoutInformation
|
|
5940
|
-
});
|
|
5941
|
-
this.layoutSubject.next(hasLayoutChanges);
|
|
5942
|
-
}
|
|
5943
|
-
/**
|
|
5944
|
-
* It's important to not use x,y since we need the absolute position of each element. Otherwise x,y would be relative to
|
|
5945
|
-
* current window (viewport).
|
|
5946
|
-
*/
|
|
5947
|
-
getAbsolutePositionOf(spineItemOrIndex) {
|
|
5948
|
-
const fallback = {
|
|
5949
|
-
left: 0,
|
|
5950
|
-
right: 0,
|
|
5951
|
-
top: 0,
|
|
5952
|
-
bottom: 0,
|
|
5953
|
-
width: 0,
|
|
5954
|
-
height: 0,
|
|
5955
|
-
x: 0,
|
|
5956
|
-
y: 0
|
|
5957
|
-
};
|
|
5958
|
-
const spineItem = this.spineItemsManager.get(spineItemOrIndex);
|
|
5959
|
-
const indexOfItem = spineItem ? this.spineItemsManager.items.indexOf(spineItem) : -1;
|
|
5960
|
-
const layoutInformation = this.itemLayoutInformation[indexOfItem];
|
|
5961
|
-
return layoutInformation || fallback;
|
|
5962
|
-
}
|
|
5963
|
-
destroy() {
|
|
5964
|
-
super.destroy();
|
|
5965
|
-
this.layoutSubject.complete();
|
|
5966
|
-
}
|
|
5967
|
-
}
|
|
5968
|
-
class DocumentRenderer {
|
|
5969
|
-
constructor(context, settings, hookManager, item, containerElement, resourcesHandler) {
|
|
5970
|
-
this.context = context;
|
|
5971
|
-
this.settings = settings;
|
|
5972
|
-
this.hookManager = hookManager;
|
|
5973
|
-
this.item = item;
|
|
5974
|
-
this.containerElement = containerElement;
|
|
5975
|
-
this.resourcesHandler = resourcesHandler;
|
|
5976
|
-
this.stateSubject = new BehaviorSubject(`idle`);
|
|
5977
|
-
this.triggerSubject = new Subject();
|
|
5978
|
-
this.layers = [];
|
|
5979
|
-
this.unload$ = this.triggerSubject.pipe(
|
|
5980
|
-
withLatestFrom(this.stateSubject),
|
|
5981
|
-
filter$1(
|
|
5982
|
-
([trigger, state]) => trigger === `unload` && state !== "idle" && state !== "unloading"
|
|
5983
|
-
),
|
|
5984
|
-
map$1(() => void 0),
|
|
5985
|
-
share()
|
|
5986
|
-
);
|
|
5987
|
-
this.load$ = this.triggerSubject.pipe(
|
|
5988
|
-
withLatestFrom(this.stateSubject),
|
|
5989
|
-
filter$1(
|
|
5990
|
-
([trigger, state]) => trigger === `load` && state !== "ready" && state !== "loaded" && state !== "loading"
|
|
5991
|
-
),
|
|
5992
|
-
map$1(() => void 0),
|
|
5993
|
-
share()
|
|
5994
|
-
);
|
|
5995
|
-
this.destroy$ = this.triggerSubject.pipe(
|
|
5996
|
-
filter$1((trigger) => trigger === `destroy`)
|
|
5997
|
-
);
|
|
5998
|
-
this.load$.pipe(
|
|
5999
|
-
switchMap(() => {
|
|
6000
|
-
this.stateSubject.next(`loading`);
|
|
6001
|
-
const createDocument$ = this.onCreateDocument().pipe(
|
|
6002
|
-
endWith(null),
|
|
6003
|
-
first$1()
|
|
6004
|
-
);
|
|
6005
|
-
return createDocument$.pipe(
|
|
6006
|
-
tap$1(() => {
|
|
6007
|
-
this.hookManager.execute(`item.onDocumentCreated`, this.item.id, {
|
|
6008
|
-
itemId: this.item.id,
|
|
6009
|
-
layers: this.layers
|
|
6010
|
-
});
|
|
6011
|
-
}),
|
|
6012
|
-
switchMap(() => {
|
|
6013
|
-
const loadDocument$ = this.onLoadDocument().pipe(
|
|
6014
|
-
endWith(null),
|
|
6015
|
-
first$1()
|
|
6016
|
-
);
|
|
6017
|
-
return loadDocument$;
|
|
6018
|
-
}),
|
|
6019
|
-
waitForSwitch(this.context.bridgeEvent.viewportFree$),
|
|
6020
|
-
switchMap(() => {
|
|
6021
|
-
const hookResults = this.hookManager.execute(`item.onDocumentLoad`, this.item.id, {
|
|
6022
|
-
itemId: this.item.id,
|
|
6023
|
-
layers: this.layers
|
|
6024
|
-
}).filter(
|
|
6025
|
-
(result) => result instanceof Observable
|
|
6026
|
-
);
|
|
6027
|
-
return combineLatest([of(null), ...hookResults]).pipe(first$1());
|
|
6028
|
-
}),
|
|
6029
|
-
tap$1(() => {
|
|
6030
|
-
this.stateSubject.next(`loaded`);
|
|
6031
|
-
this.stateSubject.next(`ready`);
|
|
6032
|
-
}),
|
|
6033
|
-
takeUntil(merge(this.destroy$, this.unload$))
|
|
6034
|
-
);
|
|
6035
|
-
})
|
|
6036
|
-
).subscribe();
|
|
6037
|
-
this.unload$.pipe(
|
|
6038
|
-
switchMap(() => {
|
|
6039
|
-
this.stateSubject.next(`unloading`);
|
|
6040
|
-
return this.context.bridgeEvent.viewportFree$.pipe(
|
|
6041
|
-
first$1(),
|
|
6042
|
-
tap$1(() => {
|
|
6043
|
-
this.hookManager.destroy(`item.onDocumentLoad`, this.item.id);
|
|
6044
|
-
}),
|
|
6045
|
-
switchMap(() => {
|
|
6046
|
-
const unload$ = this.onUnload().pipe(endWith(null), first$1());
|
|
6047
|
-
return unload$;
|
|
6048
|
-
}),
|
|
6049
|
-
tap$1(() => {
|
|
6050
|
-
this.stateSubject.next(`idle`);
|
|
6051
|
-
}),
|
|
6052
|
-
takeUntil(merge(this.destroy$, this.load$))
|
|
6053
|
-
);
|
|
6054
|
-
})
|
|
6055
|
-
).subscribe();
|
|
6056
|
-
}
|
|
6057
|
-
get state$() {
|
|
6058
|
-
return this.stateSubject;
|
|
6059
|
-
}
|
|
6060
|
-
load() {
|
|
6061
|
-
this.triggerSubject.next(`load`);
|
|
6062
|
-
}
|
|
6063
|
-
unload() {
|
|
6064
|
-
this.triggerSubject.next(`unload`);
|
|
6065
|
-
}
|
|
6066
|
-
destroy() {
|
|
6067
|
-
this.triggerSubject.next(`destroy`);
|
|
6068
|
-
this.triggerSubject.complete();
|
|
6069
|
-
this.stateSubject.complete();
|
|
6070
|
-
}
|
|
6071
|
-
get writingMode() {
|
|
6072
|
-
return void 0;
|
|
6073
|
-
}
|
|
6074
|
-
get readingDirection() {
|
|
6075
|
-
return void 0;
|
|
5556
|
+
destroyItems() {
|
|
5557
|
+
this.orderedSpineItemsSubject.value.forEach((item) => item.destroy());
|
|
6076
5558
|
}
|
|
6077
5559
|
}
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
5560
|
+
const getSpineItemFromPosition = ({
|
|
5561
|
+
position,
|
|
5562
|
+
spineItemsManager,
|
|
5563
|
+
spineLayout,
|
|
5564
|
+
settings
|
|
5565
|
+
}) => {
|
|
5566
|
+
const spineItem = spineItemsManager.items.find((item) => {
|
|
5567
|
+
const { left, right, bottom, top } = spineLayout.getAbsolutePositionOf(item);
|
|
5568
|
+
const isWithinXAxis = position.x >= left && position.x < right;
|
|
5569
|
+
if (settings.values.computedPageTurnDirection === `horizontal`) {
|
|
5570
|
+
return isWithinXAxis;
|
|
5571
|
+
} else {
|
|
5572
|
+
return isWithinXAxis && position.y >= top && position.y < bottom;
|
|
5573
|
+
}
|
|
5574
|
+
});
|
|
5575
|
+
if (position.x === 0 && !spineItem) {
|
|
5576
|
+
return spineItemsManager.items[0];
|
|
6084
5577
|
}
|
|
6085
|
-
|
|
6086
|
-
|
|
5578
|
+
return spineItem;
|
|
5579
|
+
};
|
|
5580
|
+
const isItemVisibleByThresholdForPosition = ({
|
|
5581
|
+
itemHeight,
|
|
5582
|
+
itemWidth,
|
|
5583
|
+
visibleWidthOfItem,
|
|
5584
|
+
visibleHeightOfItem,
|
|
5585
|
+
threshold
|
|
5586
|
+
}) => {
|
|
5587
|
+
const visibleWidthRatioOfSpineItem = visibleWidthOfItem / itemWidth;
|
|
5588
|
+
const visibleHeightRatioOfSpineItem = visibleHeightOfItem / itemHeight;
|
|
5589
|
+
const isItemVisibleEnough = visibleWidthRatioOfSpineItem >= threshold && visibleHeightRatioOfSpineItem >= threshold;
|
|
5590
|
+
return isItemVisibleEnough;
|
|
5591
|
+
};
|
|
5592
|
+
const isItemVisibleOnScreenByThresholdForPosition = ({
|
|
5593
|
+
visibleWidthOfItem,
|
|
5594
|
+
visibleHeightOfItem,
|
|
5595
|
+
threshold,
|
|
5596
|
+
context
|
|
5597
|
+
}) => {
|
|
5598
|
+
const widthRatioOfSpaceTakenInScreen = visibleWidthOfItem / context.state.visibleAreaRect.width;
|
|
5599
|
+
const heightRatioOfSpaceTakenInScreen = visibleHeightOfItem / context.state.visibleAreaRect.height;
|
|
5600
|
+
const isItemVisibleEnoughOnScreen = heightRatioOfSpaceTakenInScreen >= threshold && widthRatioOfSpaceTakenInScreen >= threshold;
|
|
5601
|
+
return isItemVisibleEnoughOnScreen;
|
|
5602
|
+
};
|
|
5603
|
+
const getItemVisibilityForPosition = ({
|
|
5604
|
+
itemPosition: {
|
|
5605
|
+
bottom,
|
|
5606
|
+
left,
|
|
5607
|
+
right,
|
|
5608
|
+
top,
|
|
5609
|
+
width: itemWidth,
|
|
5610
|
+
height: itemHeight
|
|
5611
|
+
},
|
|
5612
|
+
threshold,
|
|
5613
|
+
viewportPosition,
|
|
5614
|
+
restrictToScreen,
|
|
5615
|
+
context
|
|
5616
|
+
}) => {
|
|
5617
|
+
const viewportLeft = viewportPosition.x;
|
|
5618
|
+
const viewportRight = viewportPosition.x + (context.state.visibleAreaRect.width - 1);
|
|
5619
|
+
const viewportTop = viewportPosition.y;
|
|
5620
|
+
const viewportBottom = Math.max(
|
|
5621
|
+
viewportPosition.y + (context.state.visibleAreaRect.height - 1),
|
|
5622
|
+
0
|
|
5623
|
+
);
|
|
5624
|
+
const visibleWidthOfItem = Math.max(
|
|
5625
|
+
0,
|
|
5626
|
+
Math.min(right, viewportRight) - Math.max(left, viewportLeft)
|
|
5627
|
+
);
|
|
5628
|
+
const visibleHeightOfItem = Math.max(
|
|
5629
|
+
0,
|
|
5630
|
+
Math.min(bottom, viewportBottom) - Math.max(top, viewportTop)
|
|
5631
|
+
);
|
|
5632
|
+
const itemIsOnTheOuterEdge = visibleWidthOfItem <= 0 || visibleHeightOfItem <= 0;
|
|
5633
|
+
if (itemIsOnTheOuterEdge) return { visible: false };
|
|
5634
|
+
const isItemVisibleEnoughOnScreen = isItemVisibleOnScreenByThresholdForPosition({
|
|
5635
|
+
threshold,
|
|
5636
|
+
visibleHeightOfItem,
|
|
5637
|
+
visibleWidthOfItem,
|
|
5638
|
+
context
|
|
5639
|
+
});
|
|
5640
|
+
if (restrictToScreen) {
|
|
5641
|
+
return { visible: isItemVisibleEnoughOnScreen };
|
|
6087
5642
|
}
|
|
6088
|
-
|
|
6089
|
-
|
|
5643
|
+
const isItemVisibleEnough = isItemVisibleByThresholdForPosition({
|
|
5644
|
+
itemHeight,
|
|
5645
|
+
itemWidth,
|
|
5646
|
+
threshold,
|
|
5647
|
+
visibleHeightOfItem,
|
|
5648
|
+
visibleWidthOfItem
|
|
5649
|
+
});
|
|
5650
|
+
return {
|
|
5651
|
+
visible: isItemVisibleEnough || isItemVisibleEnoughOnScreen
|
|
5652
|
+
};
|
|
5653
|
+
};
|
|
5654
|
+
const getVisibleSpineItemsFromPosition = ({
|
|
5655
|
+
position,
|
|
5656
|
+
threshold,
|
|
5657
|
+
restrictToScreen,
|
|
5658
|
+
spineItemsManager,
|
|
5659
|
+
context,
|
|
5660
|
+
settings,
|
|
5661
|
+
spineLayout
|
|
5662
|
+
}) => {
|
|
5663
|
+
const fallbackSpineItem = getSpineItemFromPosition({
|
|
5664
|
+
position,
|
|
5665
|
+
settings,
|
|
5666
|
+
spineItemsManager,
|
|
5667
|
+
spineLayout
|
|
5668
|
+
}) || spineItemsManager.get(0);
|
|
5669
|
+
const spineItemsVisible = spineItemsManager.items.reduce(
|
|
5670
|
+
(acc, spineItem) => {
|
|
5671
|
+
const itemPosition = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5672
|
+
const { visible } = getItemVisibilityForPosition({
|
|
5673
|
+
itemPosition,
|
|
5674
|
+
threshold,
|
|
5675
|
+
viewportPosition: position,
|
|
5676
|
+
restrictToScreen,
|
|
5677
|
+
context
|
|
5678
|
+
});
|
|
5679
|
+
if (visible) {
|
|
5680
|
+
return [...acc, spineItem];
|
|
5681
|
+
}
|
|
5682
|
+
return acc;
|
|
5683
|
+
},
|
|
5684
|
+
[]
|
|
5685
|
+
);
|
|
5686
|
+
const beginItem = spineItemsVisible[0] ?? fallbackSpineItem;
|
|
5687
|
+
const endItem = spineItemsVisible[spineItemsVisible.length - 1] ?? beginItem;
|
|
5688
|
+
if (!beginItem || !endItem) return void 0;
|
|
5689
|
+
const beginItemIndex = spineItemsManager.getSpineItemIndex(beginItem);
|
|
5690
|
+
const endItemIndex = spineItemsManager.getSpineItemIndex(endItem);
|
|
5691
|
+
return {
|
|
5692
|
+
beginIndex: beginItemIndex ?? 0,
|
|
5693
|
+
endIndex: endItemIndex ?? 0
|
|
5694
|
+
};
|
|
5695
|
+
};
|
|
5696
|
+
const getSpinePositionFromSpineItemPosition = ({
|
|
5697
|
+
spineItemPosition,
|
|
5698
|
+
itemLayout: { left, top }
|
|
5699
|
+
}) => {
|
|
5700
|
+
return {
|
|
5701
|
+
x: left + spineItemPosition.x,
|
|
5702
|
+
y: top + spineItemPosition.y
|
|
5703
|
+
};
|
|
5704
|
+
};
|
|
5705
|
+
const getSpineInfoFromAbsolutePageIndex = ({
|
|
5706
|
+
absolutePageIndex,
|
|
5707
|
+
spineLayout,
|
|
5708
|
+
spineItemsManager,
|
|
5709
|
+
context,
|
|
5710
|
+
settings
|
|
5711
|
+
}) => {
|
|
5712
|
+
const items = spineItemsManager.items;
|
|
5713
|
+
const { found, currentAbsolutePage } = items.reduce(
|
|
5714
|
+
(acc, item) => {
|
|
5715
|
+
if (acc.found) return acc;
|
|
5716
|
+
const itemLayout = spineLayout.getAbsolutePositionOf(item);
|
|
5717
|
+
const numberOfPages = getSpineItemNumberOfPages({
|
|
5718
|
+
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
5719
|
+
itemHeight: itemLayout.height,
|
|
5720
|
+
itemWidth: itemLayout.width,
|
|
5721
|
+
context,
|
|
5722
|
+
settings
|
|
5723
|
+
});
|
|
5724
|
+
const possiblePageIndex = absolutePageIndex - acc.currentAbsolutePage;
|
|
5725
|
+
const currentAbsolutePage2 = acc.currentAbsolutePage + numberOfPages;
|
|
5726
|
+
if (possiblePageIndex <= numberOfPages - 1) {
|
|
5727
|
+
return {
|
|
5728
|
+
...acc,
|
|
5729
|
+
currentAbsolutePage: currentAbsolutePage2,
|
|
5730
|
+
found: { item, pageIndex: possiblePageIndex }
|
|
5731
|
+
};
|
|
5732
|
+
}
|
|
5733
|
+
return {
|
|
5734
|
+
...acc,
|
|
5735
|
+
currentAbsolutePage: currentAbsolutePage2
|
|
5736
|
+
};
|
|
5737
|
+
},
|
|
5738
|
+
{ currentAbsolutePage: 0 }
|
|
5739
|
+
);
|
|
5740
|
+
if (found) {
|
|
5741
|
+
return {
|
|
5742
|
+
spineItem: found.item,
|
|
5743
|
+
pageIndex: found.pageIndex,
|
|
5744
|
+
itemIndex: spineItemsManager.getSpineItemIndex(found.item) ?? 0,
|
|
5745
|
+
currentAbsolutePage
|
|
5746
|
+
};
|
|
6090
5747
|
}
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
5748
|
+
return void 0;
|
|
5749
|
+
};
|
|
5750
|
+
const getAbsolutePageIndexFromPageIndex = ({
|
|
5751
|
+
pageIndex,
|
|
5752
|
+
spineItemOrId,
|
|
5753
|
+
spineLayout,
|
|
5754
|
+
spineItemsManager,
|
|
5755
|
+
context,
|
|
5756
|
+
settings
|
|
5757
|
+
}) => {
|
|
5758
|
+
const items = spineItemsManager.items;
|
|
5759
|
+
const spineItem = spineItemsManager.get(spineItemOrId);
|
|
5760
|
+
if (!spineItem) return void 0;
|
|
5761
|
+
const { currentAbsolutePage } = items.reduce(
|
|
5762
|
+
(acc, item) => {
|
|
5763
|
+
if (acc.found) return acc;
|
|
5764
|
+
const itemLayout = spineLayout.getAbsolutePositionOf(item);
|
|
5765
|
+
const numberOfPages = getSpineItemNumberOfPages({
|
|
5766
|
+
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
5767
|
+
itemHeight: itemLayout.height,
|
|
5768
|
+
itemWidth: itemLayout.width,
|
|
5769
|
+
context,
|
|
5770
|
+
settings
|
|
5771
|
+
});
|
|
5772
|
+
if (spineItem === item) {
|
|
5773
|
+
if (pageIndex <= numberOfPages - 1) {
|
|
5774
|
+
return {
|
|
5775
|
+
currentAbsolutePage: acc.currentAbsolutePage + pageIndex,
|
|
5776
|
+
found: true
|
|
5777
|
+
};
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
return {
|
|
5781
|
+
...acc,
|
|
5782
|
+
currentAbsolutePage: acc.currentAbsolutePage + numberOfPages
|
|
5783
|
+
};
|
|
5784
|
+
},
|
|
5785
|
+
{ currentAbsolutePage: 0, found: false }
|
|
5786
|
+
);
|
|
5787
|
+
return currentAbsolutePage;
|
|
5788
|
+
};
|
|
5789
|
+
const createSpineLocator = ({
|
|
5790
|
+
spineItemsManager,
|
|
5791
|
+
context,
|
|
5792
|
+
spineItemLocator,
|
|
5793
|
+
settings,
|
|
5794
|
+
spineLayout
|
|
5795
|
+
}) => {
|
|
5796
|
+
const getSpineItemPositionFromSpinePosition = Report.measurePerformance(
|
|
5797
|
+
`getSpineItemPositionFromSpinePosition`,
|
|
5798
|
+
10,
|
|
5799
|
+
(position, spineItem) => {
|
|
5800
|
+
const { left, top } = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5801
|
+
return {
|
|
5802
|
+
/**
|
|
5803
|
+
* when using spread the item could be on the right and therefore will be negative
|
|
5804
|
+
* @example
|
|
5805
|
+
* 400 (position = viewport), page of 200
|
|
5806
|
+
* 400 - 600 = -200.
|
|
5807
|
+
* However we can assume we are at 0, because we in fact can see the beginning of the item
|
|
5808
|
+
*/
|
|
5809
|
+
x: Math.max(position.x - left, 0),
|
|
5810
|
+
y: Math.max(position.y - top, 0)
|
|
5811
|
+
};
|
|
5812
|
+
},
|
|
5813
|
+
{ disable: true }
|
|
5814
|
+
);
|
|
5815
|
+
const getSpinePositionFromSpineItem = (spineItem) => {
|
|
5816
|
+
return getSpinePositionFromSpineItemPosition({
|
|
5817
|
+
spineItemPosition: { x: 0, y: 0 },
|
|
5818
|
+
itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
|
|
5819
|
+
});
|
|
5820
|
+
};
|
|
5821
|
+
const getSpineItemFromIframe = (iframe) => {
|
|
5822
|
+
return spineItemsManager.items.find((item) => {
|
|
5823
|
+
var _a;
|
|
5824
|
+
return ((_a = item.renderer.layers[0]) == null ? void 0 : _a.element) === iframe;
|
|
5825
|
+
});
|
|
5826
|
+
};
|
|
5827
|
+
const getSpineItemPageIndexFromNode = (node, offset, spineItemOrIndex) => {
|
|
5828
|
+
if (typeof spineItemOrIndex === `number`) {
|
|
5829
|
+
const spineItem = spineItemsManager.get(spineItemOrIndex);
|
|
5830
|
+
return spineItem ? spineItemLocator.getSpineItemPageIndexFromNode(
|
|
5831
|
+
node,
|
|
5832
|
+
offset || 0,
|
|
5833
|
+
spineItem
|
|
5834
|
+
) : void 0;
|
|
5835
|
+
}
|
|
5836
|
+
return spineItemLocator.getSpineItemPageIndexFromNode(
|
|
5837
|
+
node,
|
|
5838
|
+
offset || 0,
|
|
5839
|
+
spineItemOrIndex
|
|
5840
|
+
);
|
|
5841
|
+
};
|
|
5842
|
+
const getVisiblePagesFromViewportPosition = ({
|
|
5843
|
+
position,
|
|
5844
|
+
threshold,
|
|
5845
|
+
spineItem,
|
|
5846
|
+
restrictToScreen
|
|
5847
|
+
}) => {
|
|
5848
|
+
const { height, width } = spineItem.getElementDimensions();
|
|
5849
|
+
const numberOfPages = spineItemLocator.getSpineItemNumberOfPages({
|
|
5850
|
+
isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
|
|
5851
|
+
itemHeight: height,
|
|
5852
|
+
itemWidth: width
|
|
5853
|
+
});
|
|
5854
|
+
const pages = Array.from(Array(numberOfPages)).map((_, index) => {
|
|
5855
|
+
const spineItemPosition = spineItemLocator.getSpineItemPositionFromPageIndex({
|
|
5856
|
+
pageIndex: index,
|
|
5857
|
+
isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
|
|
5858
|
+
itemLayout: spineItem.getElementDimensions()
|
|
5859
|
+
});
|
|
5860
|
+
const spinePosition = getSpinePositionFromSpineItemPosition({
|
|
5861
|
+
spineItemPosition,
|
|
5862
|
+
itemLayout: spineLayout.getAbsolutePositionOf(spineItem)
|
|
5863
|
+
});
|
|
5864
|
+
return {
|
|
5865
|
+
index,
|
|
5866
|
+
absolutePosition: {
|
|
5867
|
+
width: context.getPageSize().width,
|
|
5868
|
+
height: context.getPageSize().height,
|
|
5869
|
+
left: spinePosition.x,
|
|
5870
|
+
top: spinePosition.y,
|
|
5871
|
+
bottom: spinePosition.y + context.getPageSize().height,
|
|
5872
|
+
right: spinePosition.x + context.getPageSize().width
|
|
5873
|
+
}
|
|
5874
|
+
};
|
|
5875
|
+
});
|
|
5876
|
+
const pagesVisible = pages.reduce(
|
|
5877
|
+
(acc, { absolutePosition, index }) => {
|
|
5878
|
+
const { visible } = getItemVisibilityForPosition({
|
|
5879
|
+
context,
|
|
5880
|
+
viewportPosition: position,
|
|
5881
|
+
restrictToScreen,
|
|
5882
|
+
threshold,
|
|
5883
|
+
itemPosition: absolutePosition
|
|
5884
|
+
});
|
|
5885
|
+
if (visible) {
|
|
5886
|
+
return [...acc, index];
|
|
5887
|
+
}
|
|
5888
|
+
return acc;
|
|
5889
|
+
},
|
|
5890
|
+
[]
|
|
5891
|
+
);
|
|
5892
|
+
const beginPageIndex = pagesVisible[0];
|
|
5893
|
+
const endPageIndex = pagesVisible[pagesVisible.length - 1] ?? beginPageIndex;
|
|
5894
|
+
if (beginPageIndex === void 0 || endPageIndex === void 0)
|
|
5895
|
+
return void 0;
|
|
5896
|
+
return {
|
|
5897
|
+
beginPageIndex,
|
|
5898
|
+
endPageIndex
|
|
5899
|
+
};
|
|
5900
|
+
};
|
|
5901
|
+
const isPositionWithinSpineItem = (position, spineItem) => {
|
|
5902
|
+
const { bottom, left, right, top } = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5903
|
+
return position.x >= left && position.x <= right && position.y <= bottom && position.y >= top;
|
|
5904
|
+
};
|
|
5905
|
+
const getSafeSpineItemPositionFromUnsafeSpineItemPosition = (unsafePosition, spineItem) => {
|
|
5906
|
+
const { height, width } = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5907
|
+
return {
|
|
5908
|
+
x: Math.min(Math.max(0, unsafePosition.x), width),
|
|
5909
|
+
y: Math.min(Math.max(0, unsafePosition.y), height)
|
|
5910
|
+
};
|
|
5911
|
+
};
|
|
5912
|
+
return {
|
|
5913
|
+
getSpinePositionFromSpineItemPosition: ({
|
|
5914
|
+
spineItem,
|
|
5915
|
+
spineItemPosition
|
|
5916
|
+
}) => {
|
|
5917
|
+
const itemLayout = spineLayout.getAbsolutePositionOf(spineItem);
|
|
5918
|
+
return getSpinePositionFromSpineItemPosition({
|
|
5919
|
+
itemLayout,
|
|
5920
|
+
spineItemPosition
|
|
5921
|
+
});
|
|
5922
|
+
},
|
|
5923
|
+
getAbsolutePageIndexFromPageIndex: (params) => getAbsolutePageIndexFromPageIndex({
|
|
5924
|
+
...params,
|
|
5925
|
+
context,
|
|
5926
|
+
settings,
|
|
5927
|
+
spineItemsManager,
|
|
5928
|
+
spineLayout
|
|
5929
|
+
}),
|
|
5930
|
+
getSpineInfoFromAbsolutePageIndex: (params) => getSpineInfoFromAbsolutePageIndex({
|
|
5931
|
+
...params,
|
|
5932
|
+
context,
|
|
5933
|
+
settings,
|
|
5934
|
+
spineItemsManager,
|
|
5935
|
+
spineLayout
|
|
5936
|
+
}),
|
|
5937
|
+
getSpinePositionFromSpineItem,
|
|
5938
|
+
getSpineItemPositionFromSpinePosition,
|
|
5939
|
+
getSpineItemFromPosition: (position) => getSpineItemFromPosition({
|
|
5940
|
+
position,
|
|
5941
|
+
settings,
|
|
5942
|
+
spineItemsManager,
|
|
5943
|
+
spineLayout
|
|
5944
|
+
}),
|
|
5945
|
+
getSpineItemFromIframe,
|
|
5946
|
+
getSpineItemPageIndexFromNode,
|
|
5947
|
+
getVisibleSpineItemsFromPosition: (params) => getVisibleSpineItemsFromPosition({
|
|
5948
|
+
context,
|
|
5949
|
+
settings,
|
|
5950
|
+
spineItemsManager,
|
|
5951
|
+
spineLayout,
|
|
5952
|
+
...params
|
|
5953
|
+
}),
|
|
5954
|
+
getVisiblePagesFromViewportPosition,
|
|
5955
|
+
isPositionWithinSpineItem,
|
|
5956
|
+
spineItemLocator,
|
|
5957
|
+
getSafeSpineItemPositionFromUnsafeSpineItemPosition
|
|
5958
|
+
};
|
|
5959
|
+
};
|
|
5960
|
+
const loadItems = ({
|
|
5961
|
+
spineItemsManager,
|
|
5962
|
+
settings
|
|
5963
|
+
}) => (stream) => stream.pipe(
|
|
5964
|
+
tap$1(([beginIndex, endIndex]) => {
|
|
5965
|
+
const { numberOfAdjacentSpineItemToPreLoad } = settings.values;
|
|
5966
|
+
const leftMaximumIndex = beginIndex - numberOfAdjacentSpineItemToPreLoad;
|
|
5967
|
+
const rightMaximumIndex = endIndex + numberOfAdjacentSpineItemToPreLoad;
|
|
5968
|
+
spineItemsManager.items.forEach((orderedSpineItem, index) => {
|
|
5969
|
+
const isWithinRange = index >= leftMaximumIndex && index <= rightMaximumIndex;
|
|
5970
|
+
if (isWithinRange) {
|
|
5971
|
+
orderedSpineItem.load();
|
|
5972
|
+
} else {
|
|
5973
|
+
orderedSpineItem.unload();
|
|
5974
|
+
}
|
|
5975
|
+
});
|
|
5976
|
+
})
|
|
5977
|
+
);
|
|
5978
|
+
const mapToItemsToLoad = ({ spineLocator }) => (stream) => stream.pipe(
|
|
5979
|
+
map$1((position) => {
|
|
5980
|
+
const { beginIndex = 0, endIndex = 0 } = spineLocator.getVisibleSpineItemsFromPosition({
|
|
5981
|
+
position,
|
|
5982
|
+
threshold: 0
|
|
5983
|
+
}) || {};
|
|
5984
|
+
return [beginIndex, endIndex];
|
|
5985
|
+
})
|
|
5986
|
+
);
|
|
5987
|
+
class SpineItemsLoader extends DestroyableClass {
|
|
5988
|
+
constructor(context, spineItemsManager, spineLocator, settings, spineLayout) {
|
|
5989
|
+
super();
|
|
5990
|
+
this.context = context;
|
|
5991
|
+
this.spineItemsManager = spineItemsManager;
|
|
5992
|
+
this.spineLocator = spineLocator;
|
|
6096
5993
|
this.settings = settings;
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
|
|
5994
|
+
this.spineLayout = spineLayout;
|
|
5995
|
+
const navigationUpdate$ = this.context.bridgeEvent.navigation$;
|
|
5996
|
+
const layoutHasChanged$ = this.spineLayout.layout$.pipe(
|
|
5997
|
+
filter$1(({ hasChanged }) => hasChanged)
|
|
6102
5998
|
);
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
5999
|
+
const numberOfAdjacentSpineItemToPreLoad$ = settings.values$.pipe(
|
|
6000
|
+
map$1(
|
|
6001
|
+
({ numberOfAdjacentSpineItemToPreLoad }) => numberOfAdjacentSpineItemToPreLoad
|
|
6002
|
+
),
|
|
6003
|
+
skip$1(1),
|
|
6004
|
+
distinctUntilChanged$1()
|
|
6005
|
+
);
|
|
6006
|
+
const loadSpineItems$ = merge(
|
|
6007
|
+
navigationUpdate$,
|
|
6008
|
+
layoutHasChanged$,
|
|
6009
|
+
numberOfAdjacentSpineItemToPreLoad$
|
|
6010
|
+
).pipe(
|
|
6011
|
+
// this can be changed by whatever we want and SHOULD not break navigation.
|
|
6012
|
+
// Ideally loading faster is better but loading too close to user navigating can
|
|
6013
|
+
// be dangerous.
|
|
6014
|
+
debounceTime$1(100, animationFrameScheduler),
|
|
6015
|
+
waitForSwitch(this.context.bridgeEvent.viewportFree$),
|
|
6016
|
+
withLatestFrom(this.context.bridgeEvent.navigation$),
|
|
6017
|
+
map$1(([, navigation]) => navigation.position),
|
|
6018
|
+
mapToItemsToLoad({ spineLocator }),
|
|
6019
|
+
loadItems({ spineItemsManager, settings })
|
|
6020
|
+
);
|
|
6021
|
+
loadSpineItems$.pipe(takeUntil(this.destroy$)).subscribe();
|
|
6110
6022
|
}
|
|
6111
6023
|
}
|
|
6112
|
-
class
|
|
6113
|
-
constructor(
|
|
6114
|
-
|
|
6115
|
-
this.
|
|
6116
|
-
this.
|
|
6117
|
-
this.
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
}) => {
|
|
6126
|
-
if (right !== void 0) {
|
|
6127
|
-
this.containerElement.style.right = `${right}px`;
|
|
6128
|
-
} else {
|
|
6129
|
-
this.containerElement.style.removeProperty(`right`);
|
|
6130
|
-
}
|
|
6131
|
-
if (left !== void 0) {
|
|
6132
|
-
this.containerElement.style.left = `${left}px`;
|
|
6133
|
-
} else {
|
|
6134
|
-
this.containerElement.style.removeProperty(`left`);
|
|
6135
|
-
}
|
|
6136
|
-
if (top !== void 0) {
|
|
6137
|
-
this.containerElement.style.top = `${top}px`;
|
|
6138
|
-
} else {
|
|
6139
|
-
this.containerElement.style.removeProperty(`top`);
|
|
6140
|
-
}
|
|
6141
|
-
};
|
|
6142
|
-
this.getBoundingRectOfElementFromSelector = (selector) => {
|
|
6143
|
-
var _a2, _b2, _c, _d, _e;
|
|
6144
|
-
const frameElement = (_a2 = this.renderer.layers[0]) == null ? void 0 : _a2.element;
|
|
6145
|
-
if (frameElement && frameElement instanceof HTMLIFrameElement && selector) {
|
|
6146
|
-
if (selector.startsWith(`#`)) {
|
|
6147
|
-
return (_c = (_b2 = frameElement.contentDocument) == null ? void 0 : _b2.getElementById(selector.replace(`#`, ``))) == null ? void 0 : _c.getBoundingClientRect();
|
|
6148
|
-
}
|
|
6149
|
-
return (_e = (_d = frameElement.contentDocument) == null ? void 0 : _d.querySelector(selector)) == null ? void 0 : _e.getBoundingClientRect();
|
|
6150
|
-
}
|
|
6151
|
-
};
|
|
6152
|
-
this.layout = ({
|
|
6153
|
-
blankPagePosition,
|
|
6154
|
-
minimumWidth,
|
|
6155
|
-
spreadPosition
|
|
6156
|
-
}) => {
|
|
6157
|
-
this.hookManager.execute(`item.onBeforeLayout`, void 0, {
|
|
6158
|
-
blankPagePosition,
|
|
6159
|
-
item: this.item,
|
|
6160
|
-
minimumWidth
|
|
6161
|
-
});
|
|
6162
|
-
const { height, width } = this.renderer.layout({
|
|
6163
|
-
blankPagePosition,
|
|
6164
|
-
minPageSpread: minimumWidth / this.context.getPageSize().width,
|
|
6165
|
-
spreadPosition
|
|
6166
|
-
}) ?? { width: 0, height: 0 };
|
|
6167
|
-
const minHeight = Math.max(height, this.context.getPageSize().height);
|
|
6168
|
-
const minWidth = Math.max(width, minimumWidth);
|
|
6169
|
-
this.containerElement.style.width = `${minWidth}px`;
|
|
6170
|
-
this.containerElement.style.height = `${minHeight}px`;
|
|
6171
|
-
this.hookManager.execute(`item.onAfterLayout`, void 0, {
|
|
6172
|
-
blankPagePosition,
|
|
6173
|
-
item: this.item,
|
|
6174
|
-
minimumWidth
|
|
6175
|
-
});
|
|
6176
|
-
return { width: minWidth, height: minHeight };
|
|
6177
|
-
};
|
|
6178
|
-
this.load = () => this.renderer.load();
|
|
6179
|
-
this.unload = () => {
|
|
6180
|
-
this.renderer.unload();
|
|
6181
|
-
};
|
|
6182
|
-
this.getElementDimensions = () => {
|
|
6183
|
-
const rect = this.containerElement.getBoundingClientRect();
|
|
6184
|
-
const normalizedValues = {
|
|
6185
|
-
...rect,
|
|
6186
|
-
// we want to round to first decimal because it's possible to have half pixel
|
|
6187
|
-
// however browser engine can also gives back x.yyyy based on their precision
|
|
6188
|
-
width: Math.round(rect.width * 10) / 10,
|
|
6189
|
-
height: Math.round(rect.height * 10) / 10
|
|
6190
|
-
};
|
|
6191
|
-
return normalizedValues;
|
|
6192
|
-
};
|
|
6193
|
-
this.destroy = () => {
|
|
6194
|
-
this.destroySubject$.next();
|
|
6195
|
-
this.containerElement.remove();
|
|
6196
|
-
this.destroySubject$.complete();
|
|
6197
|
-
this.renderer.destroy();
|
|
6198
|
-
};
|
|
6199
|
-
this.isUsingVerticalWriting = () => {
|
|
6200
|
-
var _a2;
|
|
6201
|
-
return !!((_a2 = this.renderer.writingMode) == null ? void 0 : _a2.startsWith(`vertical`));
|
|
6202
|
-
};
|
|
6203
|
-
this.destroySubject$ = new Subject();
|
|
6204
|
-
this.containerElement = createContainerElement(
|
|
6205
|
-
parentElement,
|
|
6206
|
-
item,
|
|
6207
|
-
hookManager
|
|
6024
|
+
class SpineItemsObserver extends DestroyableClass {
|
|
6025
|
+
constructor(spineItemsManager, spineLocator) {
|
|
6026
|
+
super();
|
|
6027
|
+
this.spineItemsManager = spineItemsManager;
|
|
6028
|
+
this.spineLocator = spineLocator;
|
|
6029
|
+
this.itemIsReady$ = this.spineItemsManager.items$.pipe(
|
|
6030
|
+
switchMap((items) => {
|
|
6031
|
+
const itemsIsReady$ = items.map(
|
|
6032
|
+
(item) => item.isReady$.pipe(map$1((isReady) => ({ item, isReady })))
|
|
6033
|
+
);
|
|
6034
|
+
return merge(...itemsIsReady$);
|
|
6035
|
+
}),
|
|
6036
|
+
share()
|
|
6208
6037
|
);
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6038
|
+
this.itemResize$ = this.spineItemsManager.items$.pipe(
|
|
6039
|
+
switchMap((items) => {
|
|
6040
|
+
const resize$ = items.map(
|
|
6041
|
+
(item) => observeResize(item.element).pipe(
|
|
6042
|
+
map$1((entries) => ({ entries, item }))
|
|
6043
|
+
)
|
|
6044
|
+
);
|
|
6045
|
+
return merge(...resize$);
|
|
6046
|
+
}),
|
|
6047
|
+
share()
|
|
6219
6048
|
);
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6049
|
+
this.itemLoaded$ = this.spineItemsManager.items$.pipe(
|
|
6050
|
+
switchMap((items) => {
|
|
6051
|
+
const itemsIsReady$ = items.map(
|
|
6052
|
+
(item) => item.loaded$.pipe(map$1(() => item))
|
|
6053
|
+
);
|
|
6054
|
+
return merge(...itemsIsReady$);
|
|
6055
|
+
})
|
|
6223
6056
|
);
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
const convertSpinePositionToLayoutPosition = ({
|
|
6060
|
+
position,
|
|
6061
|
+
pageSize
|
|
6062
|
+
}) => {
|
|
6063
|
+
return {
|
|
6064
|
+
x: position.x,
|
|
6065
|
+
y: position.y,
|
|
6066
|
+
left: position.x,
|
|
6067
|
+
top: position.y,
|
|
6068
|
+
width: pageSize.width,
|
|
6069
|
+
height: pageSize.height,
|
|
6070
|
+
bottom: position.y + pageSize.height,
|
|
6071
|
+
right: position.x + pageSize.width
|
|
6072
|
+
};
|
|
6073
|
+
};
|
|
6074
|
+
const NAMESPACE = `SpineLayout`;
|
|
6075
|
+
class SpineLayout extends DestroyableClass {
|
|
6076
|
+
constructor(spineItemsManager, context, settings) {
|
|
6077
|
+
super();
|
|
6078
|
+
this.spineItemsManager = spineItemsManager;
|
|
6079
|
+
this.context = context;
|
|
6080
|
+
this.settings = settings;
|
|
6081
|
+
this.itemLayoutInformation = [];
|
|
6082
|
+
this.layoutSubject = new Subject();
|
|
6083
|
+
spineItemsManager.items$.pipe(
|
|
6084
|
+
switchMap((items) => {
|
|
6085
|
+
const itemsLayout$ = items.map(
|
|
6086
|
+
(spineItem) => spineItem.contentLayout$.pipe(
|
|
6087
|
+
tap$1(() => {
|
|
6088
|
+
this.layout();
|
|
6089
|
+
})
|
|
6090
|
+
)
|
|
6091
|
+
);
|
|
6092
|
+
const writingModeUpdate$ = items.map(
|
|
6093
|
+
(spineItem) => spineItem.loaded$.pipe(
|
|
6094
|
+
tap$1(() => {
|
|
6095
|
+
if (spineItem.isUsingVerticalWriting()) {
|
|
6096
|
+
this.context.update({
|
|
6097
|
+
hasVerticalWriting: true
|
|
6098
|
+
});
|
|
6099
|
+
} else {
|
|
6100
|
+
this.context.update({
|
|
6101
|
+
hasVerticalWriting: false
|
|
6102
|
+
});
|
|
6103
|
+
}
|
|
6104
|
+
})
|
|
6105
|
+
)
|
|
6106
|
+
);
|
|
6107
|
+
return merge(...itemsLayout$, ...writingModeUpdate$);
|
|
6108
|
+
})
|
|
6109
|
+
).pipe(takeUntil(this.destroy$)).subscribe();
|
|
6110
|
+
this.layout$ = this.layoutSubject.pipe(
|
|
6111
|
+
map$1((hasChanged) => ({ hasChanged })),
|
|
6112
|
+
startWith$1({ hasChanged: true }),
|
|
6113
|
+
map$1(({ hasChanged }) => {
|
|
6114
|
+
const items = spineItemsManager.items;
|
|
6115
|
+
const spineItemsPagesAbsolutePositions = items.map((item) => {
|
|
6116
|
+
const itemLayout = this.getAbsolutePositionOf(item);
|
|
6117
|
+
const numberOfPages = getSpineItemNumberOfPages({
|
|
6118
|
+
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
6119
|
+
itemHeight: itemLayout.height,
|
|
6120
|
+
itemWidth: itemLayout.width,
|
|
6121
|
+
context,
|
|
6122
|
+
settings
|
|
6123
|
+
});
|
|
6124
|
+
const pages2 = new Array(numberOfPages).fill(void 0);
|
|
6125
|
+
return pages2.map(
|
|
6126
|
+
(_, pageIndex) => convertSpinePositionToLayoutPosition({
|
|
6127
|
+
pageSize: this.context.getPageSize(),
|
|
6128
|
+
position: getSpinePositionFromSpineItemPosition({
|
|
6129
|
+
itemLayout,
|
|
6130
|
+
spineItemPosition: getSpineItemPositionFromPageIndex({
|
|
6131
|
+
isUsingVerticalWriting: !!item.isUsingVerticalWriting(),
|
|
6132
|
+
itemLayout,
|
|
6133
|
+
pageIndex,
|
|
6134
|
+
context
|
|
6135
|
+
})
|
|
6136
|
+
})
|
|
6137
|
+
})
|
|
6138
|
+
);
|
|
6139
|
+
});
|
|
6140
|
+
const pages = spineItemsPagesAbsolutePositions.reduce(
|
|
6141
|
+
(acc, itemPages, itemIndex) => {
|
|
6142
|
+
const itemPagesInfo = itemPages.map(
|
|
6143
|
+
(absolutePosition, pageIndex) => ({
|
|
6144
|
+
itemIndex,
|
|
6145
|
+
absolutePageIndex: itemIndex + pageIndex,
|
|
6146
|
+
absolutePosition
|
|
6147
|
+
})
|
|
6148
|
+
);
|
|
6149
|
+
return [...acc, ...itemPagesInfo];
|
|
6150
|
+
},
|
|
6151
|
+
[]
|
|
6152
|
+
);
|
|
6153
|
+
return {
|
|
6154
|
+
hasChanged,
|
|
6155
|
+
spineItemsAbsolutePositions: items.map(
|
|
6156
|
+
(item) => this.getAbsolutePositionOf(item)
|
|
6157
|
+
),
|
|
6158
|
+
spineItemsPagesAbsolutePositions,
|
|
6159
|
+
pages
|
|
6160
|
+
};
|
|
6161
|
+
}),
|
|
6162
|
+
shareReplay$1(1)
|
|
6230
6163
|
);
|
|
6231
6164
|
}
|
|
6232
|
-
get element() {
|
|
6233
|
-
return this.containerElement;
|
|
6234
|
-
}
|
|
6235
6165
|
/**
|
|
6236
|
-
* @
|
|
6237
|
-
*
|
|
6238
|
-
*
|
|
6239
|
-
*
|
|
6240
|
-
*
|
|
6241
|
-
*
|
|
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)
|
|
6242
6172
|
*/
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6173
|
+
layout() {
|
|
6174
|
+
const manifest = this.context.manifest;
|
|
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 }
|
|
6259
6262
|
);
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
return this.renderer.state$.pipe(
|
|
6263
|
-
distinctUntilChanged(),
|
|
6264
|
-
filter((state) => state !== "idle"),
|
|
6265
|
-
switchMap$1(
|
|
6266
|
-
() => this.renderer.state$.pipe(
|
|
6267
|
-
filter((state) => state === `idle`),
|
|
6268
|
-
first()
|
|
6269
|
-
)
|
|
6270
|
-
)
|
|
6263
|
+
const hasLayoutChanges = this.itemLayoutInformation.length !== newItemLayoutInformation.length || this.itemLayoutInformation.some(
|
|
6264
|
+
(old, index) => !isShallowEqual(old, newItemLayoutInformation[index])
|
|
6271
6265
|
);
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6266
|
+
this.itemLayoutInformation = newItemLayoutInformation;
|
|
6267
|
+
Report.log(NAMESPACE, `layout`, {
|
|
6268
|
+
hasLayoutChanges,
|
|
6269
|
+
itemLayoutInformation: this.itemLayoutInformation
|
|
6270
|
+
});
|
|
6271
|
+
this.layoutSubject.next(hasLayoutChanges);
|
|
6275
6272
|
}
|
|
6276
6273
|
/**
|
|
6277
|
-
*
|
|
6278
|
-
*
|
|
6279
|
-
* @important
|
|
6280
|
-
* The document needs to be detected as a frame.
|
|
6274
|
+
* It's important to not use x,y since we need the absolute position of each element. Otherwise x,y would be relative to
|
|
6275
|
+
* current window (viewport).
|
|
6281
6276
|
*/
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6277
|
+
getAbsolutePositionOf(spineItemOrIndex) {
|
|
6278
|
+
const fallback = {
|
|
6279
|
+
left: 0,
|
|
6280
|
+
right: 0,
|
|
6281
|
+
top: 0,
|
|
6282
|
+
bottom: 0,
|
|
6283
|
+
width: 0,
|
|
6284
|
+
height: 0,
|
|
6285
|
+
x: 0,
|
|
6286
|
+
y: 0
|
|
6287
|
+
};
|
|
6288
|
+
const spineItem = this.spineItemsManager.get(spineItemOrIndex);
|
|
6289
|
+
const indexOfItem = spineItem ? this.spineItemsManager.items.indexOf(spineItem) : -1;
|
|
6290
|
+
const layoutInformation = this.itemLayoutInformation[indexOfItem];
|
|
6291
|
+
return layoutInformation || fallback;
|
|
6292
|
+
}
|
|
6293
|
+
destroy() {
|
|
6294
|
+
super.destroy();
|
|
6295
|
+
this.layoutSubject.complete();
|
|
6288
6296
|
}
|
|
6289
6297
|
}
|
|
6290
|
-
const createContainerElement = (containerElement, item, hookManager) => {
|
|
6291
|
-
const element = containerElement.ownerDocument.createElement(`div`);
|
|
6292
|
-
element.classList.add(`spineItem`);
|
|
6293
|
-
element.classList.add(`spineItem-${item.renditionLayout}`);
|
|
6294
|
-
element.style.cssText = `
|
|
6295
|
-
position: absolute;
|
|
6296
|
-
overflow: hidden;
|
|
6297
|
-
`;
|
|
6298
|
-
hookManager.execute("item.onBeforeContainerCreated", void 0, { element });
|
|
6299
|
-
return element;
|
|
6300
|
-
};
|
|
6301
6298
|
class Spine extends DestroyableClass {
|
|
6302
6299
|
constructor(parentElement$, context, pagination, spineItemsManager, spineItemLocator, settings, hookManager) {
|
|
6303
6300
|
super();
|
|
@@ -6375,6 +6372,17 @@ class Spine extends DestroyableClass {
|
|
|
6375
6372
|
this.elementSubject.complete();
|
|
6376
6373
|
}
|
|
6377
6374
|
}
|
|
6375
|
+
const generateCfiFromSelection = ({
|
|
6376
|
+
item,
|
|
6377
|
+
selection
|
|
6378
|
+
}) => {
|
|
6379
|
+
const anchorCfi = selection.anchorNode ? generateCfi(selection.anchorNode, selection.anchorOffset, item) : void 0;
|
|
6380
|
+
const focusCfi = selection.focusNode ? generateCfi(selection.focusNode, selection.focusOffset, item) : void 0;
|
|
6381
|
+
return {
|
|
6382
|
+
anchorCfi,
|
|
6383
|
+
focusCfi
|
|
6384
|
+
};
|
|
6385
|
+
};
|
|
6378
6386
|
const createReader = (inputSettings) => {
|
|
6379
6387
|
const stateSubject$ = new BehaviorSubject({
|
|
6380
6388
|
supportedPageTurnAnimation: [`fade`, `none`, `slide`],
|
|
@@ -6523,6 +6531,8 @@ const createReader = (inputSettings) => {
|
|
|
6523
6531
|
hookManager,
|
|
6524
6532
|
cfi: {
|
|
6525
6533
|
generateCfiFromRange,
|
|
6534
|
+
generateCfiFromSelection,
|
|
6535
|
+
parseCfi,
|
|
6526
6536
|
generateCfiForSpineItemPage: (params) => generateCfiForSpineItemPage({
|
|
6527
6537
|
...params,
|
|
6528
6538
|
spineItemLocator
|
|
@@ -6530,7 +6540,6 @@ const createReader = (inputSettings) => {
|
|
|
6530
6540
|
resolveCfi: (params) => resolveCfi({ ...params, spineItemsManager })
|
|
6531
6541
|
},
|
|
6532
6542
|
navigation: {
|
|
6533
|
-
viewportFree$: context.bridgeEvent.viewportFree$,
|
|
6534
6543
|
viewportBusy$: context.bridgeEvent.viewportBusy$,
|
|
6535
6544
|
getViewportPosition: () => navigator2.viewportNavigator.viewportPosition,
|
|
6536
6545
|
getNavigation: navigator2.getNavigation.bind(navigator2),
|
|
@@ -6552,6 +6561,7 @@ const createReader = (inputSettings) => {
|
|
|
6552
6561
|
element$,
|
|
6553
6562
|
layout$: spine.spineLayout.layout$,
|
|
6554
6563
|
viewportState$: context.bridgeEvent.viewportState$,
|
|
6564
|
+
viewportFree$: context.bridgeEvent.viewportFree$,
|
|
6555
6565
|
/**
|
|
6556
6566
|
* Dispatched when the reader has loaded a book and is rendering a book.
|
|
6557
6567
|
* Using navigation API and getting information about current content will
|
|
@@ -6872,13 +6882,13 @@ const mediaEnhancer = (next) => (options) => {
|
|
|
6872
6882
|
...options,
|
|
6873
6883
|
getRenderer(item) {
|
|
6874
6884
|
var _a;
|
|
6875
|
-
const
|
|
6885
|
+
const maybeFactory = (_a = options.getRenderer) == null ? void 0 : _a.call(options, item);
|
|
6876
6886
|
const mimeType = item.mediaType ?? detectMimeTypeFromName(item.href);
|
|
6877
6887
|
const isImageType = !!(mimeType == null ? void 0 : mimeType.startsWith(`image/`));
|
|
6878
|
-
if (!
|
|
6879
|
-
return ImageRenderer;
|
|
6888
|
+
if (!maybeFactory && isImageType) {
|
|
6889
|
+
return (props) => new ImageRenderer(props);
|
|
6880
6890
|
}
|
|
6881
|
-
return
|
|
6891
|
+
return maybeFactory;
|
|
6882
6892
|
}
|
|
6883
6893
|
});
|
|
6884
6894
|
const frameObserver = new IntersectionObserver(
|
|
@@ -7308,7 +7318,9 @@ const eventsEnhancer = (next) => (options) => {
|
|
|
7308
7318
|
`item.onDocumentLoad`,
|
|
7309
7319
|
({ destroy, layers, itemId }) => {
|
|
7310
7320
|
var _a;
|
|
7311
|
-
const frame = (_a = layers
|
|
7321
|
+
const frame = (_a = layers.find(
|
|
7322
|
+
(layer) => layer.element instanceof HTMLIFrameElement
|
|
7323
|
+
)) == null ? void 0 : _a.element;
|
|
7312
7324
|
if (!(frame instanceof HTMLIFrameElement)) return;
|
|
7313
7325
|
const item = reader.spineItemsManager.get(itemId);
|
|
7314
7326
|
if (!item) return;
|
|
@@ -7978,15 +7990,8 @@ const renderReflowable = ({
|
|
|
7978
7990
|
};
|
|
7979
7991
|
};
|
|
7980
7992
|
class HtmlRenderer extends DocumentRenderer {
|
|
7981
|
-
constructor(
|
|
7982
|
-
super(
|
|
7983
|
-
context,
|
|
7984
|
-
settings,
|
|
7985
|
-
hookManager,
|
|
7986
|
-
item,
|
|
7987
|
-
containerElement,
|
|
7988
|
-
resourcesHandler
|
|
7989
|
-
);
|
|
7993
|
+
constructor() {
|
|
7994
|
+
super(...arguments);
|
|
7990
7995
|
this.isImageType = () => {
|
|
7991
7996
|
const mimeType = this.item.mediaType ?? detectMimeTypeFromName(this.item.href);
|
|
7992
7997
|
return !!(mimeType == null ? void 0 : mimeType.startsWith(`image/`));
|
|
@@ -8105,30 +8110,59 @@ const htmlEnhancer = (next) => (options) => {
|
|
|
8105
8110
|
...options,
|
|
8106
8111
|
getRenderer(item) {
|
|
8107
8112
|
var _a;
|
|
8108
|
-
const
|
|
8109
|
-
return
|
|
8113
|
+
const maybeFactory = (_a = options.getRenderer) == null ? void 0 : _a.call(options, item);
|
|
8114
|
+
return maybeFactory ?? ((props) => new HtmlRenderer(props));
|
|
8110
8115
|
}
|
|
8111
8116
|
});
|
|
8112
8117
|
return reader;
|
|
8113
8118
|
};
|
|
8114
|
-
const
|
|
8115
|
-
|
|
8116
|
-
|
|
8119
|
+
const getRangeFromSelection = (anchor, focus) => {
|
|
8120
|
+
var _a;
|
|
8121
|
+
const range = (_a = anchor.node.ownerDocument) == null ? void 0 : _a.createRange();
|
|
8122
|
+
const comparison = anchor.node.compareDocumentPosition(focus.node);
|
|
8123
|
+
if (!range) return void 0;
|
|
8124
|
+
try {
|
|
8125
|
+
if (comparison & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
8126
|
+
range.setStart(focus.node, focus.offset || 0);
|
|
8127
|
+
range.setEnd(anchor.node, anchor.offset || 0);
|
|
8128
|
+
} else if (comparison & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
8129
|
+
range.setStart(anchor.node, anchor.offset || 0);
|
|
8130
|
+
range.setEnd(focus.node, focus.offset || 0);
|
|
8131
|
+
} else {
|
|
8132
|
+
const startOffset = Math.min(anchor.offset || 0, focus.offset || 0);
|
|
8133
|
+
const endOffset = Math.max(anchor.offset || 0, focus.offset || 0);
|
|
8134
|
+
range.setStart(anchor.node, startOffset);
|
|
8135
|
+
range.setEnd(anchor.node, endOffset);
|
|
8136
|
+
}
|
|
8137
|
+
} catch (e) {
|
|
8138
|
+
Report.warn("Failed to create range from selection", e, {
|
|
8139
|
+
anchor,
|
|
8140
|
+
focus
|
|
8141
|
+
});
|
|
8142
|
+
}
|
|
8143
|
+
return range;
|
|
8144
|
+
};
|
|
8145
|
+
const createRangeFromSelection = ({
|
|
8146
|
+
selection,
|
|
8147
|
+
spineItem
|
|
8117
8148
|
}) => {
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8149
|
+
if (!spineItem.isReady) return void 0;
|
|
8150
|
+
const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
|
|
8151
|
+
if (!anchorNode || !focusNode) {
|
|
8152
|
+
return void 0;
|
|
8153
|
+
}
|
|
8154
|
+
try {
|
|
8155
|
+
return getRangeFromSelection(
|
|
8156
|
+
{ node: anchorNode, offset: anchorOffset },
|
|
8157
|
+
{ node: focusNode, offset: focusOffset }
|
|
8158
|
+
);
|
|
8159
|
+
} catch (e) {
|
|
8160
|
+
Report.warn("Failed to create range from selection", e, {
|
|
8161
|
+
selection,
|
|
8162
|
+
spineItem
|
|
8163
|
+
});
|
|
8164
|
+
return void 0;
|
|
8165
|
+
}
|
|
8132
8166
|
};
|
|
8133
8167
|
class SelectionTracker extends DestroyableClass {
|
|
8134
8168
|
constructor(document2) {
|
|
@@ -8161,6 +8195,7 @@ const selectionEnhancer = (next) => (options) => {
|
|
|
8161
8195
|
({ itemId, layers, destroy$, destroy }) => {
|
|
8162
8196
|
var _a, _b;
|
|
8163
8197
|
const frame = (_a = layers[0]) == null ? void 0 : _a.element;
|
|
8198
|
+
const itemIndex = reader.spineItemsManager.getSpineItemIndex(itemId) ?? 0;
|
|
8164
8199
|
if (frame instanceof HTMLIFrameElement) {
|
|
8165
8200
|
const frameDoc = frame.contentDocument || ((_b = frame.contentWindow) == null ? void 0 : _b.document);
|
|
8166
8201
|
if (frameDoc) {
|
|
@@ -8172,7 +8207,7 @@ const selectionEnhancer = (next) => (options) => {
|
|
|
8172
8207
|
selectionSubject.next({
|
|
8173
8208
|
document: frameDoc,
|
|
8174
8209
|
selection,
|
|
8175
|
-
|
|
8210
|
+
itemIndex
|
|
8176
8211
|
});
|
|
8177
8212
|
} else {
|
|
8178
8213
|
selectionSubject.next(void 0);
|
|
@@ -8186,7 +8221,7 @@ const selectionEnhancer = (next) => (options) => {
|
|
|
8186
8221
|
{
|
|
8187
8222
|
document: frameDoc,
|
|
8188
8223
|
selection,
|
|
8189
|
-
|
|
8224
|
+
itemIndex
|
|
8190
8225
|
}
|
|
8191
8226
|
]);
|
|
8192
8227
|
})
|
|
@@ -8233,8 +8268,8 @@ const selectionEnhancer = (next) => (options) => {
|
|
|
8233
8268
|
selectionEnd$,
|
|
8234
8269
|
selectionAfterPointerUp$,
|
|
8235
8270
|
lastSelectionOnPointerdown$,
|
|
8236
|
-
|
|
8237
|
-
|
|
8271
|
+
getSelection: () => selectionSubject.getValue(),
|
|
8272
|
+
createRangeFromSelection
|
|
8238
8273
|
},
|
|
8239
8274
|
destroy: () => {
|
|
8240
8275
|
selectionSubject.complete();
|
|
@@ -8294,8 +8329,15 @@ export {
|
|
|
8294
8329
|
SettingsManager3 as SettingsManager,
|
|
8295
8330
|
SpineItem,
|
|
8296
8331
|
createReaderWithEnhancers as createReader,
|
|
8332
|
+
getAttributeValueFromString,
|
|
8333
|
+
getFrameViewportInfo,
|
|
8334
|
+
injectCSS,
|
|
8297
8335
|
isHtmlElement,
|
|
8298
8336
|
isShallowEqual2 as isShallowEqual,
|
|
8337
|
+
removeCSS,
|
|
8338
|
+
upsertCSS,
|
|
8339
|
+
waitForFrameLoad,
|
|
8340
|
+
waitForFrameReady,
|
|
8299
8341
|
waitForSwitch
|
|
8300
8342
|
};
|
|
8301
8343
|
//# sourceMappingURL=index.js.map
|