@internetarchive/bookreader 5.0.0-9-multiple-files → 5.0.0-90

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 (333) hide show
  1. package/.eslintrc.js +21 -19
  2. package/.github/workflows/node.js.yml +81 -7
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +505 -1442
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  57. package/BookReader/images/unviewable_page.png +0 -0
  58. package/BookReader/jquery-3.js +2 -0
  59. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  60. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  61. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js +1 -165
  63. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  64. package/BookReader/plugins/plugin.chapters.js +22 -301
  65. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  66. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  67. package/BookReader/plugins/plugin.iframe.js +1 -74
  68. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  69. package/BookReader/plugins/plugin.iiif.js +2 -0
  70. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  71. package/BookReader/plugins/plugin.resume.js +1 -368
  72. package/BookReader/plugins/plugin.resume.js.map +1 -1
  73. package/BookReader/plugins/plugin.search.js +2 -1420
  74. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.search.js.map +1 -1
  76. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  77. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  78. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  79. package/BookReader/plugins/plugin.tts.js +2 -9193
  80. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  81. package/BookReader/plugins/plugin.tts.js.map +1 -1
  82. package/BookReader/plugins/plugin.url.js +1 -269
  83. package/BookReader/plugins/plugin.url.js.map +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  85. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  86. package/BookReader/webcomponents-bundle.js +3 -0
  87. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  88. package/BookReader/webcomponents-bundle.js.map +1 -0
  89. package/BookReaderDemo/BookReaderDemo.css +18 -19
  90. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +144 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  95. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  96. package/BookReaderDemo/demo-fullscreen.html +2 -4
  97. package/BookReaderDemo/demo-iiif.html +99 -12
  98. package/BookReaderDemo/demo-internetarchive.html +214 -18
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +526 -525
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +595 -33
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +5 -2
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +70 -62
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +0 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +10 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/book-navigator.js +590 -0
  125. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  126. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  127. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  128. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  129. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  130. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  131. package/src/BookNavigator/delete-modal-actions.js +1 -1
  132. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  133. package/src/BookNavigator/downloads/downloads.js +29 -25
  134. package/src/BookNavigator/search/search-provider.js +80 -28
  135. package/src/BookNavigator/search/search-results.js +29 -26
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/viewable-files.js +95 -0
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
  140. package/src/BookReader/BookModel.js +76 -41
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/ImageCache.js +48 -15
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +777 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +19 -13
  150. package/src/BookReader/Navbar/Navbar.js +70 -54
  151. package/src/BookReader/PageContainer.js +116 -22
  152. package/src/BookReader/ReduceSet.js +3 -3
  153. package/src/BookReader/Toolbar/Toolbar.js +14 -41
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +73 -15
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils/classes.js +1 -1
  160. package/src/BookReader/utils.js +128 -13
  161. package/src/BookReader.js +562 -1078
  162. package/src/BookReaderPlugin.js +44 -0
  163. package/src/assets/icons/close-circle-dark.svg +1 -0
  164. package/src/assets/icons/magnify-minus.svg +3 -7
  165. package/src/assets/icons/magnify-plus.svg +3 -7
  166. package/src/assets/icons/voice.svg +1 -0
  167. package/src/assets/images/unviewable_page.png +0 -0
  168. package/src/css/BookReader.scss +1 -17
  169. package/src/css/_BRBookmarks.scss +1 -1
  170. package/src/css/_BRComponent.scss +1 -1
  171. package/src/css/_BRicon.scss +8 -2
  172. package/src/css/_BRmain.scss +33 -27
  173. package/src/css/_BRnav.scss +12 -42
  174. package/src/css/_BRpages.scss +170 -42
  175. package/src/css/_BRsearch.scss +68 -230
  176. package/src/css/_BRtoolbar.scss +5 -5
  177. package/src/css/_TextSelection.scss +87 -27
  178. package/src/css/_colorbox.scss +2 -2
  179. package/src/css/_controls.scss +24 -7
  180. package/src/css/_icons.scss +7 -1
  181. package/src/ia-bookreader/ia-bookreader.js +224 -0
  182. package/src/plugins/plugin.archive_analytics.js +84 -78
  183. package/src/plugins/plugin.autoplay.js +99 -104
  184. package/src/plugins/plugin.chapters.js +237 -191
  185. package/src/plugins/plugin.iframe.js +1 -1
  186. package/src/plugins/plugin.iiif.js +141 -0
  187. package/src/plugins/plugin.resume.js +53 -50
  188. package/src/plugins/plugin.text_selection.js +503 -175
  189. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  190. package/src/plugins/search/plugin.search.js +183 -121
  191. package/src/plugins/search/utils.js +43 -0
  192. package/src/plugins/search/view.js +67 -202
  193. package/src/plugins/tts/AbstractTTSEngine.js +75 -45
  194. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  195. package/src/plugins/tts/PageChunk.js +16 -23
  196. package/src/plugins/tts/PageChunkIterator.js +11 -17
  197. package/src/plugins/tts/WebTTSEngine.js +88 -72
  198. package/src/plugins/tts/plugin.tts.js +310 -350
  199. package/src/plugins/tts/utils.js +16 -26
  200. package/src/plugins/url/UrlPlugin.js +191 -0
  201. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  202. package/src/util/browserSniffing.js +22 -0
  203. package/src/util/docCookies.js +21 -2
  204. package/src/util/strings.js +1 -0
  205. package/tests/e2e/README.md +37 -0
  206. package/tests/e2e/autoplay.test.js +9 -6
  207. package/tests/e2e/base.test.js +8 -16
  208. package/tests/e2e/helpers/base.js +55 -50
  209. package/tests/e2e/helpers/debug.js +1 -1
  210. package/tests/e2e/helpers/mockSearch.js +19 -22
  211. package/tests/e2e/helpers/params.js +17 -0
  212. package/tests/e2e/helpers/rightToLeft.js +8 -14
  213. package/tests/e2e/helpers/search.js +73 -0
  214. package/tests/e2e/models/Navigation.js +20 -37
  215. package/tests/e2e/rightToLeft.test.js +4 -5
  216. package/tests/e2e/viewmode.test.js +40 -33
  217. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  218. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  219. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  220. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  221. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  222. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  223. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  224. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  225. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
  226. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  227. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  228. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  229. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  230. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  231. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  232. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  233. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  234. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  235. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  236. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  237. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  238. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +42 -29
  239. package/tests/jest/BookReader/PageContainer.test.js +238 -0
  240. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  241. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
  242. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  243. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  244. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  245. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  246. package/tests/jest/BookReader/utils.test.js +250 -0
  247. package/tests/jest/BookReader.keyboard.test.js +190 -0
  248. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
  249. package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
  250. package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
  251. package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
  252. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  253. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
  254. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
  255. package/tests/jest/plugins/plugin.text_selection.test.js +316 -0
  256. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  257. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
  258. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +42 -9
  259. package/tests/jest/plugins/search/utils.js +25 -0
  260. package/tests/jest/plugins/search/utils.test.js +29 -0
  261. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +30 -10
  262. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  263. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  264. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  265. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  266. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  267. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  268. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +57 -18
  269. package/tests/jest/setup.js +3 -0
  270. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  271. package/tests/jest/util/docCookies.test.js +24 -0
  272. package/tests/{util → jest/util}/strings.test.js +1 -1
  273. package/tests/{utils.js → jest/utils.js} +38 -0
  274. package/webpack.config.js +16 -10
  275. package/.babelrc +0 -12
  276. package/.dependabot/config.yml +0 -6
  277. package/.testcaferc.json +0 -5
  278. package/BookReader/bookreader-component-bundle.js +0 -14330
  279. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  280. package/BookReader/bookreader-component-bundle.js.map +0 -1
  281. package/BookReader/icons/sort-ascending.svg +0 -1
  282. package/BookReader/icons/sort-descending.svg +0 -1
  283. package/BookReader/jquery-1.10.1.js +0 -108
  284. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  285. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  286. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  287. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  288. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  289. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  290. package/BookReaderDemo/IIIFBookReader.js +0 -207
  291. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  292. package/BookReaderDemo/demo-autoplay.html +0 -38
  293. package/BookReaderDemo/demo-iiif.js +0 -26
  294. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  295. package/karma.conf.js +0 -23
  296. package/src/BookNavigator/BookModel.js +0 -14
  297. package/src/BookNavigator/BookNavigator.js +0 -452
  298. package/src/BookNavigator/assets/book-loader.js +0 -27
  299. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  300. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  301. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  302. package/src/BookNavigator/search/a-search-result.js +0 -55
  303. package/src/BookNavigator/volumes/volumes-provider.js +0 -108
  304. package/src/BookNavigator/volumes/volumes.js +0 -162
  305. package/src/BookReader/DebugConsole.js +0 -54
  306. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  307. package/src/ItemNavigator/ItemNavigator.js +0 -372
  308. package/src/ItemNavigator/providers/sharing.js +0 -29
  309. package/src/assets/icons/sort-ascending.svg +0 -1
  310. package/src/assets/icons/sort-descending.svg +0 -1
  311. package/src/css/_MobileNav.scss +0 -194
  312. package/src/dragscrollable-br.js +0 -261
  313. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  314. package/src/plugins/plugin.mobile_nav.js +0 -287
  315. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  316. package/tests/BookReader/DebugConsole.test.js +0 -25
  317. package/tests/BookReader/Mode1Up.test.js +0 -164
  318. package/tests/BookReader/Mode2Up.test.js +0 -247
  319. package/tests/BookReader/PageContainer.test.js +0 -115
  320. package/tests/BookReader/utils.test.js +0 -109
  321. package/tests/e2e/helpers/desktopSearch.js +0 -72
  322. package/tests/e2e/helpers/mobileSearch.js +0 -85
  323. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  324. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  325. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  326. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  327. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  328. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  329. package/tests/plugins/plugin.autoplay.test.js +0 -52
  330. package/tests/plugins/plugin.chapters.test.js +0 -130
  331. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  332. package/tests/plugins/plugin.text_selection.test.js +0 -203
  333. package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,35 @@
1
+
2
+ import BookReader from '@/src/BookReader.js';
3
+ import '@/src/plugins/plugin.autoplay.js';
4
+
5
+ /** @type {BookReader} */
6
+ let br;
7
+ beforeEach(() => {
8
+ document.body.innerHTML = '<div id="BookReader">';
9
+ br = new BookReader();
10
+ });
11
+
12
+ afterEach(() => {
13
+ jest.clearAllMocks();
14
+ });
15
+
16
+ describe('Plugin: Menu Toggle', () => {
17
+ test('autoplay does not start when BookReaderInitializes', () => {
18
+ br._plugins.autoplay.toggle = jest.fn();
19
+ br.init();
20
+ expect(br._plugins.autoplay.toggle).toHaveBeenCalledTimes(0);
21
+ });
22
+ test('autoplay will run without `flipSpeed` parameters', () => {
23
+ const initialTimer = br._plugins.autoplay.timer;
24
+ br.next = jest.fn();
25
+ br._plugins.autoplay.stop = jest.fn();
26
+ br.init();
27
+ br._plugins.autoplay.toggle();
28
+ // internally referenced functions that fire
29
+ expect(br.next).toHaveBeenCalledTimes(1);
30
+
31
+ expect(initialTimer).toBeFalsy();
32
+ // timer changes when autoplay turns on
33
+ expect(br._plugins.autoplay.timer).toBeTruthy();
34
+ });
35
+ });
@@ -0,0 +1,195 @@
1
+ import sinon from "sinon";
2
+
3
+ import BookReader from "@/src/BookReader.js";
4
+ import "@/src/plugins/plugin.chapters.js";
5
+ import { BookModel } from "@/src/BookReader/BookModel";
6
+ import { deepCopy } from "../utils";
7
+ /** @typedef {import('@/src/plugins/plugin.chapters').TocEntry} TocEntry */
8
+
9
+ /** @type {TocEntry[]} */
10
+ const SAMPLE_TOC = [{
11
+ "pagenum": "3",
12
+ "level": 1,
13
+ "label": "CHAPTER I",
14
+ "type": { "key": "/type/toc_item" },
15
+ "title": "THE COUNTRY AND THE MISSION 1",
16
+ "pageIndex": 3,
17
+ }, {
18
+ "pagenum": "17",
19
+ "level": 1,
20
+ "label": "CHAPTER II",
21
+ "type": { "key": "/type/toc_item" },
22
+ "title": "THE COUNTRY AND THE MISSION 2",
23
+ "pageIndex": 17,
24
+ }, {
25
+ "pagenum": "undefined",
26
+ "level": 1,
27
+ "label": "CHAPTER III",
28
+ "type": { "key": "/type/toc_item" },
29
+ "title": "THE COUNTRY AND THE MISSION 3",
30
+ }, {
31
+ "pagenum": "40",
32
+ "level": 1,
33
+ "label": "CHAPTER IV",
34
+ "type": { "key": "/type/toc_item" },
35
+ "title": "THE COUNTRY AND THE MISSION 4",
36
+ "pageIndex": 40,
37
+ }];
38
+
39
+ /** @type {TocEntry[]} */
40
+ const SAMPLE_TOC_UNDEF = [
41
+ {
42
+ "level": 1,
43
+ "label": "CHAPTER I",
44
+ "type": { "key": "/type/toc_item" },
45
+ "title": "THE COUNTRY AND THE MISSION 1",
46
+ },
47
+ {
48
+ "level": 1,
49
+ "label": "CHAPTER II",
50
+ "type": { "key": "/type/toc_item" },
51
+ "title": "THE COUNTRY AND THE MISSION 2",
52
+ },
53
+ ];
54
+
55
+ /** @type {TocEntry[]} */
56
+ const SAMPLE_TOC_OPTION = [
57
+ {
58
+ "level": 1,
59
+ "title": "THE COUNTRY AND THE MISSION 1",
60
+ },
61
+ {
62
+ "level": 1,
63
+ "title": "THE COUNTRY AND THE MISSION 2",
64
+ },
65
+ ];
66
+
67
+ afterEach(() => {
68
+ sinon.restore();
69
+ });
70
+
71
+ describe("BRChaptersPlugin", () => {
72
+ beforeEach(() => {
73
+ sinon.stub(BookModel.prototype, "getPageIndex").callsFake((str) =>
74
+ parseFloat(str),
75
+ );
76
+ });
77
+
78
+ describe("_chaptersInit", () => {
79
+ test("does not render when no open library record", async () => {
80
+ const fakeBR = {
81
+ options: {},
82
+ getOpenLibraryRecord: async () => null,
83
+ _chaptersRender: sinon.stub(),
84
+ };
85
+ await BookReader.prototype._chapterInit.call(fakeBR);
86
+ expect(fakeBR._chaptersRender.callCount).toBe(0);
87
+ });
88
+
89
+ test("does not render when open library record with no TOC", async () => {
90
+ const fakeBR = {
91
+ options: {},
92
+ getOpenLibraryRecord: async () => ({ key: "/books/OL1M" }),
93
+ _chaptersRender: sinon.stub(),
94
+ };
95
+ await BookReader.prototype._chapterInit.call(fakeBR);
96
+ expect(fakeBR._chaptersRender.callCount).toBe(0);
97
+ });
98
+
99
+ test("renders if valid TOC on open library", async () => {
100
+ const fakeBR = {
101
+ options: {},
102
+ bind: sinon.stub(),
103
+ book: {
104
+ getPageIndex: (str) => parseFloat(str),
105
+ },
106
+ getOpenLibraryRecord: async () => ({
107
+ "title": "The Adventures of Sherlock Holmes",
108
+ "table_of_contents": deepCopy(SAMPLE_TOC_OPTION),
109
+ "ocaid": "adventureofsherl0000unse",
110
+ }),
111
+ _chaptersRender: sinon.stub(),
112
+ };
113
+ await BookReader.prototype._chapterInit.call(fakeBR);
114
+ expect(fakeBR._chaptersRender.callCount).toBe(1);
115
+ });
116
+
117
+ test("does not fetch open library record if table of contents in options", async () => {
118
+ const fakeBR = {
119
+ options: {
120
+ table_of_contents: deepCopy(SAMPLE_TOC_UNDEF),
121
+ },
122
+ bind: sinon.stub(),
123
+ getOpenLibraryRecord: sinon.stub(),
124
+ _chaptersRender: sinon.stub(),
125
+ };
126
+ await BookReader.prototype._chapterInit.call(fakeBR);
127
+ expect(fakeBR.getOpenLibraryRecord.callCount).toBe(0);
128
+ expect(fakeBR._chaptersRender.callCount).toBe(1);
129
+ });
130
+
131
+ test("converts leafs and pagenums to page index", async () => {
132
+ const table_of_contents = deepCopy(SAMPLE_TOC_UNDEF);
133
+ table_of_contents[0].leaf = 0;
134
+ table_of_contents[1].pagenum = '17';
135
+ const fakeBR = {
136
+ options: {
137
+ table_of_contents,
138
+ },
139
+ bind: sinon.stub(),
140
+ book: {
141
+ leafNumToIndex: (leaf) => leaf + 1,
142
+ getPageIndex: (str) => parseFloat(str),
143
+ },
144
+ _chaptersRender: sinon.stub(),
145
+ };
146
+ await BookReader.prototype._chapterInit.call(fakeBR);
147
+ expect(fakeBR._chaptersRender.callCount).toBe(1);
148
+ expect(fakeBR._tocEntries[0].pageIndex).toBe(1);
149
+ expect(fakeBR._tocEntries[1].pageIndex).toBe(17);
150
+ });
151
+ });
152
+
153
+ describe('_chaptersRender', () => {
154
+ test('renders markers and panel', () => {
155
+ const fakeBR = {
156
+ _tocEntries: SAMPLE_TOC,
157
+ _chaptersRenderMarker: sinon.stub(),
158
+ shell: {
159
+ menuProviders: {},
160
+ addMenuShortcut: sinon.stub(),
161
+ updateMenuContents: sinon.stub(),
162
+ },
163
+ };
164
+ BookReader.prototype._chaptersRender.call(fakeBR);
165
+ expect(fakeBR.shell.menuProviders['chapters']).toBeTruthy();
166
+ expect(fakeBR.shell.addMenuShortcut.callCount).toBe(1);
167
+ expect(fakeBR.shell.updateMenuContents.callCount).toBe(1);
168
+ expect(fakeBR._chaptersRenderMarker.callCount).toBeGreaterThan(1);
169
+ });
170
+ });
171
+
172
+ describe('_chaptersUpdateCurrent', () => {
173
+ test('highlights the current chapter', () => {
174
+ const fakeBR = {
175
+ mode: 2,
176
+ firstIndex: 16,
177
+ displayedIndices: [16, 17],
178
+ _tocEntries: SAMPLE_TOC,
179
+ _chaptersPanel: {
180
+ currentChapter: null,
181
+ },
182
+ };
183
+ BookReader.prototype._chaptersUpdateCurrent.call(fakeBR);
184
+ expect(fakeBR._chaptersPanel.currentChapter).toEqual(SAMPLE_TOC[1]);
185
+
186
+ fakeBR.mode = 1;
187
+ BookReader.prototype._chaptersUpdateCurrent.call(fakeBR);
188
+ expect(fakeBR._chaptersPanel.currentChapter).toEqual(SAMPLE_TOC[0]);
189
+
190
+ fakeBR.firstIndex = 0;
191
+ BookReader.prototype._chaptersUpdateCurrent.call(fakeBR);
192
+ expect(fakeBR._chaptersPanel.currentChapter).toBeUndefined();
193
+ });
194
+ });
195
+ });
@@ -1,7 +1,7 @@
1
1
  import sinon from 'sinon';
2
2
 
3
- import BookReader from '../../src/BookReader.js';
4
- import { _attachEventListeners } from '../../src/plugins/plugin.iframe.js';
3
+ import BookReader from '@/src/BookReader.js';
4
+ import { _attachEventListeners } from '@/src/plugins/plugin.iframe.js';
5
5
 
6
6
  afterEach(() => {
7
7
  sinon.restore();
@@ -35,8 +35,8 @@ test('updates params when window receives a message', () => {
35
35
  window.dispatchEvent(new MessageEvent('message', {
36
36
  data: {
37
37
  type: 'bookReaderFragmentChange',
38
- fragment: ''
39
- }
38
+ fragment: '',
39
+ },
40
40
  }));
41
41
  expect(br.updateFromParams.callCount).toBe(1);
42
42
  });
@@ -1,9 +1,11 @@
1
- import BookReader from '../../src/BookReader.js';
2
- import '../../src/plugins/plugin.resume.js';
1
+ import BookReader from '@/src/BookReader.js';
2
+ import '@/src/plugins/plugin.resume.js';
3
3
 
4
4
  import sinon from 'sinon';
5
- import * as docCookies from '../../src/util/docCookies.js';
5
+ import * as docCookies from '@/src/util/docCookies.js';
6
+ import { ResumePlugin } from '@/src/plugins/plugin.resume.js';
6
7
 
8
+ /** @type {import('@/src/BookReader.js').default} */
7
9
  let br;
8
10
  beforeAll(() => {
9
11
  document.body.innerHTML = '<div id="BookReader">';
@@ -16,21 +18,6 @@ afterEach(() => {
16
18
  sinon.restore();
17
19
  });
18
20
 
19
- describe('Plugin: Remember Current Page in Cookies', () => {
20
- test('has default option flag', () => {
21
- expect(BookReader.defaultOptions.enablePageResume).toEqual(true);
22
- expect(BookReader.defaultOptions.resumeCookiePath).toEqual(null);
23
- });
24
-
25
- test('has added BR property: getResumeValue', () => {
26
- expect(br).toHaveProperty('getResumeValue');
27
- });
28
-
29
- test('has added BR property: updateResumeValue', () => {
30
- expect(br).toHaveProperty('updateResumeValue');
31
- });
32
- });
33
-
34
21
  describe('updateResumeValue', () => {
35
22
  /* Mark 2020-05-02
36
23
  Skipping while confirming with Neeraj
@@ -42,57 +29,57 @@ describe('updateResumeValue', () => {
42
29
  In this branch .toHaveBeenCalledTimes() === 1
43
30
  */
44
31
  test.skip('starts when BookReaderInit is called', () => {
45
- br.updateResumeValue = jest.fn();
32
+ br._plugins.resume.updateResumeValue = jest.fn();
46
33
  br.init();
47
- expect(br.updateResumeValue).toHaveBeenCalledTimes(2);
34
+ expect(br._plugins.resume.updateResumeValue).toHaveBeenCalledTimes(2);
48
35
  });
49
36
 
50
37
  test('handles cookieName=null', () => {
51
- const { updateResumeValue } = BookReader.prototype;
38
+ const p = new ResumePlugin(null);
39
+ p.setup({ cookiePath: '/details/goody' });
52
40
  const setItemSpy = sinon.spy(docCookies, 'setItem');
53
- const fakeBr = { options: { resumeCookiePath: '/details/goody' } };
54
41
 
55
- updateResumeValue.call(fakeBr, 16);
42
+ p.updateResumeValue(16);
56
43
  expect(setItemSpy.callCount).toBe(1);
57
44
  expect(setItemSpy.args[0].slice(0, 2)).toEqual(['br-resume', 16]);
58
45
  expect(setItemSpy.args[0][3]).toEqual('/details/goody');
59
46
  });
60
47
 
61
- test('handles resumeCookiePath not set', () => {
48
+ test('handles cookiePath not set', () => {
62
49
  const setItemSpy = sinon.spy(docCookies, 'setItem');
63
50
  // Save function
64
- const saveFn = br.getCookiePath;
65
- br.getCookiePath = jest.fn(() => '/details/foo');
66
- br.updateResumeValue(16);
51
+ const saveFn = br._plugins.resume.getCookiePath;
52
+ br._plugins.resume.getCookiePath = jest.fn(() => '/details/foo');
53
+ br._plugins.resume.updateResumeValue(16);
67
54
  expect(setItemSpy.args[0][3]).toEqual('/details/foo');
68
55
  // Restore function
69
- br.getCookiePath = saveFn;
56
+ br._plugins.resume.getCookiePath = saveFn;
70
57
  });
71
58
 
72
59
  test('handles cookie path from URL with decoration', () => {
73
60
  const complexPathWithPage = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy/page/n1/mode/2up';
74
61
  const complexPath = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy';
75
- expect(br.getCookiePath(complexPathWithPage))
62
+ expect(br._plugins.resume.getCookiePath(complexPathWithPage))
76
63
  .toEqual(complexPath);
77
64
 
78
- expect(br.getCookiePath('/details/item/mode/1up'))
65
+ expect(br._plugins.resume.getCookiePath('/details/item/mode/1up'))
79
66
  .toEqual('/details/item');
80
67
 
81
- expect(br.getCookiePath('/details/item/inside/a/long/path/model/is/used'))
68
+ expect(br._plugins.resume.getCookiePath('/details/item/inside/a/long/path/model/is/used'))
82
69
  .toEqual('/details/item/inside/a/long/path/model/is/used');
83
70
 
84
- expect(br.getCookiePath('/details/item/inside/a/long/path/mode/is/used'))
71
+ expect(br._plugins.resume.getCookiePath('/details/item/inside/a/long/path/mode/is/used'))
85
72
  .toEqual('/details/item/inside/a/long/path');
86
73
  });
87
74
 
88
75
  test('handles cookie path from URL with no decoration', () => {
89
- expect(br.getCookiePath('/details/item'))
76
+ expect(br._plugins.resume.getCookiePath('/details/item'))
90
77
  .toEqual('/details/item');
91
78
 
92
- expect(br.getCookiePath('/details/item/'))
79
+ expect(br._plugins.resume.getCookiePath('/details/item/'))
93
80
  .toEqual('/details/item/');
94
81
 
95
- expect(br.getCookiePath('/details/item/almost/any/kind/of/long/path'))
82
+ expect(br._plugins.resume.getCookiePath('/details/item/almost/any/kind/of/long/path'))
96
83
  .toEqual('/details/item/almost/any/kind/of/long/path');
97
84
  });
98
85
  });
@@ -0,0 +1,316 @@
1
+ import sinon from 'sinon';
2
+
3
+ import BookReader from '@/src/BookReader.js';
4
+ import {
5
+ Cache,
6
+ genMap,
7
+ lookAroundWindow,
8
+ zip,
9
+ } from '@/src/plugins/plugin.text_selection.js';
10
+
11
+
12
+ /** @type {BookReader} */
13
+
14
+ // djvu.xml book infos copied from https://ia803103.us.archive.org/14/items/goodytwoshoes00newyiala/goodytwoshoes00newyiala_djvu.xml
15
+ const FAKE_XML_1WORD = `
16
+ <OBJECT data="file://localhost//tmp/derive/goodytwoshoes00newyiala//goodytwoshoes00newyiala.djvu" height="3192" type="image/x.djvu" usemap="goodytwoshoes00newyiala_0001.djvu" width="2454">
17
+ <PARAGRAPH>
18
+ <LINE>
19
+ <WORD coords="1216,2768,1256,2640">test</WORD>
20
+ </LINE>
21
+ </PARAGRAPH>
22
+ </OBJECT>`;
23
+ const FAKE_XML_MULT_WORDS = `
24
+ <OBJECT data="file://localhost//tmp/derive/goodytwoshoes00newyiala//goodytwoshoes00newyiala.djvu" height="3192" type="image/x.djvu" usemap="goodytwoshoes00newyiala_0001.djvu" width="2454">
25
+ <PARAGRAPH>
26
+ <LINE>
27
+ <WORD coords="1216,2768,1256,2640">test1</WORD>
28
+ <WORD coords="1400,2768,1500,2640">test2</WORD>
29
+ <WORD coords="1600,2768,1700,2640">test3</WORD>
30
+ </LINE>
31
+ </PARAGRAPH>
32
+ </OBJECT>`;
33
+ const FAKE_XML_MULT_LINES = `
34
+ <OBJECT data="file://localhost//tmp/derive/goodytwoshoes00newyiala//goodytwoshoes00newyiala.djvu" height="3192" type="image/x.djvu" usemap="goodytwoshoes00newyiala_0001.djvu" width="2454">
35
+ <PARAGRAPH>
36
+ <LINE>
37
+ <WORD coords="119,2050,230,2014" x-confidence="29">way </WORD>
38
+ <WORD coords="230,2038,320,2002" x-confidence="30">can </WORD>
39
+ <WORD coords="320,2039,433,2002" x-confidence="28">false </WORD>
40
+ <WORD coords="433,2051,658,2003" x-confidence="29">judgment </WORD>
41
+ <WORD coords="658,2039,728,2002" x-confidence="30">be </WORD>
42
+ <WORD coords="658,2039,728,2002" x-confidence="30">-</WORD>
43
+ <WORD coords="728,2039,939,2001" x-confidence="29">formed. </WORD>
44
+ <WORD coords="939,2039,1087,2001" x-confidence="29">There </WORD>
45
+ <WORD coords="1087,2039,1187,2002" x-confidence="29">still </WORD>
46
+ <WORD coords="1187,2038,1370,2003" x-confidence="29">remains </WORD>
47
+ <WORD coords="1370,2037,1433,2014" x-confidence="28">an-</WORD>
48
+ </LINE>
49
+ <LINE>
50
+ <WORD coords="244,2099,370,2063" x-confidence="29">other mode </WORD>
51
+ <WORD coords="370,2100,427,2064" x-confidence="29">in </WORD>
52
+ <WORD coords="427,2100,566,2063" x-confidence="29">which </WORD>
53
+ <WORD coords="566,2100,670,2063" x-confidence="29">false </WORD>
54
+ <WORD coords="670,2112,907,2063" x-confidence="29">judgments </WORD>
55
+ <WORD coords="907,2112,1006,2064" x-confidence="29">may </WORD>
56
+ <WORD coords="1006,2100,1071,2063" x-confidence="29">be </WORD>
57
+ <WORD coords="1071,2100,1266,2062" x-confidence="29">formed. </WORD>
58
+ <WORD coords="1266,2110,1435,2062" x-confidence="29">Suppose</WORD>
59
+ </LINE>
60
+ <LINE>
61
+ <WORD coords="118,2160,217,2123" x-confidence="29">that </WORD>
62
+ <WORD coords="217,2160,289,2124" x-confidence="29">we </WORD>
63
+ <WORD coords="289,2160,400,2124" x-confidence="29">have </WORD>
64
+ <WORD coords="400,2160,456,2124" x-confidence="30">in </WORD>
65
+ <WORD coords="456,2161,542,2136" x-confidence="29">our </WORD>
66
+ <WORD coords="542,2161,660,2124" x-confidence="29">souls </WORD>
67
+ <WORD coords="660,2160,700,2136" x-confidence="29">a </WORD>
68
+ <WORD coords="700,2160,847,2129" x-confidence="28">waxen </WORD>
69
+ <WORD coords="847,2160,983,2123" x-confidence="29">tablet </WORD>
70
+ <WORD coords="983,2160,1045,2124" x-confidence="29">of </WORD>
71
+ <WORD coords="1045,2160,1211,2124" x-confidence="29">various </WORD>
72
+ <WORD coords="1211,2171,1398,2122" x-confidence="29">qualities </WORD>
73
+ <WORD coords="1398,2157,1434,2122" x-confidence="29">lastWord</WORD>
74
+ </LINE>
75
+ </PARAGRAPH>
76
+ </OBJECT>`;
77
+ const FAKE_XML_5COORDS = `
78
+ <OBJECT data="file://localhost//tmp/derive/goodytwoshoes00newyiala//goodytwoshoes00newyiala.djvu" height="3192" type="image/x.djvu" usemap="goodytwoshoes00newyiala_0001.djvu" width="2454">
79
+ <PARAGRAPH>
80
+ <LINE>
81
+ <WORD coords="1216,2768,1256,2640,2690">test</WORD>
82
+ </LINE>
83
+ </PARAGRAPH>
84
+ </OBJECT>`;
85
+ const FAKE_XML_EMPTY = '';
86
+
87
+ describe("Generic tests", () => {
88
+ document.body.innerHTML = '<div id="BookReader">';
89
+ const br = window.br = new BookReader({
90
+ data: [
91
+ [
92
+ { width: 800, height: 1200,
93
+ uri: '//archive.org/download/BookReader/img/page001.jpg' },
94
+ ],
95
+ [
96
+ { width: 800, height: 1200,
97
+ uri: '//archive.org/download/BookReader/img/page002.jpg' },
98
+ { width: 800, height: 1200,
99
+ uri: '//archive.org/download/BookReader/img/page003.jpg' },
100
+ ],
101
+ [
102
+ { width: 800, height: 1200,
103
+ uri: '//archive.org/download/BookReader/img/page004.jpg' },
104
+ { width: 800, height: 1200,
105
+ uri: '//archive.org/download/BookReader/img/page005.jpg' },
106
+ ],
107
+ ],
108
+ });
109
+ br.init();
110
+
111
+ afterEach(() => {
112
+ sinon.restore();
113
+ $('.BRtextLayer').remove();
114
+ });
115
+
116
+ test("_createPageContainer overridden function still creates a BRpagecontainer element", () => {
117
+ const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
118
+ sinon.stub(br._plugins.textSelection, "getPageText")
119
+ .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
120
+ const container = br._createPageContainer(1, {});
121
+ expect(container).toBeTruthy();
122
+ expect(spy.callCount).toBe(1);
123
+ });
124
+
125
+ // test loading first object from sample data
126
+ test("_createPageContainer handles index 0", () => {
127
+ const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
128
+ br._createPageContainer(0, {});
129
+ expect(spy.callCount).toBe(1);
130
+ });
131
+
132
+ // test loading last object from sample data
133
+ test("_createPageContainer handles index -1", () => {
134
+ const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
135
+ br._createPageContainer(-1, {});
136
+ expect(spy.callCount).toBe(0);
137
+ });
138
+
139
+ test("createTextLayer will render the last page and create text layer properly", async () => {
140
+ const $container = br.refs.$brContainer;
141
+ sinon.stub(br._plugins.textSelection, "getPageText")
142
+ .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
143
+ const pageIndex = br.data.length - 1;
144
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: pageIndex, width: 100, height: 100 }});
145
+ expect($container.find(".BRtextLayer").length).toBe(1);
146
+ expect($container.find("p").length).toBe(1);
147
+ });
148
+
149
+ test("createTextLayer will not create text layer if there are too many words", async () => {
150
+ const $container = br.refs.$brContainer;
151
+ const xml = FAKE_XML_1WORD.replace(/<WORD.*<\/WORD>/, FAKE_XML_1WORD.match(/<WORD.*<\/WORD>/)[0].repeat(3000));
152
+ sinon.stub(br._plugins.textSelection, "getPageText")
153
+ .returns($(new DOMParser().parseFromString(xml, "text/xml")));
154
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 0, width: 100, height: 100 }});
155
+ expect($container.find(".BRtextLayer").length).toBe(0);
156
+ expect($container.find("p").length).toBe(0);
157
+ expect($container.find(".BRwordElement").length).toBe(0);
158
+ });
159
+
160
+ test("createTextLayer creates text layer with paragraph with 1 word element", async () => {
161
+ const $container = br.refs.$brContainer;
162
+ sinon.stub(br._plugins.textSelection, "getPageText")
163
+ .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
164
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 1, width: 100, height: 100 }});
165
+ expect($container.find(".BRtextLayer").length).toBe(1);
166
+ expect($container.find("p").length).toBe(1);
167
+ expect($container.find(".BRwordElement").length).toBe(1);
168
+ expect($container.find(".BRwordElement").text()).toBe("test");
169
+ });
170
+
171
+ test("createTextLayer creates text layer with paragraph with multiple word elements", async () => {
172
+ const $container = br.refs.$brContainer;
173
+ sinon.stub(br._plugins.textSelection, "getPageText")
174
+ .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_WORDS, "text/xml")));
175
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 2, width: 100, height: 100 }});
176
+ expect($container.find(".BRtextLayer").length).toBe(1);
177
+ expect($container.find("p").length).toBe(1);
178
+ expect($container.find(".BRwordElement").length).toBe(3);
179
+ expect($container.find(".BRspace").length).toBe(2);
180
+ });
181
+
182
+ test("createTextLayer creates text layer with paragraph with word with 5 params coordinates", async () => {
183
+ const $container = br.refs.$brContainer;
184
+ sinon.stub(br._plugins.textSelection, "getPageText")
185
+ .returns($(new DOMParser().parseFromString(FAKE_XML_5COORDS, "text/xml")));
186
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
187
+ expect($container.find(".BRtextLayer").length).toBe(1);
188
+ expect($container.find("p").length).toBe(1);
189
+ expect($container.find(".BRwordElement").length).toBe(1);
190
+ });
191
+
192
+ test("createTextLayer handles multiple lines", async () => {
193
+ const $container = br.refs.$brContainer;
194
+ sinon.stub(br._plugins.textSelection, "getPageText")
195
+ .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
196
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
197
+ expect($container.find(".BRtextLayer").length).toBe(1);
198
+ expect($container.find("p").length).toBe(1);
199
+ expect($container.find(".BRlineElement").length).toBe(3);
200
+ // Adds space at end of line; except last line/hyphens
201
+ expect($container.find("p").text()).toMatch(/another/);
202
+ expect($container.find("p").text()).toMatch(/Suppose /);
203
+ expect($container.find("p").text()).toMatch(/lastWord$/);
204
+ expect($container.find("p > br").length).toBe(1);
205
+ });
206
+
207
+ test("createTextLayer repairs trailing hyphens", async () => {
208
+ const $container = br.refs.$brContainer;
209
+ sinon.stub(br._plugins.textSelection, "getPageText")
210
+ .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
211
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
212
+
213
+ expect($container.find(".BRwordElement--hyphen").length).toBe(1);
214
+ expect($container.find(".BRwordElement--hyphen").closest(".BRlineElement").text().endsWith(' ')).toBe(false);
215
+ expect($container.find(".BRwordElement--hyphen").closest(".BRlineElement").text().endsWith('-')).toBe(false);
216
+ });
217
+
218
+ test("createTextLayer can handle empty xml", async () => {
219
+ const $container = br.refs.$brContainer;
220
+ sinon.stub(br._plugins.textSelection, "getPageText")
221
+ .returns($(new DOMParser().parseFromString(FAKE_XML_EMPTY, "text/xml")));
222
+ await br._plugins.textSelection.createTextLayer({ $container, page: { index: 4, width: 100, height: 100 }});
223
+ expect($container.find(".BRtextLayer").length).toBe(1);
224
+ expect($container.find("p").length).toBe(0);
225
+ expect($container.find(".BRwordElement").length).toBe(0);
226
+ });
227
+
228
+ const LONG_PRESS_DURATION = 500;
229
+ test("calling stopPageFlip does not allow long click to flip the page", () => {
230
+ const $container = br.refs.$brContainer;
231
+ br._plugins.textSelection.stopPageFlip($container);
232
+ const currIndex = br.currentIndex();
233
+ $container.find("BRwordElement").trigger("mousedown");
234
+ // Waits for long press
235
+ setTimeout(() => {
236
+ $container.find("BRwordElement").trigger("mousedown");
237
+ // Waits for flipping animation
238
+ setTimeout(() => {
239
+ expect(br.currentIndex()).toBe(currIndex);
240
+ }, 2000);
241
+ }, LONG_PRESS_DURATION);
242
+ });
243
+ });
244
+
245
+ describe("Cache", () => {
246
+ test('Adding works', () => {
247
+ const c = new Cache(10);
248
+ c.add(35);
249
+ expect(c.entries).toEqual([35]);
250
+ });
251
+
252
+ test('Size does not grow beyond limit', () => {
253
+ const c = new Cache(2);
254
+ c.add(35);
255
+ c.add(32);
256
+ c.add(12);
257
+ c.add(11);
258
+ c.add(112);
259
+ expect(c.entries).toHaveLength(2);
260
+ });
261
+
262
+ test('Oldest evicted first', () => {
263
+ const c = new Cache(2);
264
+ c.add(35);
265
+ c.add(32);
266
+ c.add(12);
267
+ c.add(12);
268
+ c.add(10);
269
+ expect(c.entries).toEqual([12, 10]);
270
+ });
271
+ });
272
+
273
+ describe('genMap', () => {
274
+ test('handles empty', () => {
275
+ expect(Array.from(genMap([], x => x ** 2))).toEqual([]);
276
+ });
277
+
278
+ test('handles non-empty', () => {
279
+ expect(Array.from(genMap([1,2,3], x => x ** 2))).toEqual([1,4,9]);
280
+ });
281
+ });
282
+
283
+ describe('lookAroundWindow', () => {
284
+ test('handles empty', () => {
285
+ expect(Array.from(lookAroundWindow([]))).toEqual([]);
286
+ });
287
+
288
+ test('handles smaller than window', () => {
289
+ expect(Array.from(lookAroundWindow([1]))).toEqual([[undefined, 1, undefined]]);
290
+ expect(Array.from(lookAroundWindow([1, 2]))).toEqual([[undefined, 1, 2], [1, 2, undefined]]);
291
+ expect(Array.from(lookAroundWindow([1, 2, 3]))).toEqual([[undefined, 1, 2], [1, 2, 3], [2, 3, undefined]]);
292
+ });
293
+
294
+ test('handles larger than window', () => {
295
+ expect(Array.from(lookAroundWindow([1, 2, 3, 4]))).toEqual([
296
+ [undefined, 1, 2],
297
+ [1, 2, 3],
298
+ [2, 3, 4],
299
+ [3, 4, undefined],
300
+ ]);
301
+ });
302
+ });
303
+
304
+ describe('zip', () => {
305
+ test('handles empty', () => {
306
+ expect(Array.from(zip([], []))).toEqual([]);
307
+ });
308
+
309
+ test('uneven throws error', () => {
310
+ expect(() => Array.from(zip([1], [2, 3]))).toThrow();
311
+ });
312
+
313
+ test('handles even', () => {
314
+ expect(Array.from(zip([1, 2], [3, 4]))).toEqual([[1, 3], [2, 4]]);
315
+ });
316
+ });