@internetarchive/bookreader 5.0.0-93 → 5.0.0-95

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 (224) hide show
  1. package/.github/workflows/npm-publish.yml +2 -12
  2. package/BookReaderDemo/IADemoBr.js +1 -24
  3. package/BookReaderDemo/demo-internetarchive.html +1 -0
  4. package/CHANGELOG.md +19 -1
  5. package/README.md +0 -2
  6. package/package.json +8 -4
  7. package/scripts/postversion.js +3 -2
  8. package/scripts/preversion.js +3 -1
  9. package/scripts/version.js +4 -6
  10. package/src/BookNavigator/book-navigator.js +38 -12
  11. package/src/BookNavigator/downloads/downloads-provider.js +2 -2
  12. package/src/BookNavigator/search/search-provider.js +5 -5
  13. package/src/BookNavigator/search/search-results.js +1 -1
  14. package/src/BookNavigator/sharing.js +2 -2
  15. package/src/BookNavigator/viewable-files.js +2 -2
  16. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +3 -3
  17. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +2 -2
  18. package/src/BookReader.js +57 -31
  19. package/src/assets/images/hypothesis.ico +0 -0
  20. package/src/css/_TextSelection.scss +3 -1
  21. package/src/plugins/plugin.autoplay.js +3 -3
  22. package/src/plugins/plugin.chapters.js +2 -2
  23. package/src/plugins/plugin.experiments.js +294 -0
  24. package/src/plugins/plugin.iiif.js +1 -1
  25. package/src/plugins/plugin.text_selection.js +112 -1
  26. package/src/plugins/search/view.js +5 -5
  27. package/src/plugins/tts/plugin.tts.js +3 -3
  28. package/src/plugins/url/plugin.url.js +2 -2
  29. package/tests/e2e/autoplay.test.js +1 -1
  30. package/tests/e2e/base.test.js +4 -4
  31. package/tests/e2e/helpers/base.js +2 -2
  32. package/tests/e2e/models/BookReader.js +1 -1
  33. package/tests/e2e/rightToLeft.test.js +4 -4
  34. package/tests/e2e/viewmode.test.js +2 -2
  35. package/tests/jest/BookNavigator/book-navigator.test.js +0 -13
  36. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +1 -1
  37. package/tests/jest/BookNavigator/downloads/downloads.test.js +1 -1
  38. package/tests/jest/BookNavigator/search/search-provider.test.js +5 -5
  39. package/tests/jest/BookReader.test.js +10 -10
  40. package/tests/jest/plugins/plugin.autoplay.test.js +6 -6
  41. package/tests/jest/plugins/plugin.chapters.test.js +2 -2
  42. package/tests/jest/plugins/plugin.resume.test.js +13 -13
  43. package/tests/jest/plugins/plugin.text_selection.test.js +155 -24
  44. package/tests/jest/plugins/search/plugin.search.test.js +7 -7
  45. package/tests/jest/plugins/search/plugin.search.view.test.js +8 -8
  46. package/tests/jest/plugins/search/utils.js +1 -1
  47. package/tests/jest/plugins/tts/PageChunkIterator.test.js +2 -2
  48. package/tests/jest/plugins/url/UrlPlugin.test.js +1 -1
  49. package/webpack.config.js +8 -3
  50. package/BookReader/BookReader.css +0 -2250
  51. package/BookReader/BookReader.js +0 -3
  52. package/BookReader/BookReader.js.LICENSE.txt +0 -72
  53. package/BookReader/BookReader.js.map +0 -1
  54. package/BookReader/ia-bookreader-bundle.js +0 -1782
  55. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +0 -7
  56. package/BookReader/ia-bookreader-bundle.js.map +0 -1
  57. package/BookReader/icons/1up.svg +0 -1
  58. package/BookReader/icons/2up.svg +0 -1
  59. package/BookReader/icons/advance.svg +0 -3
  60. package/BookReader/icons/chevron-right.svg +0 -1
  61. package/BookReader/icons/close-circle-dark.svg +0 -1
  62. package/BookReader/icons/close-circle.svg +0 -1
  63. package/BookReader/icons/fullscreen.svg +0 -1
  64. package/BookReader/icons/fullscreen_exit.svg +0 -1
  65. package/BookReader/icons/hamburger.svg +0 -1
  66. package/BookReader/icons/left-arrow.svg +0 -1
  67. package/BookReader/icons/magnify-minus.svg +0 -1
  68. package/BookReader/icons/magnify-plus.svg +0 -1
  69. package/BookReader/icons/magnify.svg +0 -1
  70. package/BookReader/icons/pause.svg +0 -1
  71. package/BookReader/icons/play.svg +0 -1
  72. package/BookReader/icons/playback-speed.svg +0 -1
  73. package/BookReader/icons/read-aloud.svg +0 -1
  74. package/BookReader/icons/review.svg +0 -3
  75. package/BookReader/icons/thumbnails.svg +0 -1
  76. package/BookReader/icons/voice.svg +0 -1
  77. package/BookReader/icons/volume-full.svg +0 -1
  78. package/BookReader/images/BRicons.png +0 -0
  79. package/BookReader/images/BRicons.svg +0 -5
  80. package/BookReader/images/BRicons_ia.png +0 -0
  81. package/BookReader/images/back_pages.png +0 -0
  82. package/BookReader/images/book_bottom_icon.png +0 -0
  83. package/BookReader/images/book_down_icon.png +0 -0
  84. package/BookReader/images/book_left_icon.png +0 -0
  85. package/BookReader/images/book_leftmost_icon.png +0 -0
  86. package/BookReader/images/book_right_icon.png +0 -0
  87. package/BookReader/images/book_rightmost_icon.png +0 -0
  88. package/BookReader/images/book_top_icon.png +0 -0
  89. package/BookReader/images/book_up_icon.png +0 -0
  90. package/BookReader/images/books_graphic.svg +0 -1
  91. package/BookReader/images/booksplit.png +0 -0
  92. package/BookReader/images/control_pause_icon.png +0 -0
  93. package/BookReader/images/control_play_icon.png +0 -0
  94. package/BookReader/images/embed_icon.png +0 -0
  95. package/BookReader/images/icon-home-ia.png +0 -0
  96. package/BookReader/images/icon_OL-logo-xs.png +0 -0
  97. package/BookReader/images/icon_alert-xs.png +0 -0
  98. package/BookReader/images/icon_book.svg +0 -1
  99. package/BookReader/images/icon_bookmark.svg +0 -1
  100. package/BookReader/images/icon_close-pop.png +0 -0
  101. package/BookReader/images/icon_download.png +0 -0
  102. package/BookReader/images/icon_gear.svg +0 -1
  103. package/BookReader/images/icon_hamburger.svg +0 -1
  104. package/BookReader/images/icon_home.png +0 -0
  105. package/BookReader/images/icon_home.svg +0 -1
  106. package/BookReader/images/icon_home_ia.png +0 -0
  107. package/BookReader/images/icon_indicator.png +0 -0
  108. package/BookReader/images/icon_info.svg +0 -1
  109. package/BookReader/images/icon_one_page.svg +0 -1
  110. package/BookReader/images/icon_pause.svg +0 -1
  111. package/BookReader/images/icon_play.svg +0 -1
  112. package/BookReader/images/icon_playback-rate.svg +0 -1
  113. package/BookReader/images/icon_return.png +0 -0
  114. package/BookReader/images/icon_search_button.svg +0 -1
  115. package/BookReader/images/icon_share.svg +0 -1
  116. package/BookReader/images/icon_skip-ahead.svg +0 -1
  117. package/BookReader/images/icon_skip-back.svg +0 -2
  118. package/BookReader/images/icon_speaker.svg +0 -1
  119. package/BookReader/images/icon_speaker_open.svg +0 -1
  120. package/BookReader/images/icon_thumbnails.svg +0 -1
  121. package/BookReader/images/icon_toc.svg +0 -1
  122. package/BookReader/images/icon_two_pages.svg +0 -1
  123. package/BookReader/images/icon_zoomer.png +0 -0
  124. package/BookReader/images/loading.gif +0 -0
  125. package/BookReader/images/logo_icon.png +0 -0
  126. package/BookReader/images/marker_chap-off.png +0 -0
  127. package/BookReader/images/marker_chap-off.svg +0 -1
  128. package/BookReader/images/marker_chap-off_ia.png +0 -0
  129. package/BookReader/images/marker_chap-on.png +0 -0
  130. package/BookReader/images/marker_chap-on.svg +0 -1
  131. package/BookReader/images/marker_srch-on.svg +0 -1
  132. package/BookReader/images/marker_srchchap-off.png +0 -0
  133. package/BookReader/images/marker_srchchap-on.png +0 -0
  134. package/BookReader/images/nav_control-dn.png +0 -0
  135. package/BookReader/images/nav_control-dn_ia.png +0 -0
  136. package/BookReader/images/nav_control-up.png +0 -0
  137. package/BookReader/images/nav_control-up_ia.png +0 -0
  138. package/BookReader/images/nav_control.png +0 -0
  139. package/BookReader/images/one_page_mode_icon.png +0 -0
  140. package/BookReader/images/paper-badge.png +0 -0
  141. package/BookReader/images/print_icon.png +0 -0
  142. package/BookReader/images/progressbar.gif +0 -0
  143. package/BookReader/images/right_edges.png +0 -0
  144. package/BookReader/images/slider.png +0 -0
  145. package/BookReader/images/slider_ia.png +0 -0
  146. package/BookReader/images/thumbnail_mode_icon.png +0 -0
  147. package/BookReader/images/transparent.png +0 -0
  148. package/BookReader/images/two_page_mode_icon.png +0 -0
  149. package/BookReader/images/unviewable_page.png +0 -0
  150. package/BookReader/images/zoom_in_icon.png +0 -0
  151. package/BookReader/images/zoom_out_icon.png +0 -0
  152. package/BookReader/jquery-3.js +0 -2
  153. package/BookReader/jquery-3.js.LICENSE.txt +0 -24
  154. package/BookReader/plugins/plugin.archive_analytics.js +0 -2
  155. package/BookReader/plugins/plugin.archive_analytics.js.map +0 -1
  156. package/BookReader/plugins/plugin.autoplay.js +0 -2
  157. package/BookReader/plugins/plugin.autoplay.js.map +0 -1
  158. package/BookReader/plugins/plugin.chapters.js +0 -26
  159. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +0 -1
  160. package/BookReader/plugins/plugin.chapters.js.map +0 -1
  161. package/BookReader/plugins/plugin.iframe.js +0 -2
  162. package/BookReader/plugins/plugin.iframe.js.map +0 -1
  163. package/BookReader/plugins/plugin.iiif.js +0 -2
  164. package/BookReader/plugins/plugin.iiif.js.map +0 -1
  165. package/BookReader/plugins/plugin.resume.js +0 -2
  166. package/BookReader/plugins/plugin.resume.js.map +0 -1
  167. package/BookReader/plugins/plugin.search.js +0 -3
  168. package/BookReader/plugins/plugin.search.js.LICENSE.txt +0 -1
  169. package/BookReader/plugins/plugin.search.js.map +0 -1
  170. package/BookReader/plugins/plugin.text_selection.js +0 -3
  171. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +0 -1
  172. package/BookReader/plugins/plugin.text_selection.js.map +0 -1
  173. package/BookReader/plugins/plugin.tts.js +0 -3
  174. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +0 -29
  175. package/BookReader/plugins/plugin.tts.js.map +0 -1
  176. package/BookReader/plugins/plugin.url.js +0 -2
  177. package/BookReader/plugins/plugin.url.js.map +0 -1
  178. package/BookReader/plugins/plugin.vendor-fullscreen.js +0 -2
  179. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +0 -1
  180. package/BookReader/webcomponents-bundle.js +0 -3
  181. package/BookReader/webcomponents-bundle.js.LICENSE.txt +0 -9
  182. package/BookReader/webcomponents-bundle.js.map +0 -1
  183. package/src/BookReader/BookModel.js +0 -554
  184. package/src/BookReader/DragScrollable.js +0 -233
  185. package/src/BookReader/ImageCache.js +0 -149
  186. package/src/BookReader/Mode1Up.js +0 -108
  187. package/src/BookReader/Mode1UpLit.js +0 -388
  188. package/src/BookReader/Mode2Up.js +0 -105
  189. package/src/BookReader/Mode2UpLit.js +0 -777
  190. package/src/BookReader/ModeCoordinateSpace.js +0 -29
  191. package/src/BookReader/ModeSmoothZoom.js +0 -312
  192. package/src/BookReader/ModeThumb.js +0 -342
  193. package/src/BookReader/Navbar/Navbar.js +0 -355
  194. package/src/BookReader/PageContainer.js +0 -169
  195. package/src/BookReader/ReduceSet.js +0 -26
  196. package/src/BookReader/Toolbar/Toolbar.js +0 -362
  197. package/src/BookReader/events.js +0 -19
  198. package/src/BookReader/options.js +0 -382
  199. package/src/BookReader/utils/HTMLDimensionsCacher.js +0 -44
  200. package/src/BookReader/utils/ScrollClassAdder.js +0 -31
  201. package/src/BookReader/utils/SelectionObserver.js +0 -45
  202. package/src/BookReader/utils/classes.js +0 -36
  203. package/src/BookReader/utils.js +0 -300
  204. package/tests/jest/BookReader/BookModel.test.js +0 -372
  205. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +0 -263
  206. package/tests/jest/BookReader/ImageCache.test.js +0 -150
  207. package/tests/jest/BookReader/Mode1UpLit.test.js +0 -73
  208. package/tests/jest/BookReader/Mode2Up.test.js +0 -98
  209. package/tests/jest/BookReader/Mode2UpLit.test.js +0 -190
  210. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +0 -16
  211. package/tests/jest/BookReader/ModeSmoothZoom.test.js +0 -218
  212. package/tests/jest/BookReader/ModeThumb.test.js +0 -71
  213. package/tests/jest/BookReader/Navbar/Navbar.test.js +0 -182
  214. package/tests/jest/BookReader/PageContainer.test.js +0 -238
  215. package/tests/jest/BookReader/ReduceSet.test.js +0 -38
  216. package/tests/jest/BookReader/Toolbar/Toolbar.test.js +0 -26
  217. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +0 -59
  218. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +0 -49
  219. package/tests/jest/BookReader/utils/SelectionObserver.test.js +0 -57
  220. package/tests/jest/BookReader/utils/classes.test.js +0 -88
  221. package/tests/jest/BookReader/utils.test.js +0 -250
  222. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
  223. /package/{.testcaferc.js → .testcaferc.cjs} +0 -0
  224. /package/{babel.config.js → babel.config.cjs} +0 -0
@@ -1,300 +0,0 @@
1
- /**
2
- * Bind mouse handlers
3
- * Disable mouse click to avoid selected/highlighted page images
4
- * @param {JQuery} jObject
5
- */
6
- export function disableSelect(jObject) {
7
- // $$$ check here for right-click and don't disable. Also use jQuery style
8
- // for stopping propagation. See https://bugs.edge.launchpad.net/gnubook/+bug/362626
9
- jObject.bind('mousedown', () => false);
10
- // Special hack for IE7
11
- jObject[0].onselectstart = () => false;
12
- }
13
-
14
- /**
15
- * @param {number} value
16
- * @param {number} min
17
- * @param {number} max
18
- * @return {number}
19
- */
20
- export function clamp(value, min, max) {
21
- return Math.min(Math.max(value, min), max);
22
- }
23
-
24
- /**
25
- * Given value and maximum, calculate a percentage suitable for CSS
26
- * @param {number} value
27
- * @param {number} max
28
- * @return {string}
29
- */
30
- export function cssPercentage(value, max) {
31
- return ((value / max) * 100) + '%';
32
- }
33
-
34
- /**
35
- * @param {*} value
36
- * @param {Array} array
37
- * @return {boolean}
38
- */
39
- export function notInArray(value, array) {
40
- return !array.includes(value);
41
- }
42
-
43
- /**
44
- * Determines the active element, going into shadow doms.
45
- * @return {Element}
46
- */
47
- export function getActiveElement(doc = document, recurseShadowDom = true) {
48
- const activeElement = doc.activeElement;
49
- if (recurseShadowDom && activeElement?.shadowRoot) {
50
- return getActiveElement(activeElement.shadowRoot, true);
51
- }
52
- return activeElement;
53
- }
54
-
55
- /** Check if an input field/textarea is active. Also checks shadow DOMs. */
56
- export function isInputActive(doc = document) {
57
- const activeEl = getActiveElement(doc);
58
- return activeEl?.tagName == "INPUT" || activeEl?.tagName == "TEXTAREA";
59
- }
60
-
61
- /**
62
- * @param {HTMLIFrameElement} iframe
63
- * @return {Document}
64
- */
65
- export function getIFrameDocument(iframe) {
66
- // Adapted from http://xkr.us/articles/dom/iframe-document/
67
- const outer = iframe.contentWindow || iframe.contentDocument;
68
- return outer.document || outer;
69
- }
70
-
71
- /**
72
- * @param {string} str
73
- * @return {string}
74
- */
75
- export function escapeHTML(str) {
76
- return str.replace(/&/g,'&')
77
- .replace(/>/g,'>')
78
- .replace(/</g,'&lt;')
79
- .replace(/"/g,'&quot;');
80
- }
81
-
82
- /**
83
- * Decodes a URI component and converts '+' to ' '
84
- * @param {string} value
85
- * @return {string}
86
- */
87
- export function decodeURIComponentPlus(value) {
88
- return decodeURIComponent(value).replace(/\+/g, ' ');
89
- }
90
-
91
- /**
92
- * Encodes a URI component and converts ' ' to '+'
93
- * @param {string|number|boolean} value
94
- * @return {string};
95
- */
96
- export function encodeURIComponentPlus(value) {
97
- return encodeURIComponent(value).replace(/%20/g, '+');
98
- }
99
-
100
- /**
101
- * @template {Function} T
102
- * Returns a function, that, as long as it continues to be invoked, will not
103
- * be triggered. The function will be called after it stops being called for
104
- * N milliseconds. If `immediate` is passed, trigger the function on the
105
- * leading edge, instead of the trailing.
106
- * @see https://davidwalsh.name/javascript-debounce-function
107
- *
108
- * @param {T} func
109
- * @param {number} wait
110
- * @param {boolean} immediate
111
- * @return {T}
112
- */
113
- export function debounce(func, wait, immediate) {
114
- let timeout;
115
- return function() {
116
- const context = this;
117
- const args = arguments;
118
- const later = () => {
119
- timeout = null;
120
- if (!immediate) func.apply(context, args);
121
- };
122
- const callNow = immediate && !timeout;
123
- clearTimeout(timeout);
124
- timeout = setTimeout(later, wait);
125
- if (callNow) func.apply(context, args);
126
- };
127
- }
128
-
129
- /**
130
- * @template T
131
- * Throttle function
132
- * @see https://remysharp.com/2010/07/21/throttling-function-calls
133
- * @param {T} fn
134
- * @param {number} threshold
135
- * @param {boolean} delay
136
- * @return {T}
137
- */
138
- export function throttle(fn, threshold, delay) {
139
- threshold || (threshold = 250);
140
- let last;
141
- let deferTimer;
142
- if (delay) last = +new Date;
143
- return function () {
144
- const context = this;
145
- const now = +new Date;
146
- const args = arguments;
147
- if (last && now < last + threshold) {
148
- // hold on to it
149
- clearTimeout(deferTimer);
150
- deferTimer = setTimeout(() => {
151
- last = now;
152
- fn.apply(context, args);
153
- }, threshold);
154
- } else {
155
- last = now;
156
- fn.apply(context, args);
157
- }
158
- };
159
- }
160
-
161
- /**
162
- * FIXME we need a better way to do this :/ This is not automatically poly-filled by
163
- * core-js https://github.com/zloirock/core-js/issues/354
164
- * @param {Window} window
165
- */
166
- export function polyfillCustomEvent(window) {
167
- if (typeof window.CustomEvent === "function") return false;
168
- window.CustomEvent = PolyfilledCustomEvent;
169
- }
170
-
171
- /**
172
- * https://caniuse.com/customevent has issues on older browsers where it can't be
173
- * called as a constructor, so we have to use older methods.
174
- * @param {String} eventName
175
- * @return {CustomEvent}
176
- */
177
- export function PolyfilledCustomEvent(eventName, {bubbles = false, cancelable = false, detail = null} = {}) {
178
- const event = document.createEvent('CustomEvent');
179
- event.initCustomEvent(eventName, bubbles, cancelable, detail);
180
- return event;
181
- }
182
-
183
- /*
184
- * Returns the number pixels something should be rendered at to be ~1n on the users
185
- * screen when measured with a ruler.
186
- */
187
- export function calcScreenDPI() {
188
- const el = document.createElement('div');
189
- el.style.width = '1in';
190
- document.body.appendChild(el);
191
- const dpi = el.offsetWidth;
192
- document.body.removeChild(el);
193
-
194
- // Do you believe in magic... numbers? We tested on some devices, and the displayed
195
- // size of `width: 1in` was less than desired. On @pezvi's mac, it was ~75% ; on
196
- // @cdrini's laptop it was ~85%. Since we want to avoid things appearing too small,
197
- // let's just use a multiplier of 1.25
198
- const screenDPI = dpi * 1.25;
199
- // This will return 0 in testing; never want it to be 0!
200
- return screenDPI == 0 ? 100 : screenDPI;
201
- }
202
-
203
- /**
204
- * @param {number[]} nums
205
- * @returns {number}
206
- */
207
- export function sum(nums) {
208
- return nums.reduce((cur, acc) => cur + acc, 0);
209
- }
210
-
211
- /**
212
- * @template T
213
- * @param {Generator<T>} gen
214
- * @returns {T[]}
215
- */
216
- export function genToArray(gen) {
217
- const result = [];
218
- for (const item of gen) {
219
- result.push(item);
220
- }
221
- return result;
222
- }
223
-
224
- /**
225
- * Check if arrays contain the same elements. Does reference comparison.
226
- * @param {Array} arr1
227
- * @param {Array} arr2
228
- */
229
- export function arrEquals(arr1, arr2) {
230
- return arr1.length == arr2.length && arr1.every((x, i) => x == arr2[i]);
231
- }
232
-
233
- /**
234
- * Check if array has changed; namely to be used with lit's property.hasChanged
235
- * @param {Array} [arr1]
236
- * @param {Array} [arr2]
237
- */
238
- export function arrChanged(arr1, arr2) {
239
- return arr1 && arr2 && !arrEquals(arr1, arr2);
240
- }
241
-
242
- /**
243
- * Waits the provided number of ms and then resolves with a promise
244
- * @param {number} ms
245
- **/
246
- export async function sleep(ms) {
247
- return new Promise(resolve => setTimeout(resolve, ms));
248
- }
249
-
250
- /**
251
- * @template T
252
- * @param {function(): T} fn
253
- * @param {Object} options
254
- * @param {function(T): boolean} [options.until]
255
- * @return {T | undefined}
256
- */
257
- export async function poll(fn, { step = 50, timeout = 500, until = val => Boolean(val), _sleep = sleep } = {}) {
258
- const startTime = Date.now();
259
- while (Date.now() - startTime < timeout) {
260
- const result = fn();
261
- if (until(result)) return result;
262
- await _sleep(step);
263
- }
264
- }
265
-
266
- /**
267
- * Convert a EventTarget style event into a promise
268
- * @param {EventTarget} target
269
- * @param {string} eventType
270
- * @return {Promise<Event>}
271
- */
272
- export function promisifyEvent(target, eventType) {
273
- return new Promise(res => {
274
- const resolver = ev => {
275
- target.removeEventListener(eventType, resolver);
276
- res(ev);
277
- };
278
- target.addEventListener(eventType, resolver);
279
- });
280
- }
281
-
282
- /**
283
- * Escapes regex special characters in a string. Allows for safe usage in regexes.
284
- * Src: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions
285
- * @param {string} string
286
- * @returns {string}
287
- */
288
- export function escapeRegExp(string) {
289
- return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
290
- }
291
-
292
- /**
293
- * @param {number | 'fast' | 'slow' | string} speed
294
- * Parsing of the jquery animation speed; see https://api.jquery.com/animate/
295
- */
296
- export function parseAnimationSpeed(speed) {
297
- if (speed === 'slow') return 600;
298
- if (speed === 'fast') return 200;
299
- return parseInt(speed, 10);
300
- }
@@ -1,372 +0,0 @@
1
- import sinon from 'sinon';
2
- import { deepCopy } from '../utils.js';
3
- import { BookModel } from '@/src/BookReader/BookModel.js';
4
- import { NAMED_REDUCE_SETS } from '@/src/BookReader/ReduceSet.js';
5
- /** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
6
-
7
- afterEach(() => {
8
- sinon.restore();
9
- });
10
-
11
- /** @type {BookReaderOptions['data']} */
12
- const SAMPLE_DATA = [
13
- [
14
- { width: 123, height: 123, uri: 'https://archive.org/image0.jpg', pageNum: '1' },
15
- ],
16
- [
17
- { width: 123, height: 123, uri: 'https://archive.org/image1.jpg', pageNum: '2' },
18
- { width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '3' },
19
- ],
20
- [
21
- { width: 123, height: 123, uri: 'https://archive.org/image3.jpg', pageNum: '4' },
22
- ],
23
- ];
24
-
25
- describe('getMedianPageSizeInches', () => {
26
- test('handles single page data', () => {
27
- const bm = new BookModel({ data: SAMPLE_DATA.slice(0, 1), options: {ppi: 10} });
28
- expect(bm.getMedianPageSizeInches()).toEqual({ width: 12.3, height: 12.3 });
29
- });
30
-
31
- test('handles odd pages data', () => {
32
- const sizes = [
33
- {width: 300, height: 2200},
34
- {width: 200, height: 2100},
35
- {width: 100, height: 2300},
36
- ];
37
- const data = deepCopy(SAMPLE_DATA);
38
- delete data[2];
39
- Object.assign(data[0][0], sizes[0]);
40
- Object.assign(data[1][0], sizes[1]);
41
- Object.assign(data[1][1], sizes[2]);
42
- const bm = new BookModel({ data, options: {ppi: 10} });
43
- expect(bm.getMedianPageSizeInches()).toEqual({ width: 20, height: 220 });
44
- });
45
-
46
-
47
- test('handles even pages data', () => {
48
- const sizes = [
49
- {width: 300, height: 2200},
50
- {width: 200, height: 2100},
51
- {width: 100, height: 2300},
52
- {width: 400, height: 2400},
53
- ];
54
- const data = deepCopy(SAMPLE_DATA);
55
- Object.assign(data[0][0], sizes[0]);
56
- Object.assign(data[1][0], sizes[1]);
57
- Object.assign(data[1][1], sizes[2]);
58
- Object.assign(data[2][0], sizes[3]);
59
- const bm = new BookModel({ data, options: {ppi: 10} });
60
- expect(bm.getMedianPageSizeInches()).toEqual({ width: 30, height: 230 });
61
- });
62
-
63
- test('does not lexicographic sort for median', () => {
64
- const sizes = [
65
- {width: 100, height: 100},
66
- {width: 20, height: 20},
67
- {width: 30, height: 30},
68
- ];
69
- const data = deepCopy(SAMPLE_DATA);
70
- delete data[2];
71
- Object.assign(data[0][0], sizes[0]);
72
- Object.assign(data[1][0], sizes[1]);
73
- Object.assign(data[1][1], sizes[2]);
74
- const bm = new BookModel({ data, options: {ppi: 10} });
75
- expect(bm.getMedianPageSizeInches()).toEqual({ width: 3, height: 3 });
76
- });
77
-
78
- test('caches result', () => {
79
- const bm = new BookModel({ data: SAMPLE_DATA });
80
- const firstResult = bm.getMedianPageSizeInches();
81
- expect(bm.getMedianPageSizeInches()).toBe(firstResult);
82
- expect(bm.getMedianPageSizeInches()).toBe(firstResult);
83
- expect(bm.getMedianPageSizeInches()).toBe(firstResult);
84
- });
85
- });
86
-
87
- describe('getPageIndices', () => {
88
- test('handles unique indices', () => {
89
- const bm = new BookModel({ data: SAMPLE_DATA });
90
- expect(bm.getPageIndices('1')).toEqual([0]);
91
- });
92
-
93
- test('handles invalid indices', () => {
94
- const bm = new BookModel({ data: SAMPLE_DATA });
95
- expect(bm.getPageIndices('foo')).toEqual([]);
96
- expect(bm.getPageIndices('123')).toEqual([]);
97
- });
98
-
99
- test('handles non-unique indices', () => {
100
- const data = deepCopy(SAMPLE_DATA);
101
- data[0][0].pageNum = '2';
102
- const bm = new BookModel({ data });
103
- expect(bm.getPageIndices('2')).toEqual([0, 1]);
104
- });
105
-
106
- test('handles n-prefixed pages', () => {
107
- const data = deepCopy(SAMPLE_DATA);
108
- data[0][0].pageNum = 'n0';
109
- const bm = new BookModel({ data });
110
- expect(bm.getPageIndices('n0')).toEqual([0]);
111
- });
112
- });
113
-
114
- test('getPageName', () => {
115
- const bm = new BookModel({ data: SAMPLE_DATA });
116
- expect(bm.getPageName(0)).toEqual('Page 1');
117
- expect(bm.getPageName(1)).toEqual('Page 2');
118
- });
119
-
120
- describe('numLeafs', () => {
121
- test('reads from data', () => {
122
- const bm = new BookModel({ data: SAMPLE_DATA });
123
- expect(bm.getNumLeafs()).toBe(4);
124
- });
125
-
126
- test('numLeafs can be overriden', () => {
127
- const bm = new BookModel({ data: SAMPLE_DATA, numLeafs: 12 });
128
- expect(bm.getNumLeafs()).toBe(12);
129
- });
130
- });
131
-
132
- test('getPageNum', () => {
133
- const bm = new BookModel({ data: SAMPLE_DATA });
134
- expect(bm.getPageNum(0)).toBe('1');
135
- });
136
-
137
- test('getPageProp gets values from correct document', () => {
138
- const bm = new BookModel({ data: SAMPLE_DATA });
139
- expect(bm.getPageProp(1, 'uri')).toBe(SAMPLE_DATA[1][0].uri);
140
- });
141
-
142
- describe('getSpreadIndices', () => {
143
- test('Works for left to right text', () => {
144
- const bm = new BookModel({ data: SAMPLE_DATA, pageProgression: 'lr' });
145
- expect(bm.getSpreadIndices(1)).toEqual([1, 2]);
146
- expect(bm.getSpreadIndices(2)).toEqual([1, 2]);
147
- });
148
- });
149
-
150
- describe('leafNumToIndex', () => {
151
- test('returns input if no leafNum in data', () => {
152
- const bm = new BookModel({ data: SAMPLE_DATA });
153
- expect(bm.leafNumToIndex(1)).toBe(1);
154
- expect(bm.leafNumToIndex(2)).toBe(2);
155
- expect(bm.leafNumToIndex(3)).toBe(3);
156
- });
157
-
158
- test('returns true index when leafNum does not point to index', () => {
159
- const data = deepCopy(SAMPLE_DATA);
160
- for (const spread of data) {
161
- for (const page of spread) {
162
- page.leafNum = parseFloat(page.pageNum) + 2;
163
- }
164
- }
165
-
166
- const bm = new BookModel({ data });
167
- expect(bm.leafNumToIndex(3)).toBe(0);
168
- });
169
- });
170
-
171
- describe('parsePageString', () => {
172
- test('handles leaf-prefixed PageString', () => {
173
- const data = deepCopy(SAMPLE_DATA);
174
- for (const spread of data) {
175
- for (const page of spread) {
176
- page.leafNum = parseFloat(page.pageNum) + 2;
177
- }
178
- }
179
-
180
- const bm = new BookModel({ data });
181
- expect(bm.parsePageString('leaf3')).toBe(0);
182
- });
183
- });
184
-
185
- describe('pagesIterator', () => {
186
- test('Goes through all pages', () => {
187
- const bm = new BookModel({ data: SAMPLE_DATA });
188
- let i = 0;
189
- for (const page of bm.pagesIterator()) {
190
- expect(page.index).toBe(i++);
191
- }
192
- });
193
-
194
- test('Can combine unviewables', () => {
195
- const data = deepCopy(SAMPLE_DATA);
196
- // add some more pages
197
- data.splice(2, 0, deepCopy(data[0]));
198
- data[1].forEach(page => page.viewable = false);
199
- const bm = new BookModel({ data });
200
- for (const page of bm.pagesIterator({combineConsecutiveUnviewables: true})) {
201
- expect(page.isConsecutiveUnviewable).toBe(false);
202
- }
203
- });
204
- });
205
-
206
- describe('_getDataFlattened', () => {
207
- test('Assigns correct page sides', () => {
208
- const bm = new BookModel({ data: SAMPLE_DATA });
209
- expect(bm._getDataFlattened().map(page => page.pageSide)).toEqual(['R', 'L', 'R', 'L']);
210
- });
211
-
212
- test('Memoized based on data length', () => {
213
- const data = deepCopy(SAMPLE_DATA);
214
- const bm = new BookModel({ data });
215
- const firstResult = bm._getDataFlattened();
216
- expect(bm._getDataFlattened()).toBe(firstResult);
217
- expect(bm._getDataFlattened()).toBe(firstResult);
218
- bm.br.data = data.slice(0, 1);
219
- expect(bm._getDataFlattened()).not.toBe(firstResult);
220
- });
221
-
222
- test('Assigns unviewablesStart', () => {
223
- const data = deepCopy(SAMPLE_DATA);
224
- data.slice(1, -1)
225
- .forEach(spread => spread.forEach(page => {
226
- page.viewable = false;
227
- }));
228
- const bm = new BookModel({ data });
229
- const pages = bm._getDataFlattened();
230
- expect(pages[0].unviewablesStart).toBeUndefined();
231
- expect(pages[1].unviewablesStart).toBe(1);
232
- expect(pages[2].unviewablesStart).toBe(1);
233
- expect(pages[3].unviewablesStart).toBeUndefined();
234
- });
235
- });
236
-
237
- describe('getPage', () => {
238
- test('loops around by default', () => {
239
- const bm = new BookModel({ data: SAMPLE_DATA });
240
- expect(bm.getPage(-1).index).toBe(3);
241
- expect(bm.getPage(-2).index).toBe(2);
242
- expect(bm.getPage(-3).index).toBe(1);
243
- expect(bm.getPage(4).index).toBe(0);
244
- expect(bm.getPage(5).index).toBe(1);
245
- });
246
-
247
- test('does not loop if loop=false', () => {
248
- const bm = new BookModel({ data: SAMPLE_DATA });
249
- expect(bm.getPage(-1, false)).toBeUndefined();
250
- expect(bm.getPage(-2, false)).toBeUndefined();
251
- expect(bm.getPage(4, false)).toBeUndefined();
252
- expect(bm.getPage(5, false)).toBeUndefined();
253
- });
254
- });
255
-
256
- describe('PageModel', () => {
257
- test('constructor copies fields from book model', () => {
258
- const bm = new BookModel({ data: SAMPLE_DATA });
259
- const spy = sinon.spy(bm, 'getPageWidth');
260
- const page = bm.getPage(0);
261
- expect(spy.callCount).toBe(1);
262
- expect(page.width).toBe(SAMPLE_DATA[0][0].width);
263
- });
264
-
265
- test('prev at start of book returns null', () => {
266
- const bm = new BookModel({ data: SAMPLE_DATA });
267
- expect(bm.getPage(0).prev).toBeUndefined();
268
- });
269
-
270
- test('prev to return previous', () => {
271
- const bm = new BookModel({ data: SAMPLE_DATA });
272
- expect(bm.getPage(1).prev.index).toBe(0);
273
- expect(bm.getPage(3).prev.prev.index).toBe(1);
274
- });
275
-
276
- test('next at end of book returns null', () => {
277
- const bm = new BookModel({ data: SAMPLE_DATA });
278
- expect(bm.getPage(-1).next).toBeUndefined();
279
- });
280
-
281
- test('next to return next page', () => {
282
- const bm = new BookModel({ data: SAMPLE_DATA });
283
- expect(bm.getPage(0).next.index).toBe(1);
284
- expect(bm.getPage(1).next.next.index).toBe(3);
285
- });
286
-
287
- describe('findNext combineConsecutiveUnviewables=true', () => {
288
- const data = deepCopy(SAMPLE_DATA);
289
- // add some more pages
290
- data.splice(2, 0, deepCopy(data[0]));
291
- data[1].forEach(page => page.viewable = false);
292
-
293
- const bm = new BookModel({ data });
294
-
295
- test('does not skip the first unviewable page', () => {
296
- expect(bm.getPage(0).findNext({ combineConsecutiveUnviewables: true }).index).toBe(1);
297
- });
298
-
299
- test('skips consecutive unviewables', () => {
300
- expect(bm.getPage(1).findNext({ combineConsecutiveUnviewables: true }).index).toBe(3);
301
- });
302
-
303
- test('at end is undefined', () => {
304
- expect(bm.getPage(-1).findNext({ combineConsecutiveUnviewables: true })).toBeUndefined();
305
- });
306
- });
307
-
308
- describe('findPrev', () => {
309
- const data = deepCopy(SAMPLE_DATA);
310
- // add some more pages
311
- data.splice(2, 0, deepCopy(data[0]));
312
- data[1].forEach(page => page.viewable = false);
313
-
314
- const bm = new BookModel({ data });
315
-
316
- test('works if called on first unviewable', () => {
317
- expect(bm.getPage(1).findPrev({ combineConsecutiveUnviewables: true }).index).toBe(0);
318
- });
319
-
320
- test('works if called within unviewable chunk', () => {
321
- expect(bm.getPage(2).findPrev({ combineConsecutiveUnviewables: true }).index).toBe(1);
322
- });
323
-
324
- test('at start is undefined', () => {
325
- expect(bm.getPage(0).findPrev({ combineConsecutiveUnviewables: true })).toBeUndefined();
326
- });
327
- });
328
-
329
- describe('findLeft/findRight', () => {
330
- const data = deepCopy(SAMPLE_DATA);
331
-
332
- test('Calls findNext/findPrev based on progression', () => {
333
- const bm = new BookModel({ data });
334
- const page = bm.getPage(0);
335
- const findNextStub = sinon.stub(page, 'findNext');
336
- const findPrevStub = sinon.stub(page, 'findPrev');
337
- bm.pageProgression = 'lr';
338
- page.findLeft();
339
- expect(findPrevStub.callCount).toBe(1);
340
- expect(findNextStub.callCount).toBe(0);
341
- page.findRight();
342
- expect(findPrevStub.callCount).toBe(1);
343
- expect(findNextStub.callCount).toBe(1);
344
- bm.pageProgression = 'rl';
345
- page.findLeft();
346
- expect(findPrevStub.callCount).toBe(1);
347
- expect(findNextStub.callCount).toBe(2);
348
- page.findRight();
349
- expect(findPrevStub.callCount).toBe(2);
350
- expect(findNextStub.callCount).toBe(2);
351
- });
352
- });
353
-
354
- describe('getURISrcSet', () => {
355
- const data = deepCopy(SAMPLE_DATA);
356
- const bm = new BookModel({ data, reduceSet: NAMED_REDUCE_SETS.pow2 });
357
- bm.getPageURI = (index, scale, rotate) => `correctURL.png?scale=${scale}`;
358
- const page = bm.getPage(0);
359
-
360
- test('with 0 elements in srcset', () => {
361
- expect(page.getURISrcSet(1)).toBe("");
362
- });
363
-
364
- test('with 2 elements in srcset', () => {
365
- expect(page.getURISrcSet(5)).toBe("correctURL.png?scale=2 2x, correctURL.png?scale=1 4x");
366
- });
367
-
368
- test('with the most elements in srcset', () => {
369
- expect(page.getURISrcSet(35)).toBe("correctURL.png?scale=16 2x, correctURL.png?scale=8 4x, correctURL.png?scale=4 8x, correctURL.png?scale=2 16x, correctURL.png?scale=1 32x");
370
- });
371
- });
372
- });