@readium/navigator-html-injectables 1.3.2 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +853 -1032
- package/dist/index.umd.cjs +8 -8
- package/package.json +7 -8
- package/src/comms/keys.ts +2 -0
- package/src/helpers/color.ts +114 -0
- package/src/helpers/css.ts +37 -0
- package/src/helpers/document.ts +42 -21
- package/src/helpers/dom.ts +30 -3
- package/src/modules/Decorator.ts +3 -5
- package/src/modules/Peripherals.ts +1 -1
- package/src/modules/setup/ReflowableSetup.ts +12 -1
- package/src/modules/snapper/ColumnSnapper.ts +35 -9
- package/src/modules/snapper/ScrollSnapper.ts +24 -17
- package/types/src/comms/keys.d.ts +1 -1
- package/types/src/helpers/color.d.ts +16 -0
- package/types/src/helpers/css.d.ts +6 -0
- package/types/src/helpers/document.d.ts +11 -2
- package/types/src/modules/snapper/ScrollSnapper.d.ts +3 -3
- package/src/helpers/scrollSnapperHelper.ts +0 -43
package/src/helpers/css.ts
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
import { ReadiumWindow } from "./dom";
|
|
2
2
|
|
|
3
|
+
export function getProperties(wnd: ReadiumWindow) {
|
|
4
|
+
const cssProperties: { [key: string]: string } = {};
|
|
5
|
+
|
|
6
|
+
const rootStyle = wnd.document.documentElement.style;
|
|
7
|
+
|
|
8
|
+
for (const prop in wnd.document.documentElement.style) {
|
|
9
|
+
// We check if the property belongs to the CSSStyleDeclaration instance
|
|
10
|
+
// We also ensure that the property is a numeric index (indicating an inline style)
|
|
11
|
+
if (
|
|
12
|
+
Object.hasOwn(rootStyle, prop) &&
|
|
13
|
+
!Number.isNaN(Number.parseInt(prop))
|
|
14
|
+
) {
|
|
15
|
+
cssProperties[rootStyle[prop]] = rootStyle.getPropertyValue(rootStyle[prop]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return cssProperties;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function updateProperties(wnd: ReadiumWindow, properties: { [key: string]: string }) {
|
|
23
|
+
const currentProperties = getProperties(wnd);
|
|
24
|
+
|
|
25
|
+
// Remove properties
|
|
26
|
+
Object.keys(currentProperties).forEach((key) => {
|
|
27
|
+
if (!properties.hasOwnProperty(key)) {
|
|
28
|
+
removeProperty(wnd, key);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Update properties
|
|
33
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
34
|
+
if (currentProperties[key] !== value) {
|
|
35
|
+
setProperty(wnd, key, value);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
3
40
|
// Easy way to get a CSS property
|
|
4
41
|
export function getProperty(wnd: ReadiumWindow, key: string) {
|
|
5
42
|
return wnd.document.documentElement.style.getPropertyValue(key);
|
package/src/helpers/document.ts
CHANGED
|
@@ -12,32 +12,53 @@ export function getColumnCountPerScreen(wnd: ReadiumWindow) {
|
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Returns the "content height" of an element, which is its clientHeight
|
|
17
|
+
* minus any vertical padding.
|
|
18
|
+
*
|
|
19
|
+
* @param el - The element to measure.
|
|
20
|
+
*/
|
|
21
|
+
export function getContentHeight(el: Element) {
|
|
22
|
+
const cStyle = getComputedStyle(el);
|
|
23
|
+
const paddingTop = parseFloat(cStyle.paddingTop || "0");
|
|
24
|
+
const paddingBottom = parseFloat(cStyle.paddingBottom || "0");
|
|
25
|
+
return el.clientHeight - paddingTop - paddingBottom;
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
29
|
+
* We have to make sure that the total number of columns is a multiple
|
|
30
|
+
* of the number of columns per screen.
|
|
31
|
+
* Otherwise it causes snapping and page turning issues.
|
|
32
|
+
* To fix this, we insert and remove blank virtual columns at the end of the resource.
|
|
18
33
|
*/
|
|
19
34
|
export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
const virtualCols = wnd.document.querySelectorAll("div[id^='readium-virtual-page']");
|
|
36
|
+
// Remove first so that we don’t end up with an incorrect scrollWidth
|
|
37
|
+
// Even when removing their width we risk having an incorrect scrollWidth
|
|
38
|
+
// so removing them entirely is the most robust solution
|
|
39
|
+
for (const virtualCol of virtualCols) {
|
|
40
|
+
virtualCol.remove();
|
|
41
|
+
}
|
|
42
|
+
const colCount = getColumnCountPerScreen(wnd);
|
|
43
|
+
const documentWidth = wnd.document.scrollingElement!.scrollWidth;
|
|
44
|
+
const neededColCount = Math.ceil(documentWidth / wnd.innerWidth) * colCount;
|
|
45
|
+
const totalColCount = Math.round((documentWidth / wnd.innerWidth) * colCount);
|
|
46
|
+
const needed = colCount === 1 ? 0 : neededColCount - totalColCount;
|
|
47
|
+
if (needed > 0) {
|
|
48
|
+
for (let i = 0; i < needed; i++) {
|
|
49
|
+
const virtualCol = wnd.document.createElement("div");
|
|
50
|
+
virtualCol.setAttribute("id", `readium-virtual-page-${ i }`);
|
|
51
|
+
virtualCol.dataset.readium = "true";
|
|
52
|
+
if (CSS.supports("break-before", "column")) {
|
|
37
53
|
virtualCol.style.breakBefore = "column";
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
} else if (CSS.supports("break-inside", "avoid-column")) {
|
|
55
|
+
virtualCol.style.breakInside = "avoid-column";
|
|
56
|
+
virtualCol.style.height = getContentHeight(wnd.document.documentElement) + "px";
|
|
57
|
+
} else {
|
|
58
|
+
virtualCol.style.height = getContentHeight(wnd.document.documentElement) + "px";
|
|
40
59
|
}
|
|
60
|
+
virtualCol.innerHTML = "​"; // zero-width space
|
|
61
|
+
wnd.document.body.appendChild(virtualCol);
|
|
41
62
|
}
|
|
42
63
|
}
|
|
43
64
|
}
|
package/src/helpers/dom.ts
CHANGED
|
@@ -68,13 +68,19 @@ export function nearestInteractiveElement(element: Element): Element | null {
|
|
|
68
68
|
/// Returns the `Locator` object to the first block element that is visible on
|
|
69
69
|
/// the screen.
|
|
70
70
|
export function findFirstVisibleLocator(wnd: ReadiumWindow, scrolling: boolean) {
|
|
71
|
-
const element = findElement(wnd, wnd.document.body, scrolling);
|
|
71
|
+
const element = findElement(wnd, wnd.document.body, scrolling) as HTMLElement;
|
|
72
|
+
|
|
73
|
+
// Use only the allowed selectors to generate the cssSelector and avoid a crash
|
|
74
|
+
const cssSelector = wnd._readium_cssSelectorGenerator.getCssSelector(element, {
|
|
75
|
+
selectors: ["tag", "id", "class", "nthchild", "nthoftype", "attribute"]
|
|
76
|
+
});
|
|
77
|
+
|
|
72
78
|
return new Locator({
|
|
73
79
|
href: "#",
|
|
74
80
|
type: "application/xhtml+xml",
|
|
75
81
|
locations: new LocatorLocations({
|
|
76
82
|
otherLocations: new Map([
|
|
77
|
-
["cssSelector",
|
|
83
|
+
["cssSelector", cssSelector]
|
|
78
84
|
])
|
|
79
85
|
}),
|
|
80
86
|
text: new LocatorText({
|
|
@@ -87,6 +93,9 @@ function findElement(wnd: ReadiumWindow, rootElement: Element, scrolling: boolea
|
|
|
87
93
|
for (var i = 0; i < rootElement.children.length; i++) {
|
|
88
94
|
const child = rootElement.children[i];
|
|
89
95
|
if (!shouldIgnoreElement(child) && isElementVisible(wnd, child, scrolling)) {
|
|
96
|
+
// Once we get a fully visible element, return it
|
|
97
|
+
if (isElementFullyVisible(wnd, child)) return child;
|
|
98
|
+
// if the parent is not fully visible, search in the childs
|
|
90
99
|
return findElement(wnd, child, scrolling);
|
|
91
100
|
}
|
|
92
101
|
}
|
|
@@ -111,11 +120,29 @@ function isElementVisible(wnd: ReadiumWindow, element: Element, scrolling: boole
|
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Check if an element is fully visible in the current viewport.
|
|
125
|
+
* @param wnd Window instance to operate on
|
|
126
|
+
* @param element Element to check visibility of
|
|
127
|
+
* @returns True if the element is fully visible, false otherwise
|
|
128
|
+
*/
|
|
129
|
+
function isElementFullyVisible(wnd: ReadiumWindow, element: Element): boolean {
|
|
130
|
+
const rect = element.getBoundingClientRect();
|
|
131
|
+
const isFullyVisible =
|
|
132
|
+
rect.top >= 0 &&
|
|
133
|
+
rect.left >= 0 &&
|
|
134
|
+
rect.bottom <= wnd.innerHeight &&
|
|
135
|
+
rect.right <= wnd.innerWidth;
|
|
136
|
+
return isFullyVisible;
|
|
137
|
+
}
|
|
138
|
+
|
|
114
139
|
function shouldIgnoreElement(element: Element) {
|
|
115
140
|
const elStyle = getComputedStyle(element);
|
|
116
141
|
if (elStyle) {
|
|
117
142
|
const display = elStyle.getPropertyValue("display");
|
|
118
|
-
|
|
143
|
+
// Added list-item as it is a common display property for list items
|
|
144
|
+
// TODO: Check if there are other display properties that should be ignored/considered
|
|
145
|
+
if (display != "block" && display != "list-item") {
|
|
119
146
|
return true;
|
|
120
147
|
}
|
|
121
148
|
// Cannot be relied upon, because web browser engine reports invisible when out of view in
|
package/src/modules/Decorator.ts
CHANGED
|
@@ -4,12 +4,9 @@ import { Module } from "./Module";
|
|
|
4
4
|
import { rangeFromLocator } from "../helpers/locator";
|
|
5
5
|
import { ModuleName } from "./ModuleLibrary";
|
|
6
6
|
import { Rect, getClientRectsNoOverlap } from "../helpers/rect";
|
|
7
|
-
import { ResizeObserver as Polyfill } from '@juggle/resize-observer';
|
|
8
7
|
import { getProperty } from "../helpers/css";
|
|
9
8
|
import { ReadiumWindow } from "../helpers/dom";
|
|
10
|
-
|
|
11
|
-
// Necessary for iOS 13 and below
|
|
12
|
-
const ResizeObserver = window.ResizeObserver || Polyfill;
|
|
9
|
+
import { isDarkColor } from "../helpers/color";
|
|
13
10
|
|
|
14
11
|
export enum Width {
|
|
15
12
|
Wrap = "wrap", // Smallest width fitting the CSS border box.
|
|
@@ -254,7 +251,8 @@ class DecorationGroup {
|
|
|
254
251
|
// template.innerHTML = item.decoration.element.trim();
|
|
255
252
|
// TODO more styles logic
|
|
256
253
|
|
|
257
|
-
const isDarkMode = getProperty(this.wnd, "--USER__appearance") === "readium-night-on"
|
|
254
|
+
const isDarkMode = getProperty(this.wnd, "--USER__appearance") === "readium-night-on" ||
|
|
255
|
+
isDarkColor(getProperty(this.wnd, "--USER__backgroundColor"));
|
|
258
256
|
|
|
259
257
|
template.innerHTML = `
|
|
260
258
|
<div
|
|
@@ -71,7 +71,7 @@ export class Peripherals extends Module {
|
|
|
71
71
|
targetFrameSrc: this.wnd.location.href,
|
|
72
72
|
targetElement: (event.target as Element).outerHTML,
|
|
73
73
|
interactiveElement: nearestInteractiveElement(event.target as Element)?.outerHTML,
|
|
74
|
-
cssSelector: this.wnd._readium_cssSelectorGenerator.getCssSelector(event.target),
|
|
74
|
+
cssSelector: this.wnd._readium_cssSelectorGenerator.getCssSelector(event.target as Element),
|
|
75
75
|
} as FrameClickEvent);
|
|
76
76
|
|
|
77
77
|
this.pointerMoved = false;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Comms } from "../../comms/comms";
|
|
2
2
|
import { Setup } from "./Setup";
|
|
3
|
-
import { removeProperty, setProperty } from "../../helpers/css";
|
|
3
|
+
import { getProperties, removeProperty, setProperty, updateProperties } from "../../helpers/css";
|
|
4
4
|
import { ReadiumWindow } from "../../helpers/dom";
|
|
5
5
|
|
|
6
6
|
const VIEWPORT_META_TAG_ID = "readium-viewport";
|
|
@@ -35,6 +35,17 @@ export class ReflowableSetup extends Setup {
|
|
|
35
35
|
target: wnd
|
|
36
36
|
} as any); // Cheat!
|
|
37
37
|
|
|
38
|
+
comms.register("get_properties", ReflowableSetup.moduleName, (_, ack) => {
|
|
39
|
+
getProperties(wnd);
|
|
40
|
+
ack(true);
|
|
41
|
+
});
|
|
42
|
+
comms.register("update_properties", ReflowableSetup.moduleName, (data, ack) => {
|
|
43
|
+
// In order to keep the viewport width that is added in the setup itself,
|
|
44
|
+
// and don’t have EpubNavigator concerned with this, we need to add it there
|
|
45
|
+
(data as { [key: string]: string })["--RS__viewportWidth"] = `${ wnd.innerWidth }px`;
|
|
46
|
+
updateProperties(wnd, data as { [key: string]: string });
|
|
47
|
+
ack(true);
|
|
48
|
+
})
|
|
38
49
|
comms.register("set_property", ReflowableSetup.moduleName, (data, ack) => {
|
|
39
50
|
const kv = data as string[];
|
|
40
51
|
setProperty(wnd, kv[0], kv[1]);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ResizeObserver as Polyfill } from '@juggle/resize-observer';
|
|
2
1
|
import { Comms } from "../../comms";
|
|
3
2
|
import { Snapper } from "./Snapper";
|
|
4
3
|
import { getColumnCountPerScreen, isRTL, appendVirtualColumnIfNeeded } from "../../helpers/document";
|
|
@@ -272,18 +271,43 @@ export class ColumnSnapper extends Snapper {
|
|
|
272
271
|
`;
|
|
273
272
|
wnd.document.head.appendChild(d);
|
|
274
273
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
})
|
|
274
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
275
|
+
wnd.requestAnimationFrame(() => {
|
|
276
|
+
wnd && appendVirtualColumnIfNeeded(wnd);
|
|
277
|
+
});
|
|
278
|
+
this.onWidthChange();
|
|
279
|
+
});
|
|
281
280
|
this.resizeObserver.observe(wnd.document.body);
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
|
|
282
|
+
this.mutationObserver = new MutationObserver((mutations) => {
|
|
283
|
+
for (const mutation of mutations) {
|
|
284
|
+
// We have to check it’s not onTouchMove + snapOffset setting transforms
|
|
285
|
+
if (mutation.target === this.wnd.document.documentElement) {
|
|
286
|
+
const oldValue = mutation.oldValue as string;
|
|
287
|
+
const newValue = (mutation.target as HTMLElement).getAttribute("style") as string;
|
|
288
|
+
const transformRegex = /transform\s*:\s*([^;]+)/;
|
|
289
|
+
const oldValueTransform = oldValue?.match(transformRegex);
|
|
290
|
+
const newValueTransform = newValue?.match(transformRegex);
|
|
291
|
+
if (
|
|
292
|
+
(!oldValueTransform && !newValueTransform) ||
|
|
293
|
+
(oldValueTransform && !newValueTransform) ||
|
|
294
|
+
(oldValueTransform && newValueTransform && oldValueTransform[1] !== newValueTransform[1])
|
|
295
|
+
) {
|
|
296
|
+
wnd.requestAnimationFrame(() => {
|
|
297
|
+
wnd && appendVirtualColumnIfNeeded(wnd);
|
|
298
|
+
});
|
|
299
|
+
this.onWidthChange();
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
wnd.requestAnimationFrame(() => this.cachedScrollWidth = this.doc().scrollWidth!);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
284
305
|
});
|
|
285
306
|
wnd.frameElement && this.mutationObserver.observe(wnd.frameElement, {attributes: true, attributeFilter: ["style"]});
|
|
286
307
|
this.mutationObserver.observe(wnd.document, {attributes: true, attributeFilter: ["style"]});
|
|
308
|
+
// For cases the resizeObserver is not able to detect cos body is not resizing despite colCount,
|
|
309
|
+
// we need to check the syle attribute on the documentElement (ReadiumCSS props)
|
|
310
|
+
this.mutationObserver.observe(wnd.document.documentElement, {attributes: true, attributeFilter: ["style"]});
|
|
287
311
|
|
|
288
312
|
const scrollToOffset = (offset: number): boolean => {
|
|
289
313
|
const oldScrollLeft = this.doc().scrollLeft;
|
|
@@ -387,6 +411,7 @@ export class ColumnSnapper extends Snapper {
|
|
|
387
411
|
|
|
388
412
|
comms.register("go_prev", ColumnSnapper.moduleName, (_, ack) => {
|
|
389
413
|
this.wnd.requestAnimationFrame(() => {
|
|
414
|
+
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
390
415
|
const offset = wnd.scrollX - wnd.innerWidth;
|
|
391
416
|
const minOffset = isRTL(wnd) ? - (this.cachedScrollWidth - wnd.innerWidth) : 0;
|
|
392
417
|
const change = scrollToOffset(Math.max(offset, minOffset));
|
|
@@ -400,6 +425,7 @@ export class ColumnSnapper extends Snapper {
|
|
|
400
425
|
|
|
401
426
|
comms.register("go_next", ColumnSnapper.moduleName, (_, ack) => {
|
|
402
427
|
this.wnd.requestAnimationFrame(() => {
|
|
428
|
+
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
403
429
|
const offset = wnd.scrollX + wnd.innerWidth;
|
|
404
430
|
const maxOffset = isRTL(wnd) ? 0 : this.cachedScrollWidth - wnd.innerWidth;
|
|
405
431
|
const change = scrollToOffset(Math.min(offset, maxOffset));
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Locator, LocatorLocations, LocatorText } from "@readium/shared";
|
|
2
2
|
import { Comms } from "../../comms";
|
|
3
3
|
import { ReadiumWindow, deselect, findFirstVisibleLocator } from "../../helpers/dom";
|
|
4
|
-
import { AnchorObserver, helperCreateAnchorElements, helperRemoveAnchorElements } from '../../helpers/scrollSnapperHelper';
|
|
5
4
|
import { ModuleName } from "../ModuleLibrary";
|
|
6
5
|
import { Snapper } from "./Snapper";
|
|
7
6
|
import { rangeFromLocator } from "../../helpers/locator";
|
|
@@ -12,28 +11,28 @@ export class ScrollSnapper extends Snapper {
|
|
|
12
11
|
static readonly moduleName: ModuleName = "scroll_snapper";
|
|
13
12
|
private wnd!: ReadiumWindow;
|
|
14
13
|
private comms!: Comms;
|
|
14
|
+
private resizeObserver!: ResizeObserver;
|
|
15
|
+
private isScrolling = false;
|
|
15
16
|
|
|
16
17
|
private doc() {
|
|
17
18
|
return this.wnd.document.scrollingElement as HTMLElement;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
private createAnchorElements = () => {
|
|
21
|
-
helperCreateAnchorElements(this.doc());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private removeAnchorElements = () => {
|
|
25
|
-
helperRemoveAnchorElements(this.doc());
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
private createCustomElement = () => {
|
|
29
|
-
customElements.get("anchor-observer") ||
|
|
30
|
-
customElements.define("anchor-observer", AnchorObserver);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
21
|
private reportProgress(data: { progress: number, reference: number }) {
|
|
34
22
|
this.comms.send("progress", data);
|
|
35
23
|
}
|
|
36
24
|
|
|
25
|
+
private handleScroll = () => {
|
|
26
|
+
if (!this.isScrolling) {
|
|
27
|
+
this.isScrolling = true;
|
|
28
|
+
this.wnd.requestAnimationFrame(() => {
|
|
29
|
+
const progress = this.doc().scrollTop / this.doc().offsetHeight;
|
|
30
|
+
this.reportProgress({ progress: progress, reference: this.wnd.innerHeight / this.doc().scrollHeight });
|
|
31
|
+
this.isScrolling = false;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
37
36
|
mount(wnd: ReadiumWindow, comms: Comms): boolean {
|
|
38
37
|
this.wnd = wnd;
|
|
39
38
|
this.comms = comms;
|
|
@@ -55,6 +54,15 @@ export class ScrollSnapper extends Snapper {
|
|
|
55
54
|
`;
|
|
56
55
|
wnd.document.head.appendChild(style);
|
|
57
56
|
|
|
57
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
58
|
+
this.comms.ready && this.handleScroll();
|
|
59
|
+
});
|
|
60
|
+
this.resizeObserver.observe(wnd.document.body);
|
|
61
|
+
|
|
62
|
+
wnd.addEventListener("scroll", this.handleScroll, {
|
|
63
|
+
passive: true
|
|
64
|
+
});
|
|
65
|
+
|
|
58
66
|
comms.register("go_progression", ScrollSnapper.moduleName, (data, ack) => {
|
|
59
67
|
const position = data as number;
|
|
60
68
|
|
|
@@ -158,14 +166,13 @@ export class ScrollSnapper extends Snapper {
|
|
|
158
166
|
});
|
|
159
167
|
|
|
160
168
|
comms.log("ScrollSnapper Mounted");
|
|
161
|
-
this.createCustomElement();
|
|
162
|
-
this.createAnchorElements();
|
|
163
169
|
return true;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
unmount(wnd: ReadiumWindow, comms: Comms): boolean {
|
|
167
173
|
comms.unregisterAll(ScrollSnapper.moduleName);
|
|
168
|
-
this.
|
|
174
|
+
this.resizeObserver.disconnect();
|
|
175
|
+
if (this.handleScroll) wnd.removeEventListener("scroll", this.handleScroll);
|
|
169
176
|
wnd.document.getElementById(SCROLL_SNAPPER_STYLE_ID)?.remove();
|
|
170
177
|
comms.log("ScrollSnapper Unmounted");
|
|
171
178
|
return true;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type CommsEventKey = "_pong" | "_unhandled" | "_ack" | "log" | "error" | "click" | "tap" | "tap_more" | "no_more" | "no_less" | "swipe" | "progress" | "first_visible_locator" | "text_selected" | "media_play" | "media_pause";
|
|
2
|
-
export type CommsCommandKey = "_ping" | "go_prev" | "go_next" | "go_id" | "go_text" | "go_end" | "go_start" | "go_progression" | "set_property" | "remove_property" | "first_visible_locator" | "decorate" | "protect" | "unprotect" | "unfocus" | "focus" | "activate" | "shake";
|
|
2
|
+
export type CommsCommandKey = "_ping" | "go_prev" | "go_next" | "go_id" | "go_text" | "go_end" | "go_start" | "go_progression" | "get_properties" | "update_properties" | "set_property" | "remove_property" | "first_visible_locator" | "decorate" | "protect" | "unprotect" | "unfocus" | "focus" | "activate" | "shake";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const colorToRgba: (color: string) => {
|
|
2
|
+
r: number;
|
|
3
|
+
g: number;
|
|
4
|
+
b: number;
|
|
5
|
+
a: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const getLuminance: (color: {
|
|
8
|
+
r: number;
|
|
9
|
+
g: number;
|
|
10
|
+
b: number;
|
|
11
|
+
a: number;
|
|
12
|
+
}) => number;
|
|
13
|
+
export declare const isDarkColor: (color: string) => boolean;
|
|
14
|
+
export declare const isLightColor: (color: string) => boolean;
|
|
15
|
+
export declare const checkContrast: (color1: string, color2: string) => number;
|
|
16
|
+
export declare const ensureContrast: (color1: string, color2: string, contrast?: number) => string[];
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ReadiumWindow } from "./dom";
|
|
2
|
+
export declare function getProperties(wnd: ReadiumWindow): {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function updateProperties(wnd: ReadiumWindow, properties: {
|
|
6
|
+
[key: string]: string;
|
|
7
|
+
}): void;
|
|
2
8
|
export declare function getProperty(wnd: ReadiumWindow, key: string): string;
|
|
3
9
|
export declare function setProperty(wnd: ReadiumWindow, key: string, value: string): void;
|
|
4
10
|
export declare function removeProperty(wnd: ReadiumWindow, key: string): void;
|
|
@@ -2,7 +2,16 @@ import { ReadiumWindow } from "./dom";
|
|
|
2
2
|
export declare function isRTL(wnd: ReadiumWindow): boolean;
|
|
3
3
|
export declare function getColumnCountPerScreen(wnd: ReadiumWindow): number;
|
|
4
4
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
* Returns the "content height" of an element, which is its clientHeight
|
|
6
|
+
* minus any vertical padding.
|
|
7
|
+
*
|
|
8
|
+
* @param el - The element to measure.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getContentHeight(el: Element): number;
|
|
11
|
+
/**
|
|
12
|
+
* We have to make sure that the total number of columns is a multiple
|
|
13
|
+
* of the number of columns per screen.
|
|
14
|
+
* Otherwise it causes snapping and page turning issues.
|
|
15
|
+
* To fix this, we insert and remove blank virtual columns at the end of the resource.
|
|
7
16
|
*/
|
|
8
17
|
export declare function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): void;
|
|
@@ -6,11 +6,11 @@ export declare class ScrollSnapper extends Snapper {
|
|
|
6
6
|
static readonly moduleName: ModuleName;
|
|
7
7
|
private wnd;
|
|
8
8
|
private comms;
|
|
9
|
+
private resizeObserver;
|
|
10
|
+
private isScrolling;
|
|
9
11
|
private doc;
|
|
10
|
-
private createAnchorElements;
|
|
11
|
-
private removeAnchorElements;
|
|
12
|
-
private createCustomElement;
|
|
13
12
|
private reportProgress;
|
|
13
|
+
private handleScroll;
|
|
14
14
|
mount(wnd: ReadiumWindow, comms: Comms): boolean;
|
|
15
15
|
unmount(wnd: ReadiumWindow, comms: Comms): boolean;
|
|
16
16
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const iframeAnchors = {
|
|
2
|
-
top: "js-iframe-reader-top-anchor",
|
|
3
|
-
bottom: "js-iframe-reader-bottom-anchor",
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
export class AnchorObserver extends HTMLElement {
|
|
7
|
-
connectedCallback() {
|
|
8
|
-
this.setAttribute("aria-hidden", "true");
|
|
9
|
-
this.style.setProperty("display", "block", "important");
|
|
10
|
-
this.style.setProperty("padding", "0", "important");
|
|
11
|
-
this.style.setProperty("margin", "0", "important");
|
|
12
|
-
this.style.setProperty("visibility", "hidden", "important");
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function helperCreateAnchorElements(iframeElement: HTMLElement) {
|
|
17
|
-
const body = iframeElement.getElementsByTagName("body")[0];
|
|
18
|
-
const anchorTop = document.createElement("anchor-observer");
|
|
19
|
-
const anchorBottom = document.createElement("anchor-observer");
|
|
20
|
-
anchorTop.dataset.readium = "true";
|
|
21
|
-
anchorBottom.dataset.readium = "true";
|
|
22
|
-
|
|
23
|
-
anchorTop?.setAttribute("id", iframeAnchors.top);
|
|
24
|
-
anchorTop?.style.setProperty("height", "115px", "important");
|
|
25
|
-
|
|
26
|
-
anchorBottom?.setAttribute("id", iframeAnchors.bottom);
|
|
27
|
-
anchorBottom?.style.setProperty("height", "80px", "important");
|
|
28
|
-
|
|
29
|
-
body?.insertBefore(anchorTop, body.firstChild);
|
|
30
|
-
body?.appendChild(anchorBottom);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function helperRemoveAnchorElements(iframeElement: HTMLElement) {
|
|
34
|
-
const body = iframeElement.getElementsByTagName("body")[0];
|
|
35
|
-
const anchorTop = body?.querySelector(`#${iframeAnchors.top}`);
|
|
36
|
-
const anchorBottom = body?.querySelector(`#${iframeAnchors.bottom}`);
|
|
37
|
-
if (anchorTop) {
|
|
38
|
-
anchorTop.parentElement?.removeChild(anchorTop);
|
|
39
|
-
}
|
|
40
|
-
if (anchorBottom) {
|
|
41
|
-
anchorBottom.parentElement?.removeChild(anchorBottom);
|
|
42
|
-
}
|
|
43
|
-
}
|