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