@internetarchive/bookreader 5.0.0-11-multiple-files → 5.0.0-110

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 (389) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +616 -1467
  4. package/BookReader/BookReader.js +2 -21564
  5. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  6. package/BookReader/BookReader.js.map +1 -1
  7. package/BookReader/bergamot-translator-worker.js +2966 -0
  8. package/BookReader/bergamot-translator-worker.wasm +0 -0
  9. package/BookReader/hypothesis/LICENSE +50 -0
  10. package/BookReader/hypothesis/README.md +55 -0
  11. package/BookReader/hypothesis/build/boot.js +1 -0
  12. package/BookReader/hypothesis/build/manifest.json +20 -0
  13. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +184 -0
  14. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +798 -0
  16. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  17. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +711 -0
  18. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  19. package/BookReader/hypothesis/build/styles/annotator.css +2235 -0
  20. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  38. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  39. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  40. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  41. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  42. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/katex.min.css +2 -0
  44. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +2 -0
  46. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  47. package/BookReader/hypothesis/build/styles/sidebar.css +2731 -0
  48. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  49. package/BookReader/hypothesis/build/styles/ui-playground.css +2659 -0
  50. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  51. package/BookReader/hypothesis/package.json +126 -0
  52. package/BookReader/ia-bookreader-bundle.js +1907 -0
  53. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  54. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  55. package/BookReader/icons/1up.svg +1 -12
  56. package/BookReader/icons/2up.svg +1 -15
  57. package/BookReader/icons/advance.svg +3 -26
  58. package/BookReader/icons/chevron-right.svg +1 -1
  59. package/BookReader/icons/close-circle-dark.svg +1 -0
  60. package/BookReader/icons/close-circle.svg +1 -1
  61. package/BookReader/icons/fullscreen.svg +1 -17
  62. package/BookReader/icons/fullscreen_exit.svg +1 -17
  63. package/BookReader/icons/hamburger.svg +1 -15
  64. package/BookReader/icons/left-arrow.svg +1 -12
  65. package/BookReader/icons/magnify-minus.svg +1 -16
  66. package/BookReader/icons/magnify-plus.svg +1 -17
  67. package/BookReader/icons/magnify.svg +1 -15
  68. package/BookReader/icons/pause.svg +1 -23
  69. package/BookReader/icons/play.svg +1 -22
  70. package/BookReader/icons/playback-speed.svg +1 -34
  71. package/BookReader/icons/read-aloud.svg +1 -22
  72. package/BookReader/icons/review.svg +3 -22
  73. package/BookReader/icons/slider-toggle.svg +1 -0
  74. package/BookReader/icons/thumbnails.svg +1 -17
  75. package/BookReader/icons/voice.svg +1 -0
  76. package/BookReader/icons/volume-full.svg +1 -22
  77. package/BookReader/images/BRicons.svg +5 -94
  78. package/BookReader/images/books_graphic.svg +1 -177
  79. package/BookReader/images/hypothesis.ico +0 -0
  80. package/BookReader/images/icon_book.svg +1 -12
  81. package/BookReader/images/icon_bookmark.svg +1 -12
  82. package/BookReader/images/icon_experiment.svg +1 -0
  83. package/BookReader/images/icon_gear.svg +1 -14
  84. package/BookReader/images/icon_hamburger.svg +1 -20
  85. package/BookReader/images/icon_home.svg +1 -21
  86. package/BookReader/images/icon_info.svg +1 -11
  87. package/BookReader/images/icon_one_page.svg +1 -8
  88. package/BookReader/images/icon_pause.svg +1 -1
  89. package/BookReader/images/icon_play.svg +1 -1
  90. package/BookReader/images/icon_playback-rate.svg +1 -15
  91. package/BookReader/images/icon_search_button.svg +1 -8
  92. package/BookReader/images/icon_share.svg +1 -9
  93. package/BookReader/images/icon_skip-ahead.svg +1 -6
  94. package/BookReader/images/icon_skip-back.svg +2 -13
  95. package/BookReader/images/icon_speaker.svg +1 -18
  96. package/BookReader/images/icon_speaker_open.svg +1 -10
  97. package/BookReader/images/icon_thumbnails.svg +1 -12
  98. package/BookReader/images/icon_toc.svg +1 -5
  99. package/BookReader/images/icon_two_pages.svg +1 -9
  100. package/BookReader/images/marker_chap-off.svg +1 -11
  101. package/BookReader/images/marker_chap-on.svg +1 -11
  102. package/BookReader/images/marker_srch-on.svg +1 -11
  103. package/BookReader/images/translate.svg +1 -0
  104. package/BookReader/images/unviewable_page.png +0 -0
  105. package/BookReader/jquery-3.js +2 -0
  106. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  107. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  108. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js +1 -165
  110. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  111. package/BookReader/plugins/plugin.chapters.js +19 -301
  112. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  113. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  114. package/BookReader/plugins/plugin.experiments.js +3 -0
  115. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  116. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  117. package/BookReader/plugins/plugin.iframe.js +1 -74
  118. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  119. package/BookReader/plugins/plugin.iiif.js +2 -0
  120. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  121. package/BookReader/plugins/plugin.resume.js +1 -368
  122. package/BookReader/plugins/plugin.resume.js.map +1 -1
  123. package/BookReader/plugins/plugin.search.js +2 -1420
  124. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  125. package/BookReader/plugins/plugin.search.js.map +1 -1
  126. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  127. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  128. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  129. package/BookReader/plugins/plugin.translate.js +137 -0
  130. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  131. package/BookReader/plugins/plugin.translate.js.map +1 -0
  132. package/BookReader/plugins/plugin.tts.js +2 -9193
  133. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  134. package/BookReader/plugins/plugin.tts.js.map +1 -1
  135. package/BookReader/plugins/plugin.url.js +1 -269
  136. package/BookReader/plugins/plugin.url.js.map +1 -1
  137. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  138. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  139. package/BookReader/plugins/translator-worker.js +2 -0
  140. package/BookReader/plugins/translator-worker.js.map +1 -0
  141. package/BookReader/silence.mp3 +0 -0
  142. package/BookReader/translator-worker.js +475 -0
  143. package/BookReader/webcomponents-bundle.js +3 -0
  144. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  145. package/BookReader/webcomponents-bundle.js.map +1 -0
  146. package/README.md +14 -3
  147. package/jsconfig.json +19 -0
  148. package/package.json +92 -70
  149. package/src/BookReader/BookModel.js +92 -46
  150. package/src/BookReader/DragScrollable.js +233 -0
  151. package/src/BookReader/ImageCache.js +49 -16
  152. package/src/BookReader/Mode1Up.js +66 -356
  153. package/src/BookReader/Mode1UpLit.js +392 -0
  154. package/src/BookReader/Mode2Up.js +87 -1315
  155. package/src/BookReader/Mode2UpLit.js +788 -0
  156. package/src/BookReader/ModeAbstract.js +43 -0
  157. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  158. package/src/BookReader/ModeSmoothZoom.js +312 -0
  159. package/src/BookReader/ModeThumb.js +30 -16
  160. package/src/BookReader/Navbar/Navbar.js +201 -76
  161. package/src/BookReader/PageContainer.js +120 -23
  162. package/src/BookReader/ReduceSet.js +3 -3
  163. package/src/BookReader/Toolbar/Toolbar.js +19 -41
  164. package/src/BookReader/events.js +3 -3
  165. package/src/BookReader/options.js +94 -17
  166. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  167. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  168. package/src/BookReader/utils/SelectionObserver.js +45 -0
  169. package/src/BookReader/utils/classes.js +1 -1
  170. package/src/BookReader/utils.js +141 -13
  171. package/src/BookReader.js +711 -1241
  172. package/src/BookReaderPlugin.js +52 -0
  173. package/src/assets/icons/close-circle-dark.svg +1 -0
  174. package/src/assets/icons/magnify-minus.svg +3 -7
  175. package/src/assets/icons/magnify-plus.svg +3 -7
  176. package/src/assets/icons/slider-toggle.svg +1 -0
  177. package/src/assets/icons/voice.svg +1 -0
  178. package/src/assets/images/hypothesis.ico +0 -0
  179. package/src/assets/images/icon_experiment.svg +1 -0
  180. package/src/assets/images/translate.svg +1 -0
  181. package/src/assets/images/unviewable_page.png +0 -0
  182. package/src/assets/silence.mp3 +0 -0
  183. package/src/css/BookReader.scss +1 -17
  184. package/src/css/_BRBookmarks.scss +1 -1
  185. package/src/css/_BRComponent.scss +1 -1
  186. package/src/css/_BRicon.scss +8 -2
  187. package/src/css/_BRmain.scss +33 -27
  188. package/src/css/_BRnav.scss +74 -70
  189. package/src/css/_BRpages.scss +171 -42
  190. package/src/css/_BRsearch.scss +69 -235
  191. package/src/css/_BRtoolbar.scss +5 -5
  192. package/src/css/_TextSelection.scss +129 -24
  193. package/src/css/_colorbox.scss +2 -2
  194. package/src/css/_controls.scss +24 -7
  195. package/src/css/_icons.scss +14 -1
  196. package/src/{BookNavigator/assets → css}/button-base.js +10 -3
  197. package/src/css/icon_checkmark.js +9 -0
  198. package/src/css/sharedStyles.js +15 -0
  199. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  200. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +29 -25
  201. package/src/ia-bookreader/ia-bookreader.js +666 -0
  202. package/src/ia-bookreader/sharing.js +27 -0
  203. package/src/ia-bookreader/viewable-files.js +98 -0
  204. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  205. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  206. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  207. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  208. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +44 -32
  209. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  210. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +5 -10
  211. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  212. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  213. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  214. package/src/plugins/plugin.archive_analytics.js +84 -78
  215. package/src/plugins/plugin.autoplay.js +99 -104
  216. package/src/plugins/plugin.chapters.js +310 -201
  217. package/src/plugins/plugin.experiments.js +321 -0
  218. package/src/plugins/plugin.iframe.js +1 -1
  219. package/src/plugins/plugin.iiif.js +141 -0
  220. package/src/plugins/plugin.resume.js +53 -50
  221. package/src/plugins/plugin.text_selection.js +522 -219
  222. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  223. package/src/plugins/search/plugin.search.js +380 -360
  224. package/src/{BookNavigator → plugins}/search/search-provider.js +94 -32
  225. package/src/{BookNavigator → plugins}/search/search-results.js +108 -90
  226. package/src/plugins/search/utils.js +50 -0
  227. package/src/plugins/search/view.js +79 -210
  228. package/src/plugins/translate/TranslationManager.js +164 -0
  229. package/src/plugins/translate/plugin.translate.js +512 -0
  230. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  231. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  232. package/src/plugins/tts/PageChunk.js +33 -21
  233. package/src/plugins/tts/PageChunkIterator.js +11 -17
  234. package/src/plugins/tts/WebTTSEngine.js +131 -91
  235. package/src/plugins/tts/plugin.tts.js +345 -350
  236. package/src/plugins/tts/utils.js +77 -49
  237. package/src/plugins/url/UrlPlugin.js +191 -0
  238. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  239. package/src/util/TextSelectionManager.js +282 -0
  240. package/src/util/browserSniffing.js +33 -1
  241. package/src/util/cache.js +20 -0
  242. package/src/util/docCookies.js +21 -2
  243. package/src/util/lit.js +15 -0
  244. package/src/util/strings.js +1 -0
  245. package/.babelrc +0 -12
  246. package/.dependabot/config.yml +0 -6
  247. package/.eslintrc.js +0 -49
  248. package/.gitattributes +0 -2
  249. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  250. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  251. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  252. package/.github/workflows/node.js.yml +0 -28
  253. package/.github/workflows/npm-publish.yml +0 -47
  254. package/.testcaferc.json +0 -5
  255. package/BookReader/bookreader-component-bundle.js +0 -14330
  256. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  257. package/BookReader/bookreader-component-bundle.js.map +0 -1
  258. package/BookReader/icons/sort-ascending.svg +0 -1
  259. package/BookReader/icons/sort-descending.svg +0 -1
  260. package/BookReader/jquery-1.10.1.js +0 -108
  261. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  262. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  263. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  264. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  265. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  266. package/BookReaderDemo/BookReaderDemo.css +0 -41
  267. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  268. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  269. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  270. package/BookReaderDemo/IIIFBookReader.js +0 -207
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  273. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  274. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  275. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  276. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  277. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  278. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  279. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  280. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  281. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  282. package/BookReaderDemo/demo-advanced.html +0 -33
  283. package/BookReaderDemo/demo-autoplay.html +0 -38
  284. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  285. package/BookReaderDemo/demo-embed.html +0 -26
  286. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  287. package/BookReaderDemo/demo-fullscreen.html +0 -33
  288. package/BookReaderDemo/demo-iiif.html +0 -34
  289. package/BookReaderDemo/demo-iiif.js +0 -26
  290. package/BookReaderDemo/demo-internetarchive.html +0 -74
  291. package/BookReaderDemo/demo-multiple.html +0 -43
  292. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  293. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  294. package/BookReaderDemo/demo-simple.html +0 -34
  295. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  296. package/BookReaderDemo/immersion-1up.html +0 -64
  297. package/BookReaderDemo/immersion-mode.html +0 -35
  298. package/BookReaderDemo/toggle_controls.html +0 -53
  299. package/BookReaderDemo/view_mode.html +0 -39
  300. package/BookReaderDemo/viewmode-cycle.html +0 -41
  301. package/CHANGELOG.md +0 -476
  302. package/CONTRIBUTING.md +0 -7
  303. package/codecov.yml +0 -17
  304. package/index.html +0 -31
  305. package/karma.conf.js +0 -23
  306. package/screenshot.png +0 -0
  307. package/scripts/postversion.js +0 -10
  308. package/scripts/preversion.js +0 -14
  309. package/scripts/version.js +0 -26
  310. package/src/BookNavigator/BookModel.js +0 -14
  311. package/src/BookNavigator/BookNavigator.js +0 -451
  312. package/src/BookNavigator/assets/book-loader.js +0 -27
  313. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  314. package/src/BookNavigator/assets/icon_close.js +0 -3
  315. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  316. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  317. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  318. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  319. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  320. package/src/BookNavigator/search/a-search-result.js +0 -55
  321. package/src/BookNavigator/volumes/volumes-provider.js +0 -75
  322. package/src/BookNavigator/volumes/volumes.js +0 -161
  323. package/src/BookReader/DebugConsole.js +0 -54
  324. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  325. package/src/ItemNavigator/ItemNavigator.js +0 -372
  326. package/src/ItemNavigator/providers/sharing.js +0 -29
  327. package/src/assets/icons/sort-ascending.svg +0 -1
  328. package/src/assets/icons/sort-descending.svg +0 -1
  329. package/src/css/_MobileNav.scss +0 -194
  330. package/src/dragscrollable-br.js +0 -261
  331. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  332. package/src/plugins/plugin.mobile_nav.js +0 -287
  333. package/tests/BookReader/BookModel.test.js +0 -312
  334. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  335. package/tests/BookReader/DebugConsole.test.js +0 -25
  336. package/tests/BookReader/ImageCache.test.js +0 -150
  337. package/tests/BookReader/Mode1Up.test.js +0 -164
  338. package/tests/BookReader/Mode2Up.test.js +0 -247
  339. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  340. package/tests/BookReader/PageContainer.test.js +0 -115
  341. package/tests/BookReader/ReduceSet.test.js +0 -38
  342. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  343. package/tests/BookReader/utils/classes.test.js +0 -88
  344. package/tests/BookReader/utils.test.js +0 -109
  345. package/tests/BookReader.options.test.js +0 -39
  346. package/tests/BookReader.test.js +0 -301
  347. package/tests/e2e/README.md +0 -75
  348. package/tests/e2e/autoplay.test.js +0 -13
  349. package/tests/e2e/base.test.js +0 -35
  350. package/tests/e2e/helpers/base.js +0 -258
  351. package/tests/e2e/helpers/debug.js +0 -13
  352. package/tests/e2e/helpers/desktopSearch.js +0 -72
  353. package/tests/e2e/helpers/mobileSearch.js +0 -85
  354. package/tests/e2e/helpers/mockSearch.js +0 -93
  355. package/tests/e2e/helpers/rightToLeft.js +0 -29
  356. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  357. package/tests/e2e/models/BookReader.js +0 -11
  358. package/tests/e2e/models/Navigation.js +0 -56
  359. package/tests/e2e/rightToLeft.test.js +0 -20
  360. package/tests/e2e/viewmode.test.js +0 -37
  361. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  362. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  363. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  364. package/tests/karma/BookNavigator/search-results.test.js +0 -240
  365. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  366. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  367. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  368. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  369. package/tests/plugins/plugin.autoplay.test.js +0 -52
  370. package/tests/plugins/plugin.chapters.test.js +0 -130
  371. package/tests/plugins/plugin.iframe.test.js +0 -42
  372. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  373. package/tests/plugins/plugin.resume.test.js +0 -98
  374. package/tests/plugins/plugin.text_selection.test.js +0 -203
  375. package/tests/plugins/plugin.url.test.js +0 -129
  376. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  377. package/tests/plugins/search/plugin.search.test.js +0 -166
  378. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  379. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  380. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  381. package/tests/plugins/tts/PageChunk.test.js +0 -57
  382. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  383. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  384. package/tests/plugins/tts/utils.test.js +0 -133
  385. package/tests/util/browserSniffing.test.js +0 -56
  386. package/tests/util/docCookies.test.js +0 -15
  387. package/tests/util/strings.test.js +0 -63
  388. package/tests/utils.js +0 -42
  389. package/webpack.config.js +0 -86
@@ -1,9 +1,6 @@
1
- /* global BookReader */
1
+ // @ts-check
2
2
  /**
3
3
  * Plugin for Archive.org book search
4
- * NOTE: This script must be loaded AFTER `plugin.mobile_nav.js`
5
- * as it mutates mobile nav drawer
6
- *
7
4
  * Events fired at various points throughout search processing are published
8
5
  * on the document DOM element. These can be subscribed to using jQuery's event
9
6
  * binding method `$.fn.on`. All of the events are prefixed with a BookReader
@@ -20,412 +17,435 @@
20
17
  * the book has not had OCR text indexed yet. Receives `instance`
21
18
  * @event BookReader:SearchCallbackEmpty - When no results found. Receives
22
19
  * `instance`
20
+ * @event BookReader:SearchCanceled - When no results found. Receives
21
+ * `instance`
23
22
  */
23
+ import { poll } from '../../BookReader/utils.js';
24
+ import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
24
25
  import SearchView from './view.js';
26
+ import { marshallSearchResults } from './utils.js';
27
+ import { BookReaderPlugin } from '../../BookReaderPlugin.js';
28
+ import { applyVariables } from '../../util/strings.js';
29
+ import { toISO6391 } from '../tts/utils.js';
30
+ /** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
31
+ /** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
32
+ /** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */
33
+ /** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */
34
+
35
+ // @ts-ignore
36
+ const BookReader = /** @type {typeof import('@/src/BookReader.js').default} */(window.BookReader);
37
+
38
+ export class SearchPlugin extends BookReaderPlugin {
39
+ options = {
40
+ enabled: true,
41
+ preTag: '{{{',
42
+ postTag: '}}}',
43
+ /**
44
+ * @type {import('@/src/util/strings.js').StringWithVars}
45
+ * Provides the variables: `query`, `preTag`, and `postTag` (from these options)
46
+ */
47
+ searchInsideUrl: '/fulltext/inside.php?' + [
48
+ 'q={{query|urlencode}}',
49
+ 'pre_tag={{preTag|urlencode}}',
50
+ 'post_tag={{postTag|urlencode}}',
51
+ ].join('&'),
52
+ /** @type {string} */
53
+ initialSearchTerm: null,
54
+ goToFirstResult: false,
55
+ }
25
56
 
26
- jQuery.extend(BookReader.defaultOptions, {
27
- server: 'ia600609.us.archive.org',
28
- bookId: '',
29
- subPrefix: '',
30
- bookPath: '',
31
- enableSearch: true,
32
- searchInsideUrl: '/fulltext/inside.php',
33
- initialSearchTerm: null,
34
- });
35
-
36
- /** @override */
37
- BookReader.prototype.setup = (function (super_) {
38
- return function (options) {
39
- super_.call(this, options);
57
+ /**
58
+ * @override
59
+ * @param {Partial<SearchPlugin['options']>} options
60
+ **/
61
+ setup(options) {
62
+ super.setup(options);
40
63
 
41
64
  this.searchTerm = '';
65
+ /** @type {SearchInsideResults | null} */
42
66
  this.searchResults = null;
43
- this.searchInsideUrl = options.searchInsideUrl;
44
- this.enableSearch = options.enableSearch;
45
- this.goToFirstResult = false;
46
-
47
- // Base server used by some api calls
48
- this.bookId = options.bookId;
49
- this.server = options.server;
50
- this.subPrefix = options.subPrefix;
51
- this.bookPath = options.bookPath;
52
-
53
- if (this.searchView) { return; }
54
- this.searchView = new SearchView({
55
- br: this,
56
- selector: '#BRsearch_tray',
57
- });
58
- };
59
- })(BookReader.prototype.setup);
60
-
61
- /** @override */
62
- BookReader.prototype.init = (function (super_) {
63
- return function () {
64
- super_.call(this);
67
+ this.searchInsideUrl = this.options.searchInsideUrl;
68
+ this.enabled = this.options.enabled;
69
+ this.searchXHR = null;
70
+
71
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
72
+ this._searchBoxesByIndex = {};
73
+
74
+ if (this.enabled) {
75
+ this.searchView = new SearchView({
76
+ br: this.br,
77
+ searchCancelledCallback: () => {
78
+ this._cancelSearch();
79
+ this.br.trigger('SearchCanceled', { term: this.searchTerm, instance: this.br });
80
+ },
81
+ });
82
+ } else {
83
+ this.searchView = null;
84
+ }
85
+ }
65
86
 
66
- if (this.options.enableSearch && this.options.initialSearchTerm) {
87
+ /** @override */
88
+ init() {
89
+ super.init();
90
+
91
+ if (!this.enabled) return;
92
+
93
+ this.searchView.init();
94
+ if (this.options.initialSearchTerm) {
95
+ /**
96
+ * this.search() take two parameter
97
+ * 1. this.options.initialSearchTerm - search term
98
+ * 2. {
99
+ * goToFirstResult: this.options.goToFirstResult,
100
+ * suppressFragmentChange: false // always want to change fragment in URL
101
+ * }
102
+ */
67
103
  this.search(
68
104
  this.options.initialSearchTerm,
69
- { goToFirstResult: this.goToFirstResult, suppressFragmentChange: true }
105
+ { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false },
70
106
  );
71
107
  }
72
- };
73
- })(BookReader.prototype.init);
74
-
75
- /** @override */
76
- BookReader.prototype.buildMobileDrawerElement = (function (super_) {
77
- return function () {
78
- const $el = super_.call(this);
79
- if (!this.enableSearch) { return; }
80
- if (this.searchView.dom.mobileSearch) {
81
- $el.find('.BRmobileMenu__moreInfoRow').after(this.searchView.dom.mobileSearch);
82
- }
83
- return $el;
84
- };
85
- })(BookReader.prototype.buildMobileDrawerElement);
86
-
87
- /** @override */
88
- BookReader.prototype.buildToolbarElement = (function (super_) {
89
- return function () {
90
- const $el = super_.call(this);
91
- if (!this.enableSearch) { return; }
108
+ }
109
+
110
+ /**
111
+ * @override
112
+ * @protected
113
+ * @param {JQuery<HTMLElement>} $toolbarElement
114
+ */
115
+ _configureToolbar($toolbarElement) {
116
+ if (!this.enabled) { return; }
92
117
  if (this.searchView.dom.toolbarSearch) {
93
- $el.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);
118
+ $toolbarElement.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);
94
119
  }
95
- return $el;
96
- };
97
- })(BookReader.prototype.buildToolbarElement);
98
-
99
- /**
100
- * @typedef {object} SearchOptions
101
- * @property {boolean} goToFirstResult
102
- * @property {boolean} disablePopup
103
- * @property {(null|function)} error - @deprecated at v.5.0
104
- * @property {(null|function)} success - @deprecated at v.5.0
105
- */
106
-
107
- /**
108
- * Submits search request
109
- *
110
- * @param {string} term
111
- * @param {SearchOptions} overrides
112
- */
113
- BookReader.prototype.search = function(term = '', overrides = {}) {
114
- /** @type {SearchOptions} */
115
- const defaultOptions = {
116
- goToFirstResult: false, /* jump to the first result (default=false) */
117
- disablePopup: false, /* don't show the modal progress (default=false) */
118
- suppressFragmentChange: false, /* don't change the URL on initial load */
119
- error: null, /* optional error handler (default=null) */
120
- success: null, /* optional success handler (default=null) */
121
-
122
- };
123
- const options = jQuery.extend({}, defaultOptions, overrides);
124
- this.suppressFragmentChange = options.suppressFragmentChange;
125
-
126
- // strip slashes, since this goes in the url
127
- this.searchTerm = term.replace(/\//g, ' ');
128
-
129
- if (!options.suppressFragmentChange) {
130
- this.trigger(BookReader.eventNames.fragmentChange);
120
+ return $toolbarElement;
131
121
  }
132
122
 
133
- // Add quotes to the term. This is to compenstate for the backends default OR query
134
- // term = term.replace(/['"]+/g, '');
135
- // term = '"' + term + '"';
136
-
137
- // Remove the port and userdir
138
- const serverPath = this.server.replace(/:.+/, '');
139
- const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;
140
-
141
- // Remove subPrefix from end of path
142
- let path = this.bookPath;
143
- const subPrefixWithSlash = `/${this.subPrefix}`;
144
- if (this.bookPath.length - this.bookPath.lastIndexOf(subPrefixWithSlash) == subPrefixWithSlash.length) {
145
- path = this.bookPath.substr(0, this.bookPath.length - subPrefixWithSlash.length);
123
+ /**
124
+ * @override
125
+ * @param {import ("@/src/BookReader/PageContainer.js").PageContainer} pageContainer
126
+ */
127
+ _configurePageContainer(pageContainer) {
128
+ if (this.enabled && pageContainer.page && pageContainer.page.index in this._searchBoxesByIndex) {
129
+ const pageIndex = pageContainer.page.index;
130
+ const boxes = this._searchBoxesByIndex[pageIndex];
131
+ renderBoxesInPageContainerLayer(
132
+ 'searchHiliteLayer',
133
+ boxes,
134
+ pageContainer.page,
135
+ pageContainer.$container[0],
136
+ boxes.map(b => `match-index-${b.matchIndex}`),
137
+ );
138
+ }
139
+ return pageContainer;
146
140
  }
147
141
 
148
- const urlParams = {
149
- item_id: this.bookId,
150
- doc: this.subPrefix,
151
- path,
152
- q: term,
153
- };
154
-
155
- // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
156
- const paramStr = $.param(urlParams).replace(/%2F/g, '/');
157
-
158
- const url = `${baseUrl}${paramStr}`;
142
+ /**
143
+ * Submits search request
144
+ *
145
+ * @param {string} term
146
+ * @param {Partial<SearchOptions>} overrides
147
+ */
148
+ async search(term = '', overrides = {}) {
149
+ /** @type {SearchOptions} */
150
+ const defaultOptions = {
151
+ goToFirstResult: false, /* jump to the first result (default=false) */
152
+ disablePopup: false, /* don't show the modal progress (default=false) */
153
+ suppressFragmentChange: false, /* don't change the URL on initial load */
154
+ error: null, /* optional error handler (default=null) */
155
+ success: null, /* optional success handler (default=null) */
156
+
157
+ };
158
+ const options = jQuery.extend({}, defaultOptions, overrides);
159
+ this.suppressFragmentChange = options.suppressFragmentChange;
160
+ this.searchCancelled = false;
161
+
162
+ // strip slashes, since this goes in the url
163
+ this.searchTerm = term.replace(/\//g, ' ');
164
+
165
+ if (!options.suppressFragmentChange) {
166
+ this.br.trigger(BookReader.eventNames.fragmentChange);
167
+ }
159
168
 
160
- const processSearchResults = (searchInsideResults) => {
161
- const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
162
- const hasCustomError = typeof options.error === 'function';
163
- const hasCustomSuccess = typeof options.success === 'function';
169
+ // Add quotes to the term. This is to compenstate for the backends default OR query
170
+ // term = term.replace(/['"]+/g, '');
171
+ // term = '"' + term + '"';
164
172
 
165
- if (responseHasError) {
166
- hasCustomError
167
- ? options.error.call(this, searchInsideResults, options)
168
- : this.BRSearchCallbackError(searchInsideResults, options);
169
- } else {
170
- hasCustomSuccess
171
- ? options.success.call(this, searchInsideResults, options)
172
- : this.BRSearchCallback(searchInsideResults, options);
173
- }
174
- };
173
+ const url = applyVariables(this.options.searchInsideUrl, this.br.options.vars, {
174
+ query: term,
175
+ preTag: this.options.preTag,
176
+ postTag: this.options.postTag,
177
+ });
175
178
 
176
- this.trigger('SearchStarted', { term: this.searchTerm });
177
- return $.ajax({
178
- url: url,
179
- dataType: 'jsonp'
180
- }).then(processSearchResults);
181
- };
179
+ const callSearchResultsCallback = (searchInsideResults) => {
180
+ if (this.searchCancelled) {
181
+ return;
182
+ }
183
+ const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
184
+ const hasCustomError = typeof options.error === 'function';
185
+ const hasCustomSuccess = typeof options.success === 'function';
186
+
187
+ if (responseHasError) {
188
+ console.error('Search Inside Response Error', searchInsideResults.error || 'matches.length == 0');
189
+ hasCustomError
190
+ ? options.error.call(this, searchInsideResults, options)
191
+ : this.BRSearchCallbackError(searchInsideResults);
192
+ } else {
193
+ hasCustomSuccess
194
+ ? options.success.call(this, searchInsideResults, options)
195
+ : this.BRSearchCallback(searchInsideResults, options);
196
+ }
197
+ };
198
+
199
+ this.br.trigger('SearchStarted', { term: this.searchTerm, instance: this.br });
200
+ callSearchResultsCallback(await $.ajax({
201
+ url: url,
202
+ cache: true,
203
+ xhrFields: {
204
+ withCredentials: this.br.protected,
205
+ },
206
+ beforeSend: xhr => { this.searchXHR = xhr; },
207
+ }));
208
+ }
182
209
 
183
- /**
184
- * @typedef {object} SearchInsideMatchBox
185
- * @property {number} page
186
- * @property {number} r
187
- * @property {number} l
188
- * @property {number} b
189
- * @property {number} t
190
- * @property {HTMLDivElement} [div]
191
- */
210
+ /**
211
+ * cancels AJAX Call
212
+ * emits custom event
213
+ */
214
+ _cancelSearch() {
215
+ this.searchXHR?.abort();
216
+ this.searchView.clearSearchFieldAndResults(false);
217
+ this.searchTerm = '';
218
+ this.searchXHR = null;
219
+ this.searchCancelled = true;
220
+ this.searchResults = null;
221
+ }
192
222
 
193
- /**
194
- * @typedef {object} SearchInsideMatch
195
- * @property {string} text
196
- * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
197
- */
223
+ /**
224
+ * External function to cancel search
225
+ * checks for term & xhr in flight before running
226
+ */
227
+ cancelSearchRequest() {
228
+ this.searchCancelled = true;
229
+ if (this.searchXHR !== null) {
230
+ this._cancelSearch();
231
+ this.searchView.toggleSearchPending();
232
+ this.br.trigger('SearchCanceled', { term: this.searchTerm, instance: this.br });
233
+ }
234
+ }
198
235
 
199
- /**
200
- * @typedef {object} SearchInsideResults
201
- * @property {string} error
202
- * @property {SearchInsideMatch[]} matches
203
- * @property {boolean} indexed
204
- */
236
+ /**
237
+ * Search Results return handler
238
+ * @param {SearchInsideResults} results
239
+ * @param {object} options
240
+ * @param {boolean} options.goToFirstResult
241
+ */
242
+ BRSearchCallback(results, options) {
243
+ const bookLangCode = toISO6391(this.br.options.bookLanguage);
244
+ marshallSearchResults(
245
+ results,
246
+ pageNum => this.br.book.getPageNum(this.br.book.leafNumToIndex(pageNum)),
247
+ this.options.preTag,
248
+ this.options.postTag,
249
+ bookLangCode,
250
+ );
251
+ this.searchResults = results || null;
252
+
253
+ this.updateSearchHilites();
254
+ this.br.removeProgressPopup();
255
+ if (options.goToFirstResult) {
256
+ this.jumpToMatch(0);
257
+ }
258
+ this.br.trigger('SearchCallback', { results, options, instance: this.br });
259
+ }
205
260
 
206
- /**
207
- * Search Results return handler
208
- * @callback
209
- * @param {SearchInsideResults} results
210
- * @param {object} options
211
- * @param {boolean} options.goToFirstResult
212
- */
213
- BookReader.prototype.BRSearchCallback = function(results, options) {
214
- this.searchResults = results;
261
+ /**
262
+ * Main search results error handler
263
+ * @param {SearchInsideResults} results
264
+ */
265
+ BRSearchCallbackError(results) {
266
+ this._BRSearchCallbackError(results);
267
+ }
215
268
 
216
- this.updateSearchHilites();
217
- this.removeProgressPopup();
218
- if (options.goToFirstResult) {
219
- this._searchPluginGoToResult(results.matches[0].par[0].page);
269
+ /**
270
+ * @private draws search results error
271
+ * @param {SearchInsideResults} results
272
+ */
273
+ _BRSearchCallbackError(results) {
274
+ this.searchResults = results;
275
+ const payload = {
276
+ term: this.searchTerm,
277
+ results,
278
+ instance: this.br,
279
+ };
280
+ if (results.error) {
281
+ this.br.trigger('SearchCallbackError', payload);
282
+ } else if (0 == results.matches.length) {
283
+ if (false === results.indexed) {
284
+ this.br.trigger('SearchCallbackBookNotIndexed', payload);
285
+ return;
286
+ }
287
+ this.br.trigger('SearchCallbackEmpty', payload);
288
+ }
220
289
  }
221
- this.trigger('SearchCallback', { results, options, instance: this });
222
- }
223
290
 
224
- /**
225
- * Main search results error handler
226
- * @callback
227
- * @param {SearchInsideResults} results
228
- */
229
- BookReader.prototype.BRSearchCallbackError = function(results) {
230
- this._BRSearchCallbackError(results);
231
- };
291
+ /**
292
+ * updates search on-page highlights controller
293
+ */
294
+ updateSearchHilites() {
295
+ /** @type {SearchInsideMatch[]} */
296
+ const matches = this.searchResults?.matches || [];
297
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
298
+ const boxesByIndex = {};
299
+
300
+ // Clear any existing svg layers
301
+ this.removeSearchHilites();
302
+
303
+ // Group by pageIndex
304
+ for (const match of matches) {
305
+ for (const box of match.par[0].boxes) {
306
+ const pageIndex = this.br.book.leafNumToIndex(box.page);
307
+ const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
308
+ pageBoxes.push(box);
309
+ }
310
+ }
232
311
 
233
- /**
234
- * @private draws search results error
235
- * @callback
236
- * @param {SearchInsideResults} results
237
- * @param {jQuery} $el
238
- * @param {boolean} fade
239
- */
240
- BookReader.prototype._BRSearchCallbackError = function(results) {
241
- this.searchResults = results;
242
- const basePayload = {
243
- term: this.searchTerm,
244
- instance: this,
245
- };
246
- if (results.error) {
247
- const payload = Object.assign({}, basePayload, { results });
248
- this.trigger('SearchCallbackError', payload);
249
- } else if (0 == results.matches.length) {
250
- if (false === results.indexed) {
251
- this.trigger('SearchCallbackBookNotIndexed', basePayload);
252
- return;
312
+ // update any already created pages
313
+ for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
314
+ const pageIndex = parseFloat(pageIndexString);
315
+ const page = this.br.book.getPage(pageIndex);
316
+ const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
317
+ for (const container of pageContainers) {
318
+ renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));
319
+ }
253
320
  }
254
- this.trigger('SearchCallbackEmpty', basePayload);
321
+
322
+ this._searchBoxesByIndex = boxesByIndex;
255
323
  }
256
- };
257
324
 
258
- /**
259
- * updates search on-page highlights controller
260
- */
261
- BookReader.prototype.updateSearchHilites = function() {
262
- if (this.constMode2up == this.mode) {
263
- this.updateSearchHilites2UP();
264
- return;
325
+ /**
326
+ * remove search highlights
327
+ */
328
+ removeSearchHilites() {
329
+ $(this.br.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
265
330
  }
266
- this.updateSearchHilites1UP();
267
- };
268
331
 
269
- /**
270
- * update search on-page highlights in 1up mode
271
- */
272
- BookReader.prototype.updateSearchHilites1UP = function() {
273
- const results = this.searchResults;
274
- if (null == results) return;
275
- results.matches.forEach(match => {
276
- match.par[0].boxes.forEach(box => {
277
- const pageIndex = this.leafNumToIndex(box.page);
278
- const pageIsInView = jQuery.inArray(pageIndex, this.displayedIndices) >= 0;
279
- if (pageIsInView) {
280
- if (!box.div) {
281
- //create a div for the search highlight, and stash it in the box object
282
- box.div = document.createElement('div');
283
- $(box.div).prop('className', 'BookReaderSearchHilite').appendTo(this.$(`.pagediv${pageIndex}`));
284
- }
285
- const page = this._models.book.getPage(pageIndex);
286
- const highlight = {
287
- width: this._modes.mode1Up.physicalInchesToDisplayPixels((box.r - box.l) / page.ppi),
288
- height: this._modes.mode1Up.physicalInchesToDisplayPixels((box.b - box.t) / page.ppi),
289
- left: this._modes.mode1Up.physicalInchesToDisplayPixels(box.l / page.ppi),
290
- top: this._modes.mode1Up.physicalInchesToDisplayPixels(box.t / page.ppi),
291
- };
292
- $(box.div).css(highlight);
293
- } else {
294
- if (box.div) {
295
- $(box.div).remove();
296
- box.div = null;
297
- }
332
+ /**
333
+ * Goes to the page specified. If the page is not viewable, tries to load the page
334
+ * FIXME Most of this logic is IA specific, and should be less integrated into here
335
+ * or at least more configurable.
336
+ * @param {number} matchIndex
337
+ */
338
+ async jumpToMatch(matchIndex) {
339
+ const match = this.searchResults?.matches[matchIndex];
340
+ const book = this.br.book;
341
+ const pageIndex = book.leafNumToIndex(match.par[0].page);
342
+ const page = book.getPage(pageIndex);
343
+ const onNearbyPage = Math.abs(this.br.currentIndex() - pageIndex) < 3;
344
+ let makeUnviewableAtEnd = false;
345
+ if (!page.isViewable) {
346
+ const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
347
+ id: this.br.options.bookId,
348
+ subprefix: this.br.options.subPrefix,
349
+ leafNum: page.leafNum,
350
+ })).then(r => r.json());
351
+
352
+ for (const leafNum of resp.value) {
353
+ book.getPage(book.leafNumToIndex(leafNum)).makeViewable();
298
354
  }
299
- });
300
- });
301
- };
302
355
 
303
- /**
304
- * update search on-page highlights in 2up mode
305
- */
306
- BookReader.prototype.updateSearchHilites2UP = function() {
307
- const results = this.searchResults;
308
-
309
- if (results === null) return;
310
-
311
- const { matches } = results;
312
- matches.forEach((match) => {
313
- match.par[0].boxes.forEach(box => {
314
- const pageIndex = this.leafNumToIndex(match.par[0].page);
315
- const pageIsInView = jQuery.inArray(pageIndex, this.displayedIndices) >= 0;
316
- const { isViewable } = this._models.book.getPage(pageIndex);
317
-
318
- if (pageIsInView && isViewable) {
319
- if (!box.div) {
320
- //create a div for the search highlight, and stash it in the box object
321
- box.div = document.createElement('div');
322
- $(box.div).addClass('BookReaderSearchHilite')
323
- .appendTo(this.refs.$brTwoPageView);
324
- }
325
- this.setHilightCss2UP(box.div, pageIndex, box.l, box.r, box.t, box.b);
326
- } else {
327
- // clear stale reference
328
- if (box.div) {
329
- $(box.div).remove();
330
- box.div = null;
331
- }
356
+ // not able to show page; make the page viewable anyways so that it can
357
+ // actually open. On IA, it has a fallback to a special error page.
358
+ if (!resp.value.length) {
359
+ book.getPage(pageIndex).makeViewable();
360
+ makeUnviewableAtEnd = true;
332
361
  }
333
- });
334
- });
335
- };
336
362
 
337
- /**
338
- * remove search highlights
339
- */
340
- BookReader.prototype.removeSearchHilites = function() {
341
- const results = this.searchResults;
342
- if (null == results || !results.matches) { return; }
343
- results.matches.forEach(match => {
344
- match.par[0].boxes.forEach(box => {
345
- if (null != box.div) {
346
- $(box.div).remove();
347
- box.div = null;
363
+ // Trigger an update of book
364
+ this.br._modes.mode1Up.mode1UpLit.updatePages();
365
+ if (this.br.activeMode == this.br._modes.mode1Up) {
366
+ await this.br._modes.mode1Up.mode1UpLit.updateComplete;
348
367
  }
349
- });
350
- });
351
- };
368
+ }
369
+ /* this updates the URL */
370
+ if (!this.br._isIndexDisplayed(pageIndex)) {
371
+ this.suppressFragmentChange = false;
372
+ this.br.jumpToIndex(pageIndex, { ariaLive: true });
373
+ }
352
374
 
353
- /**
354
- * @private
355
- * Goes to the page specified. If the page is not viewable, tries to load the page
356
- * FIXME Most of this logic is IA specific, and should be less integrated into here
357
- * or at least more configurable.
358
- * @param {PageIndex} pageIndex
359
- */
360
- BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
361
- const { book } = this._models;
362
- const page = book.getPage(pageIndex);
363
- let makeUnviewableAtEnd = false;
364
- if (!page.isViewable) {
365
- const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
366
- id: this.options.bookId,
367
- subprefix: this.options.subPrefix,
368
- leafNum: page.leafNum,
369
- })).then(r => r.json());
370
-
371
- for (const leafNum of resp.value) {
372
- book.getPage(book.leafNumToIndex(leafNum)).makeViewable();
375
+ // Reset it to unviewable if it wasn't resolved
376
+ if (makeUnviewableAtEnd) {
377
+ book.getPage(pageIndex).makeViewable(false);
373
378
  }
374
379
 
375
- // not able to show page; make the page viewable anyways so that it can
376
- // actually open. On IA, it has a fallback to a special error page.
377
- if (!resp.value.length) {
378
- book.getPage(pageIndex).makeViewable();
379
- makeUnviewableAtEnd = true;
380
+ // Scroll/flash in the ui
381
+ const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });
382
+ if ($boxes.length) {
383
+ $boxes.css('animation', 'none');
384
+ $boxes[0].scrollIntoView({
385
+ // Only vertically center the highlight if we're in 1up or in full screen. In
386
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
387
+ // center the highlight 🙄 See:
388
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
389
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
390
+ // full-width, and covers up the last line of the highlight.
391
+ block: this.br.constMode1up == this.br.mode || this.br.isFullscreenActive ? 'center' : 'nearest',
392
+ inline: 'center',
393
+ behavior: onNearbyPage ? 'smooth' : 'auto',
394
+ });
395
+ // wait for animation to start
396
+ await new Promise(resolve => setTimeout(resolve, 100));
397
+ $boxes.removeAttr("style");
380
398
  }
381
399
  }
382
- /* this updates the URL */
383
- this.suppressFragmentChange = false;
384
- this.jumpToIndex(pageIndex);
385
400
 
386
- // Reset it to unviewable if it wasn't resolved
387
- if (makeUnviewableAtEnd) {
388
- book.getPage(pageIndex).makeViewable(false);
401
+ /**
402
+ * Removes all search pins
403
+ */
404
+ removeSearchResults(suppressFragmentChange = false) {
405
+ this.removeSearchHilites(); //be sure to set all box.divs to null
406
+ this.searchTerm = null;
407
+ this.searchResults = null;
408
+ if (!suppressFragmentChange) {
409
+ this.br.trigger(BookReader.eventNames.fragmentChange);
410
+ }
389
411
  }
390
- };
412
+ }
413
+ BookReader?.registerPlugin('search', SearchPlugin);
391
414
 
392
415
  /**
393
- * Removes all search pins
416
+ * @typedef {object} SearchOptions
417
+ * @property {boolean} goToFirstResult
418
+ * @property {boolean} disablePopup
419
+ * @property {boolean} suppressFragmentChange
420
+ * @property {(null|function)} error (deprecated)
421
+ * @property {(null|function)} success (deprecated)
394
422
  */
395
- BookReader.prototype.removeSearchResults = function(suppressFragmentChange = false) {
396
- this.removeSearchHilites(); //be sure to set all box.divs to null
397
- this.searchTerm = null;
398
- this.searchResults = null;
399
- if (!suppressFragmentChange) {
400
- this.trigger(BookReader.eventNames.fragmentChange);
401
- }
402
- };
403
423
 
404
424
  /**
405
- * Returns true if a search highlight is currently being displayed
406
- * @returns {boolean}
425
+ * @typedef {object} SearchInsideMatchBox
426
+ * @property {number} page
427
+ * @property {number} r
428
+ * @property {number} l
429
+ * @property {number} b
430
+ * @property {number} t
431
+ * @property {HTMLDivElement} [div]
432
+ * @property {number} matchIndex This is a fake field! not part of the API response. The index of the match that contains this box in total search results matches.
407
433
  */
408
- BookReader.prototype.searchHighlightVisible = function() {
409
- const results = this.searchResults;
410
- let visiblePages = [];
411
- if (null == results) return false;
412
-
413
- if (this.constMode2up == this.mode) {
414
- visiblePages = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
415
- } else if (this.constMode1up == this.mode) {
416
- visiblePages = [this.currentIndex()];
417
- } else {
418
- return false;
419
- }
420
434
 
421
- results.matches.some(match => {
422
- return match.par[0].boxes.some(box => {
423
- const pageIndex = this.leafNumToIndex(box.page);
424
- if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
425
- return true;
426
- }
427
- });
428
- });
435
+ /**
436
+ * @typedef {object} SearchInsideMatch
437
+ * @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.
438
+ * @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
439
+ * @property {string} html (computed field) The html-escaped raw html to display in the UI.
440
+ * @property {string} text
441
+ * @property {string} lang (fake field) The ISO 639-1 language code of the book
442
+ * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
443
+ */
429
444
 
430
- return false;
431
- };
445
+ /**
446
+ * @typedef {object} SearchInsideResults
447
+ * @property {string} q
448
+ * @property {string} error
449
+ * @property {SearchInsideMatch[]} matches
450
+ * @property {boolean} indexed
451
+ */