@readium/navigator-html-injectables 2.3.1 → 2.4.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 +816 -660
- package/dist/index.umd.cjs +21 -10
- package/package.json +1 -1
- package/src/Loader.ts +3 -3
- package/src/helpers/document.ts +4 -1
- package/src/modules/ModuleLibrary.ts +4 -0
- package/src/modules/snapper/CJKVerticalSnapper.ts +322 -0
- package/src/modules/snapper/ColumnSnapper.ts +139 -58
- package/types/src/Loader.d.ts +2 -2
- package/types/src/modules/ModuleLibrary.d.ts +1 -1
- package/types/src/modules/snapper/CJKVerticalSnapper.d.ts +57 -0
- package/types/src/modules/snapper/ColumnSnapper.d.ts +11 -0
|
@@ -41,7 +41,9 @@ export class ColumnSnapper extends Snapper {
|
|
|
41
41
|
// The reason we do this is because when the document is transformed (translate3d),
|
|
42
42
|
// the scrollLeft value is 0 because... reasons. So we have to use the cached value
|
|
43
43
|
// from this.alreadyScrollLeft instead.
|
|
44
|
-
|
|
44
|
+
// Note: for RTL, scrollLeft is negative, so we check !== 0, not > 0.
|
|
45
|
+
const sl = this.doc().scrollLeft;
|
|
46
|
+
return (sl !== 0) ? sl : this.alreadyScrollLeft;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
snapOffset(offset: number) {
|
|
@@ -49,13 +51,35 @@ export class ColumnSnapper extends Snapper {
|
|
|
49
51
|
return value - (value % this.wnd.innerWidth);
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Snap a non-negative normalized offset (distance from document start) to
|
|
56
|
+
* the nearest page boundary. Works identically regardless of reading direction.
|
|
57
|
+
*/
|
|
58
|
+
private snapNormOffset(offset: number): number {
|
|
59
|
+
const value = offset + 1;
|
|
60
|
+
return value - (value % this.wnd.innerWidth);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Normalized scroll position: distance from document start, always in
|
|
65
|
+
* [0, scrollWidth - innerWidth] regardless of reading direction.
|
|
66
|
+
* scrollLeft may be negative depending on the browser — Math.abs() normalizes it.
|
|
67
|
+
*/
|
|
68
|
+
private normScroll(): number {
|
|
69
|
+
const rtl = isRTL(this.wnd);
|
|
70
|
+
const raw = this.doc().scrollLeft || this.alreadyScrollLeft;
|
|
71
|
+
return rtl ? Math.abs(raw) : Math.max(0, this.wnd.scrollX > 0 ? this.wnd.scrollX : raw);
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
reportProgress() {
|
|
53
|
-
// Contrary to ScrollTop, Android slightly adds to scrollX
|
|
54
|
-
// So we do not need to round it up
|
|
55
|
-
const scrollX = this.wnd.scrollX;
|
|
56
75
|
const scrollWidth = this.cachedScrollWidth;
|
|
57
|
-
const
|
|
58
|
-
const
|
|
76
|
+
const viewportWidth = this.wnd.innerWidth;
|
|
77
|
+
const norm = this.normScroll();
|
|
78
|
+
const scrollable = Math.max(1, scrollWidth - viewportWidth);
|
|
79
|
+
|
|
80
|
+
// progress 0 = document start, 1 = document end — same regardless of direction.
|
|
81
|
+
const progress = Math.max(0, Math.min(1, norm / scrollable));
|
|
82
|
+
const viewportEnd = Math.max(0, Math.min(1, (norm + viewportWidth) / scrollWidth));
|
|
59
83
|
this.comms.send("progress", {
|
|
60
84
|
start: progress,
|
|
61
85
|
end: viewportEnd
|
|
@@ -69,11 +93,17 @@ export class ColumnSnapper extends Snapper {
|
|
|
69
93
|
if(this.overscroll !== 0 || this.shakeTimeout !== 0) return;
|
|
70
94
|
const doc = this.doc();
|
|
71
95
|
|
|
72
|
-
|
|
96
|
+
// Bounce toward the boundary that was hit.
|
|
97
|
+
// LTR: end is on the right → bounce-r. RTL: start is on the right (norm≈0),
|
|
98
|
+
// end is on the left → bounce direction flips based on which boundary we're at.
|
|
99
|
+
const atStart = this.normScroll() < 5;
|
|
100
|
+
const bounceClass = isRTL(this.wnd)
|
|
101
|
+
? (atStart ? "readium-bounce-r" : "readium-bounce-l")
|
|
102
|
+
: "readium-bounce-r";
|
|
103
|
+
doc.classList.add(bounceClass);
|
|
73
104
|
const curScrollLeft = this.scrollOffset();
|
|
74
105
|
this.shakeTimeout = this.wnd.setTimeout(() => {
|
|
75
|
-
doc.classList.remove(
|
|
76
|
-
doc.classList.remove("readium-bounce-r");
|
|
106
|
+
doc.classList.remove(bounceClass);
|
|
77
107
|
this.shakeTimeout = 0;
|
|
78
108
|
this.doc().scrollLeft = curScrollLeft;
|
|
79
109
|
}, 150);
|
|
@@ -95,33 +125,37 @@ export class ColumnSnapper extends Snapper {
|
|
|
95
125
|
|
|
96
126
|
// Snaps the current offset to the page width.
|
|
97
127
|
snapCurrentOffset(smooth=false, noprogress=false) {
|
|
98
|
-
const
|
|
128
|
+
const rtl = isRTL(this.wnd);
|
|
99
129
|
const doc = this.doc();
|
|
100
|
-
const cdo = this.dragOffset();
|
|
101
130
|
const columnCount = getColumnCountPerScreen(this.wnd);
|
|
102
|
-
const
|
|
103
|
-
const factor = isRTL(this.wnd) ? -1 : 1;
|
|
104
|
-
const hurdle =
|
|
105
|
-
// The hurdle to overcome in order to change pages
|
|
106
|
-
factor *
|
|
107
|
-
(this.wnd.innerWidth / 3) *
|
|
108
|
-
((factor * cdo) > 0 ? 2 : 1);
|
|
131
|
+
const maxScroll = this.cachedScrollWidth - this.wnd.innerWidth;
|
|
109
132
|
|
|
110
|
-
|
|
133
|
+
// Work in normalized (non-negative, distance-from-start) coordinates
|
|
134
|
+
// so all arithmetic is direction-agnostic.
|
|
135
|
+
const currentNorm = Math.min(Math.max(0, this.normScroll()), maxScroll);
|
|
136
|
+
|
|
137
|
+
// Forward drag: LTR = drag left (cdo > 0), RTL = drag right (cdo < 0).
|
|
138
|
+
// Normalize so that positive = moving forward in reading order.
|
|
139
|
+
const cdo = this.dragOffset();
|
|
140
|
+
const normalizedCdo = rtl ? -cdo : cdo;
|
|
141
|
+
const hurdle = (this.wnd.innerWidth / 3) * (normalizedCdo > 0 ? 2 : 1);
|
|
111
142
|
|
|
112
|
-
const
|
|
143
|
+
const snappedNorm = Math.min(maxScroll, Math.max(0, this.snapNormOffset(currentNorm + hurdle)));
|
|
113
144
|
|
|
114
|
-
|
|
145
|
+
// Convert back to signed scrollLeft for the actual DOM write.
|
|
146
|
+
const so = rtl ? -snappedNorm : snappedNorm;
|
|
147
|
+
const currentScrollLeft = rtl ? -currentNorm : currentNorm;
|
|
115
148
|
|
|
116
|
-
|
|
149
|
+
const direction = so > currentScrollLeft ? "right" : "left";
|
|
150
|
+
this.checkSuspiciousSnap(direction, Math.abs(so - currentScrollLeft));
|
|
151
|
+
|
|
152
|
+
if(smooth && so !== currentScrollLeft) { // Smooth snapping
|
|
117
153
|
this.snappingCancelled = false;
|
|
118
154
|
const position = (start: number, end: number, elapsed: number, period: number) => {
|
|
119
|
-
if (elapsed > period)
|
|
120
|
-
return end;
|
|
121
|
-
}
|
|
155
|
+
if (elapsed > period) return end;
|
|
122
156
|
return start + (end - start) * easeInOutQuad(elapsed / period);
|
|
123
|
-
}
|
|
124
|
-
const period =
|
|
157
|
+
};
|
|
158
|
+
const period = SNAP_DURATION * columnCount;
|
|
125
159
|
let startTime: number;
|
|
126
160
|
const step = (timestamp: number) => {
|
|
127
161
|
if(this.snappingCancelled) return;
|
|
@@ -130,7 +164,7 @@ export class ColumnSnapper extends Snapper {
|
|
|
130
164
|
const elapsed = timestamp - startTime;
|
|
131
165
|
|
|
132
166
|
const lpos = position(this.overscroll, 0, elapsed, period);
|
|
133
|
-
const spos = position(
|
|
167
|
+
const spos = position(currentScrollLeft, so, elapsed, period);
|
|
134
168
|
doc.scrollLeft = spos;
|
|
135
169
|
if(this.overscroll !== 0)
|
|
136
170
|
doc.style.transform = `translate3d(${-lpos}px, 0px, 0px)`;
|
|
@@ -143,7 +177,7 @@ export class ColumnSnapper extends Snapper {
|
|
|
143
177
|
doc.scrollLeft = so;
|
|
144
178
|
if(!noprogress) this.reportProgress();
|
|
145
179
|
}
|
|
146
|
-
}
|
|
180
|
+
};
|
|
147
181
|
this.wnd.requestAnimationFrame(step);
|
|
148
182
|
} else { // Instant snapping
|
|
149
183
|
doc.style.removeProperty("transform");
|
|
@@ -193,18 +227,25 @@ export class ColumnSnapper extends Snapper {
|
|
|
193
227
|
if(this.touchState === ScrollTouchState.MOVE) {
|
|
194
228
|
// Get the horizontal drag distance
|
|
195
229
|
const dragOffset = this.dragOffset();
|
|
196
|
-
const
|
|
197
|
-
|
|
230
|
+
const rtl = isRTL(this.wnd);
|
|
231
|
+
|
|
232
|
+
// Normalize: distance from document start, forward drag is positive.
|
|
233
|
+
const norm = this.normScroll();
|
|
234
|
+
const maxScroll = this.cachedScrollWidth - this.wnd.innerWidth;
|
|
235
|
+
const normalizedDrag = rtl ? -dragOffset : dragOffset;
|
|
236
|
+
|
|
198
237
|
if(this.cachedScrollWidth <= this.wnd.innerWidth) {
|
|
199
238
|
// Only a single page, meaning any swipe triggers next/prev
|
|
200
239
|
this.reportProgress();
|
|
201
|
-
if(
|
|
202
|
-
if(
|
|
203
|
-
} else if(
|
|
240
|
+
if(normalizedDrag > 5) this.comms.send("no_more", undefined);
|
|
241
|
+
if(normalizedDrag < -5) this.comms.send("no_less", undefined);
|
|
242
|
+
} else if(norm < 5 && normalizedDrag < 5) {
|
|
243
|
+
// At document start, tried to go backward
|
|
204
244
|
this.alreadyScrollLeft = 0;
|
|
205
245
|
this.comms.send("no_less", undefined);
|
|
206
|
-
} else if((
|
|
207
|
-
|
|
246
|
+
} else if((maxScroll - norm) < 5 && normalizedDrag > 5) {
|
|
247
|
+
// At document end, tried to go forward
|
|
248
|
+
this.alreadyScrollLeft = rtl ? -maxScroll : maxScroll;
|
|
208
249
|
this.comms.send("no_more", undefined);
|
|
209
250
|
}
|
|
210
251
|
|
|
@@ -235,16 +276,22 @@ export class ColumnSnapper extends Snapper {
|
|
|
235
276
|
|
|
236
277
|
const dro = this.dragOffset();
|
|
237
278
|
const newpos = this.alreadyScrollLeft + dro;
|
|
238
|
-
|
|
279
|
+
|
|
280
|
+
// For RTL, scrollLeft is in [-(scrollWidth - innerWidth), 0].
|
|
281
|
+
// For LTR, scrollLeft is in [0, scrollWidth - innerWidth].
|
|
282
|
+
const minScrollLeft = isRTL(this.wnd) ? -(this.cachedScrollWidth - this.wnd.innerWidth) : 0;
|
|
283
|
+
const maxScrollLeft = isRTL(this.wnd) ? 0 : (this.cachedScrollWidth - this.wnd.innerWidth);
|
|
284
|
+
|
|
285
|
+
if(newpos < minScrollLeft) {
|
|
239
286
|
this.overscroll = newpos;
|
|
240
287
|
this.doc().style.transform = `translate3d(${-this.overscroll}px, 0px, 0px)`;
|
|
241
|
-
} else if(
|
|
288
|
+
} else if(newpos > maxScrollLeft) {
|
|
242
289
|
this.overscroll = newpos;
|
|
243
290
|
this.doc().style.transform = `translate3d(${-newpos}px, 0px, 0px)`;
|
|
244
291
|
} else {
|
|
245
292
|
this.overscroll = 0;
|
|
246
293
|
this.doc().style.removeProperty("transform");
|
|
247
|
-
this.doc().scrollLeft =
|
|
294
|
+
this.doc().scrollLeft = newpos;
|
|
248
295
|
}
|
|
249
296
|
}
|
|
250
297
|
private readonly onTouchMover = this.onTouchMove.bind(this);
|
|
@@ -371,10 +418,19 @@ export class ColumnSnapper extends Snapper {
|
|
|
371
418
|
ack(true);
|
|
372
419
|
});
|
|
373
420
|
|
|
421
|
+
// LTR only — snapOffset only works with non-negative values.
|
|
374
422
|
const scrollToOffset = (offset: number): boolean => {
|
|
375
423
|
const oldScrollLeft = this.doc().scrollLeft;
|
|
376
|
-
this.doc().scrollLeft = this.snapOffset(offset);
|
|
424
|
+
this.doc().scrollLeft = this.snapOffset(offset);
|
|
425
|
+
return oldScrollLeft !== this.doc().scrollLeft;
|
|
426
|
+
}
|
|
377
427
|
|
|
428
|
+
// RTL: offset is normalized (non-negative, 0 = start, scrollable = end).
|
|
429
|
+
// Snaps to page boundary and sets scrollLeft = -snappedNorm.
|
|
430
|
+
const rtlScrollToNorm = (norm: number): boolean => {
|
|
431
|
+
const oldScrollLeft = this.doc().scrollLeft;
|
|
432
|
+
const snapped = this.snapNormOffset(Math.max(0, Math.min(this.cachedScrollWidth - wnd.innerWidth, norm)));
|
|
433
|
+
this.doc().scrollLeft = -snapped;
|
|
378
434
|
return oldScrollLeft !== this.doc().scrollLeft;
|
|
379
435
|
}
|
|
380
436
|
|
|
@@ -393,10 +449,13 @@ export class ColumnSnapper extends Snapper {
|
|
|
393
449
|
}
|
|
394
450
|
this.wnd.requestAnimationFrame(() => {
|
|
395
451
|
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
396
|
-
const
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
452
|
+
const scrollable = this.cachedScrollWidth - wnd.innerWidth;
|
|
453
|
+
const norm = scrollable * position;
|
|
454
|
+
if (isRTL(wnd)) {
|
|
455
|
+
this.doc().scrollLeft = -this.snapNormOffset(norm);
|
|
456
|
+
} else {
|
|
457
|
+
this.doc().scrollLeft = this.snapOffset(norm);
|
|
458
|
+
}
|
|
400
459
|
this.reportProgress();
|
|
401
460
|
deselect(this.wnd);
|
|
402
461
|
ack(true);
|
|
@@ -410,7 +469,11 @@ export class ColumnSnapper extends Snapper {
|
|
|
410
469
|
return;
|
|
411
470
|
}
|
|
412
471
|
this.wnd.requestAnimationFrame(() => {
|
|
413
|
-
|
|
472
|
+
if (isRTL(wnd)) {
|
|
473
|
+
this.doc().scrollLeft = -this.snapNormOffset(element.getBoundingClientRect().left + wnd.scrollX);
|
|
474
|
+
} else {
|
|
475
|
+
this.doc().scrollLeft = this.snapOffset(element.getBoundingClientRect().left + wnd.scrollX);
|
|
476
|
+
}
|
|
414
477
|
this.reportProgress();
|
|
415
478
|
deselect(this.wnd);
|
|
416
479
|
ack(true);
|
|
@@ -441,7 +504,11 @@ export class ColumnSnapper extends Snapper {
|
|
|
441
504
|
return;
|
|
442
505
|
}
|
|
443
506
|
this.wnd.requestAnimationFrame(() => {
|
|
444
|
-
|
|
507
|
+
if (isRTL(wnd)) {
|
|
508
|
+
this.doc().scrollLeft = -this.snapNormOffset(r.getBoundingClientRect().left + wnd.scrollX);
|
|
509
|
+
} else {
|
|
510
|
+
this.doc().scrollLeft = this.snapOffset(r.getBoundingClientRect().left + wnd.scrollX);
|
|
511
|
+
}
|
|
445
512
|
this.reportProgress();
|
|
446
513
|
deselect(this.wnd);
|
|
447
514
|
ack(true);
|
|
@@ -449,12 +516,18 @@ export class ColumnSnapper extends Snapper {
|
|
|
449
516
|
});
|
|
450
517
|
|
|
451
518
|
comms.register("go_end", ColumnSnapper.moduleName, (_, ack) => {
|
|
452
|
-
const factor = isRTL(wnd) ? -1 : 1;
|
|
453
519
|
this.wnd.requestAnimationFrame(() => {
|
|
454
520
|
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
455
|
-
|
|
456
|
-
if(
|
|
457
|
-
|
|
521
|
+
let snappedFinal: number;
|
|
522
|
+
if (isRTL(wnd)) {
|
|
523
|
+
// RTL: end is the leftmost position, using normalized snapping first
|
|
524
|
+
snappedFinal = -this.snapNormOffset(this.cachedScrollWidth - wnd.innerWidth);
|
|
525
|
+
} else {
|
|
526
|
+
// LTR: end is scrollWidth (browser clamps to scrollWidth - innerWidth)
|
|
527
|
+
snappedFinal = this.snapOffset(this.cachedScrollWidth);
|
|
528
|
+
}
|
|
529
|
+
if(this.doc().scrollLeft === snappedFinal) return ack(false);
|
|
530
|
+
this.doc().scrollLeft = snappedFinal;
|
|
458
531
|
this.reportProgress();
|
|
459
532
|
deselect(this.wnd);
|
|
460
533
|
ack(true);
|
|
@@ -474,11 +547,15 @@ export class ColumnSnapper extends Snapper {
|
|
|
474
547
|
comms.register("go_prev", ColumnSnapper.moduleName, (_, ack) => {
|
|
475
548
|
this.wnd.requestAnimationFrame(() => {
|
|
476
549
|
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
550
|
+
let change: boolean;
|
|
551
|
+
if (isRTL(wnd)) {
|
|
552
|
+
// RTL: go_prev = toward document start = decreasing norm = scrollLeft toward 0
|
|
553
|
+
change = rtlScrollToNorm(this.normScroll() - wnd.innerWidth);
|
|
554
|
+
} else {
|
|
555
|
+
change = scrollToOffset(wnd.scrollX - wnd.innerWidth);
|
|
556
|
+
}
|
|
557
|
+
this.reportProgress();
|
|
480
558
|
if(change) {
|
|
481
|
-
this.reportProgress();
|
|
482
559
|
deselect(this.wnd);
|
|
483
560
|
this.checkSuspiciousSnap("left", this.wnd.innerWidth);
|
|
484
561
|
}
|
|
@@ -489,11 +566,15 @@ export class ColumnSnapper extends Snapper {
|
|
|
489
566
|
comms.register("go_next", ColumnSnapper.moduleName, (_, ack) => {
|
|
490
567
|
this.wnd.requestAnimationFrame(() => {
|
|
491
568
|
this.cachedScrollWidth = this.doc().scrollWidth!;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
569
|
+
let change: boolean;
|
|
570
|
+
if (isRTL(wnd)) {
|
|
571
|
+
// RTL: go_next = toward document end = increasing norm = scrollLeft more negative
|
|
572
|
+
change = rtlScrollToNorm(this.normScroll() + wnd.innerWidth);
|
|
573
|
+
} else {
|
|
574
|
+
change = scrollToOffset(wnd.scrollX + wnd.innerWidth);
|
|
575
|
+
}
|
|
576
|
+
this.reportProgress();
|
|
495
577
|
if(change) {
|
|
496
|
-
this.reportProgress();
|
|
497
578
|
deselect(this.wnd);
|
|
498
579
|
this.checkSuspiciousSnap("right", this.wnd.innerWidth);
|
|
499
580
|
}
|
package/types/src/Loader.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ReadiumWindow } from "./helpers/dom";
|
|
2
|
-
import { ModuleName } from "./modules";
|
|
1
|
+
import { ReadiumWindow } from "./helpers/dom.ts";
|
|
2
|
+
import { ModuleName } from "./modules/index.ts";
|
|
3
3
|
/**
|
|
4
4
|
* The Module loader. Handles initialization of the HTML injectables
|
|
5
5
|
* in the target Window, which could be an IFrame, or the current window).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ModuleDerived } from "./Module.ts";
|
|
2
|
-
export type ModuleName = "setup" | "snapper" | "column_snapper" | "scroll_snapper" | "webpub_snapper" | "fixed_setup" | "decorator" | "reflowable_setup" | "peripherals" | "webpub_setup" | "print_protection";
|
|
2
|
+
export type ModuleName = "setup" | "snapper" | "column_snapper" | "scroll_snapper" | "cjk_vertical_snapper" | "webpub_snapper" | "fixed_setup" | "decorator" | "reflowable_setup" | "peripherals" | "webpub_setup" | "print_protection";
|
|
3
3
|
export declare const FXLModules: ModuleName[];
|
|
4
4
|
export declare const ReflowableModules: ModuleName[];
|
|
5
5
|
export declare const WebPubModules: ModuleName[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Comms } from "../../comms/comms.ts";
|
|
2
|
+
import { ReadiumWindow } from "../../helpers/dom.ts";
|
|
3
|
+
import { ModuleName } from "../ModuleLibrary.ts";
|
|
4
|
+
import { Snapper } from "./Snapper.ts";
|
|
5
|
+
import { BaseSuspiciousActivityEvent } from "../Peripherals.ts";
|
|
6
|
+
export interface SuspiciousCJKScrollingEvent extends BaseSuspiciousActivityEvent {
|
|
7
|
+
type: "suspicious_scrolling";
|
|
8
|
+
scrollDelta: number;
|
|
9
|
+
scrollDirection: "left" | "right";
|
|
10
|
+
targetElement: {
|
|
11
|
+
tagName: string;
|
|
12
|
+
} | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Snapper for CJK vertical writing (writing-mode: vertical-rl).
|
|
16
|
+
*
|
|
17
|
+
* In vertical-rl, content overflows on the X axis, flowing from right (start)
|
|
18
|
+
* to left (end). This snapper is the horizontal counterpart of ScrollSnapper:
|
|
19
|
+
* it tracks scrollLeft / scrollWidth / innerWidth and reports progress
|
|
20
|
+
* accordingly.
|
|
21
|
+
*
|
|
22
|
+
* Progress convention:
|
|
23
|
+
* scrollLeft = 0 (right edge, document start) → progress 0
|
|
24
|
+
* scrollLeft = ±(scrollWidth − clientWidth) → progress 1 (document end, left edge)
|
|
25
|
+
*
|
|
26
|
+
* All modern browsers use negative scrollLeft for vertical-rl (range: [−scrollable, 0]).
|
|
27
|
+
* Read it with Math.abs() to get a non-negative offset from document start.
|
|
28
|
+
* Write absolute positions as negative values (go_progression, go_end).
|
|
29
|
+
* Write relative adjustments as viewport-coordinate deltas (go_id, go_text) — this
|
|
30
|
+
* is sign-agnostic and works regardless of browser convention.
|
|
31
|
+
*
|
|
32
|
+
* go_next / go_prev always return false so that the navigator advances to the
|
|
33
|
+
* next or previous spine item — this snapper intentionally provides free
|
|
34
|
+
* horizontal scroll without intra-resource page fragmentation.
|
|
35
|
+
*/
|
|
36
|
+
export declare class CJKVerticalSnapper extends Snapper {
|
|
37
|
+
static readonly moduleName: ModuleName;
|
|
38
|
+
private wnd;
|
|
39
|
+
private comms;
|
|
40
|
+
private resizeObserver;
|
|
41
|
+
private patternAnalyzer;
|
|
42
|
+
private lastScrollTime;
|
|
43
|
+
private isScrollProtectionEnabled;
|
|
44
|
+
private initialScrollHandled;
|
|
45
|
+
private isScrolling;
|
|
46
|
+
private lastScrollLeft;
|
|
47
|
+
private isResizing;
|
|
48
|
+
private resizeDebounce;
|
|
49
|
+
private doc;
|
|
50
|
+
/** Total horizontally scrollable distance (magnitude). */
|
|
51
|
+
private scrollable;
|
|
52
|
+
private reportProgress;
|
|
53
|
+
private handleScroll;
|
|
54
|
+
private enableScrollProtection;
|
|
55
|
+
mount(wnd: ReadiumWindow, comms: Comms): boolean;
|
|
56
|
+
unmount(wnd: ReadiumWindow, comms: Comms): boolean;
|
|
57
|
+
}
|
|
@@ -22,6 +22,17 @@ export declare class ColumnSnapper extends Snapper {
|
|
|
22
22
|
private doc;
|
|
23
23
|
private scrollOffset;
|
|
24
24
|
snapOffset(offset: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Snap a non-negative normalized offset (distance from document start) to
|
|
27
|
+
* the nearest page boundary. Works identically regardless of reading direction.
|
|
28
|
+
*/
|
|
29
|
+
private snapNormOffset;
|
|
30
|
+
/**
|
|
31
|
+
* Normalized scroll position: distance from document start, always in
|
|
32
|
+
* [0, scrollWidth - innerWidth] regardless of reading direction.
|
|
33
|
+
* scrollLeft may be negative depending on the browser — Math.abs() normalizes it.
|
|
34
|
+
*/
|
|
35
|
+
private normScroll;
|
|
25
36
|
reportProgress(): void;
|
|
26
37
|
private shakeTimeout;
|
|
27
38
|
shake(): void;
|