@internetarchive/bookreader 5.0.0-115 → 5.0.0-117

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.
Files changed (42) hide show
  1. package/BookReader/BookReader.css +44 -18
  2. package/BookReader/BookReader.js +1 -43
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/ia-bookreader-bundle.js +109 -67
  5. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  6. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  7. package/BookReader/plugins/plugin.autoplay.js +1 -1
  8. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  9. package/BookReader/plugins/plugin.chapters.js +2 -2
  10. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  11. package/BookReader/plugins/plugin.experiments.js +1 -1
  12. package/BookReader/plugins/plugin.experiments.js.map +1 -1
  13. package/BookReader/plugins/plugin.iframe.js +1 -1
  14. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  15. package/BookReader/plugins/plugin.iiif.js +1 -1
  16. package/BookReader/plugins/plugin.resume.js +1 -1
  17. package/BookReader/plugins/plugin.search.js +1 -1
  18. package/BookReader/plugins/plugin.search.js.map +1 -1
  19. package/BookReader/plugins/plugin.text_selection.js +63 -1
  20. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  21. package/BookReader/plugins/plugin.translate.js +65 -3
  22. package/BookReader/plugins/plugin.translate.js.map +1 -1
  23. package/BookReader/plugins/plugin.tts.js +1 -1
  24. package/BookReader/plugins/plugin.tts.js.map +1 -1
  25. package/BookReader/plugins/plugin.url.js +1 -1
  26. package/BookReader/plugins/plugin.url.js.map +1 -1
  27. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  28. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  29. package/README.md +3 -1
  30. package/jsconfig.json +2 -3
  31. package/package.json +38 -31
  32. package/src/BookReader.js +24 -20
  33. package/src/css/_TextSelection.scss +51 -18
  34. package/src/plugins/plugin.chapters.js +8 -4
  35. package/src/plugins/plugin.iframe.js +36 -37
  36. package/src/plugins/plugin.text_selection.js +40 -101
  37. package/src/plugins/search/plugin.search.js +4 -8
  38. package/src/plugins/tts/plugin.tts.js +3 -8
  39. package/src/plugins/url/UrlPlugin.js +12 -0
  40. package/src/util/TextSelectionManager.js +221 -154
  41. package/src/util/dom.js +88 -0
  42. package/src/util/generators.js +89 -0
@@ -0,0 +1,88 @@
1
+ // @ts-check
2
+ import { clamp } from '../BookReader/utils.js';
3
+
4
+ /**
5
+ * Walks up the DOM tree starting at (but not including) the given element,
6
+ * returning the nearest ancestor that can actually scroll its overflow.
7
+ * @param {Element} el
8
+ * @return {Element | null}
9
+ */
10
+ export function findScrollableAncestor(el) {
11
+ let current = el.parentElement;
12
+ while (current) {
13
+ const style = getComputedStyle(current);
14
+ const canScrollY = (style.overflowY === 'auto' || style.overflowY === 'scroll') && current.scrollHeight > current.clientHeight;
15
+ const canScrollX = (style.overflowX === 'auto' || style.overflowX === 'scroll') && current.scrollWidth > current.clientWidth;
16
+ if (canScrollY || canScrollX) return current;
17
+ current = current.parentElement;
18
+ }
19
+ return null;
20
+ }
21
+
22
+ /**
23
+ * Computes the scroll offset for a single axis needed to align an element
24
+ * within a container, per the same semantics as scrollIntoView's block/inline.
25
+ * @param {number} elStart
26
+ * @param {number} elEnd
27
+ * @param {number} containerStart
28
+ * @param {number} containerEnd
29
+ * @param {number} currentScroll
30
+ * @param {'start' | 'center' | 'end' | 'nearest'} align
31
+ * @return {number}
32
+ */
33
+ function computeAxisScroll(elStart, elEnd, containerStart, containerEnd, currentScroll, align) {
34
+ let delta = 0;
35
+ switch (align) {
36
+ case 'start':
37
+ delta = elStart - containerStart;
38
+ break;
39
+ case 'end':
40
+ delta = elEnd - containerEnd;
41
+ break;
42
+ case 'center':
43
+ delta = (elStart + elEnd) / 2 - (containerStart + containerEnd) / 2;
44
+ break;
45
+ case 'nearest':
46
+ default:
47
+ if (elStart < containerStart) delta = elStart - containerStart;
48
+ else if (elEnd > containerEnd) delta = elEnd - containerEnd;
49
+ break;
50
+ }
51
+ return currentScroll + delta;
52
+ }
53
+
54
+ /**
55
+ * Scrolls the given element into view within a single scroll container.
56
+ *
57
+ * Unlike the native `Element.scrollIntoView`, this never walks up and scrolls
58
+ * every scrollable ancestor in turn (which can otherwise unexpectedly move
59
+ * the whole page) — it only ever adjusts the scroll position of one
60
+ * container: either the one explicitly passed in, or the nearest scrollable
61
+ * ancestor found via {@link findScrollableAncestor}.
62
+ * @param {Element} el
63
+ * @param {object} [options]
64
+ * @param {'auto' | 'smooth'} [options.behavior]
65
+ * @param {'start' | 'center' | 'end' | 'nearest'} [options.block]
66
+ * @param {'start' | 'center' | 'end' | 'nearest'} [options.inline]
67
+ * @param {Element} [options.scrollContainer] The scrollable element whose
68
+ * scroll position should be adjusted. Defaults to `findScrollableAncestor(el)`.
69
+ */
70
+ export function singleScrollIntoView(el, options) {
71
+ const { block = 'start', inline = 'nearest', behavior = 'auto', scrollContainer = findScrollableAncestor(el) } = options || {};
72
+ if (!scrollContainer) {
73
+ el.scrollIntoView({ block, inline, behavior });
74
+ return;
75
+ }
76
+
77
+ const containerRect = scrollContainer.getBoundingClientRect();
78
+ const elRect = el.getBoundingClientRect();
79
+
80
+ const top = computeAxisScroll(elRect.top, elRect.bottom, containerRect.top, containerRect.bottom, scrollContainer.scrollTop, block);
81
+ const left = computeAxisScroll(elRect.left, elRect.right, containerRect.left, containerRect.right, scrollContainer.scrollLeft, inline);
82
+
83
+ scrollContainer.scrollTo({
84
+ top: clamp(top, 0, scrollContainer.scrollHeight - scrollContainer.clientHeight),
85
+ left: clamp(left, 0, scrollContainer.scrollWidth - scrollContainer.clientWidth),
86
+ behavior,
87
+ });
88
+ }
@@ -0,0 +1,89 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @template T
5
+ * Get the i-th element of an iterable
6
+ * @param {Iterable<T>} iterable
7
+ * @param {number} index
8
+ */
9
+ export function genAt(iterable, index) {
10
+ let i = 0;
11
+ for (const x of iterable) {
12
+ if (i == index) return x;
13
+ i++;
14
+ }
15
+ return undefined;
16
+ }
17
+
18
+ /**
19
+ * @template T
20
+ * Generator version of filter
21
+ * @param {Iterable<T>} iterable
22
+ * @param {function(T): boolean} fn
23
+ */
24
+ export function* genFilter(iterable, fn) {
25
+ for (const x of iterable) {
26
+ if (fn(x)) yield x;
27
+ }
28
+ }
29
+
30
+ /**
31
+ * @template TFrom, TTo
32
+ * Generator version of map
33
+ * @param {Iterable<TFrom>} gen
34
+ * @param {function(TFrom): TTo} fn
35
+ * @returns {Iterable<TTo>}
36
+ */
37
+ export function* genMap(gen, fn) {
38
+ for (const x of gen) yield fn(x);
39
+ }
40
+
41
+ /**
42
+ * @template T
43
+ * Generator that provides a sliding window of 3 elements,
44
+ * prev, current, and next.
45
+ * @param {Iterable<T>} gen
46
+ * @returns {Iterable<[T | undefined, T, T | undefined]>}
47
+ */
48
+ export function* lookAroundWindow(gen) {
49
+ let prev = undefined;
50
+ let cur = undefined;
51
+ let next = undefined;
52
+ for (const x of gen) {
53
+ if (typeof cur !== 'undefined') {
54
+ next = x;
55
+ yield [prev, cur, next];
56
+ }
57
+ prev = cur;
58
+ cur = x;
59
+ next = undefined;
60
+ }
61
+
62
+ if (typeof cur !== 'undefined') {
63
+ yield [prev, cur, next];
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @template T1, T2
69
+ * Lazy zip implementation to avoid importing lodash
70
+ * Expects iterators to be of the same length
71
+ * @param {Iterable<T1>} gen1
72
+ * @param {Iterable<T2>} gen2
73
+ * @returns {Iterable<[T1, T2]>}
74
+ */
75
+ export function* zip(gen1, gen2) {
76
+ const it1 = gen1[Symbol.iterator]();
77
+ const it2 = gen2[Symbol.iterator]();
78
+ while (true) {
79
+ const r1 = it1.next();
80
+ const r2 = it2.next();
81
+ if (r1.done && r2.done) {
82
+ return;
83
+ }
84
+ if (r1.done || r2.done) {
85
+ throw new Error('zip: one of the iterators is done');
86
+ }
87
+ yield [r1.value, r2.value];
88
+ }
89
+ }