@internetarchive/bookreader 5.0.0-12-fixsorting-8 → 5.0.0-121

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