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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/.eslintrc.js +21 -19
  2. package/.github/workflows/node.js.yml +81 -7
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +505 -1442
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  57. package/BookReader/images/unviewable_page.png +0 -0
  58. package/BookReader/jquery-3.js +2 -0
  59. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  60. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  61. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js +1 -165
  63. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  64. package/BookReader/plugins/plugin.chapters.js +22 -301
  65. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  66. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  67. package/BookReader/plugins/plugin.iframe.js +1 -74
  68. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  69. package/BookReader/plugins/plugin.iiif.js +2 -0
  70. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  71. package/BookReader/plugins/plugin.resume.js +1 -368
  72. package/BookReader/plugins/plugin.resume.js.map +1 -1
  73. package/BookReader/plugins/plugin.search.js +2 -1420
  74. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.search.js.map +1 -1
  76. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  77. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  78. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  79. package/BookReader/plugins/plugin.tts.js +2 -9193
  80. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  81. package/BookReader/plugins/plugin.tts.js.map +1 -1
  82. package/BookReader/plugins/plugin.url.js +1 -269
  83. package/BookReader/plugins/plugin.url.js.map +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  85. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  86. package/BookReader/webcomponents-bundle.js +3 -0
  87. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  88. package/BookReader/webcomponents-bundle.js.map +1 -0
  89. package/BookReaderDemo/BookReaderDemo.css +18 -19
  90. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +144 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  95. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  96. package/BookReaderDemo/demo-fullscreen.html +2 -4
  97. package/BookReaderDemo/demo-iiif.html +99 -12
  98. package/BookReaderDemo/demo-internetarchive.html +214 -18
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +526 -525
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +595 -33
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +5 -2
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +70 -62
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +0 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +10 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/book-navigator.js +590 -0
  125. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  126. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  127. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  128. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  129. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  130. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  131. package/src/BookNavigator/delete-modal-actions.js +1 -1
  132. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  133. package/src/BookNavigator/downloads/downloads.js +29 -25
  134. package/src/BookNavigator/search/search-provider.js +80 -28
  135. package/src/BookNavigator/search/search-results.js +29 -26
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/viewable-files.js +95 -0
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
  140. package/src/BookReader/BookModel.js +76 -41
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/ImageCache.js +48 -15
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +777 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +19 -13
  150. package/src/BookReader/Navbar/Navbar.js +70 -54
  151. package/src/BookReader/PageContainer.js +116 -22
  152. package/src/BookReader/ReduceSet.js +3 -3
  153. package/src/BookReader/Toolbar/Toolbar.js +14 -41
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +73 -15
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils/classes.js +1 -1
  160. package/src/BookReader/utils.js +128 -13
  161. package/src/BookReader.js +562 -1078
  162. package/src/BookReaderPlugin.js +44 -0
  163. package/src/assets/icons/close-circle-dark.svg +1 -0
  164. package/src/assets/icons/magnify-minus.svg +3 -7
  165. package/src/assets/icons/magnify-plus.svg +3 -7
  166. package/src/assets/icons/voice.svg +1 -0
  167. package/src/assets/images/unviewable_page.png +0 -0
  168. package/src/css/BookReader.scss +1 -17
  169. package/src/css/_BRBookmarks.scss +1 -1
  170. package/src/css/_BRComponent.scss +1 -1
  171. package/src/css/_BRicon.scss +8 -2
  172. package/src/css/_BRmain.scss +33 -27
  173. package/src/css/_BRnav.scss +12 -42
  174. package/src/css/_BRpages.scss +170 -42
  175. package/src/css/_BRsearch.scss +68 -230
  176. package/src/css/_BRtoolbar.scss +5 -5
  177. package/src/css/_TextSelection.scss +87 -27
  178. package/src/css/_colorbox.scss +2 -2
  179. package/src/css/_controls.scss +24 -7
  180. package/src/css/_icons.scss +7 -1
  181. package/src/ia-bookreader/ia-bookreader.js +224 -0
  182. package/src/plugins/plugin.archive_analytics.js +84 -78
  183. package/src/plugins/plugin.autoplay.js +99 -104
  184. package/src/plugins/plugin.chapters.js +237 -191
  185. package/src/plugins/plugin.iframe.js +1 -1
  186. package/src/plugins/plugin.iiif.js +141 -0
  187. package/src/plugins/plugin.resume.js +53 -50
  188. package/src/plugins/plugin.text_selection.js +503 -175
  189. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  190. package/src/plugins/search/plugin.search.js +183 -121
  191. package/src/plugins/search/utils.js +43 -0
  192. package/src/plugins/search/view.js +67 -202
  193. package/src/plugins/tts/AbstractTTSEngine.js +75 -45
  194. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  195. package/src/plugins/tts/PageChunk.js +16 -23
  196. package/src/plugins/tts/PageChunkIterator.js +11 -17
  197. package/src/plugins/tts/WebTTSEngine.js +88 -72
  198. package/src/plugins/tts/plugin.tts.js +310 -350
  199. package/src/plugins/tts/utils.js +16 -26
  200. package/src/plugins/url/UrlPlugin.js +191 -0
  201. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  202. package/src/util/browserSniffing.js +22 -0
  203. package/src/util/docCookies.js +21 -2
  204. package/src/util/strings.js +1 -0
  205. package/tests/e2e/README.md +37 -0
  206. package/tests/e2e/autoplay.test.js +9 -6
  207. package/tests/e2e/base.test.js +8 -16
  208. package/tests/e2e/helpers/base.js +55 -50
  209. package/tests/e2e/helpers/debug.js +1 -1
  210. package/tests/e2e/helpers/mockSearch.js +19 -22
  211. package/tests/e2e/helpers/params.js +17 -0
  212. package/tests/e2e/helpers/rightToLeft.js +8 -14
  213. package/tests/e2e/helpers/search.js +73 -0
  214. package/tests/e2e/models/Navigation.js +20 -37
  215. package/tests/e2e/rightToLeft.test.js +4 -5
  216. package/tests/e2e/viewmode.test.js +40 -33
  217. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  218. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  219. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  220. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  221. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  222. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  223. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  224. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  225. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
  226. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  227. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  228. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  229. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  230. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  231. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  232. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  233. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  234. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  235. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  236. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  237. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  238. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +42 -29
  239. package/tests/jest/BookReader/PageContainer.test.js +238 -0
  240. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  241. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
  242. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  243. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  244. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  245. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  246. package/tests/jest/BookReader/utils.test.js +250 -0
  247. package/tests/jest/BookReader.keyboard.test.js +190 -0
  248. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
  249. package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
  250. package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
  251. package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
  252. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  253. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
  254. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
  255. package/tests/jest/plugins/plugin.text_selection.test.js +316 -0
  256. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  257. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
  258. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +42 -9
  259. package/tests/jest/plugins/search/utils.js +25 -0
  260. package/tests/jest/plugins/search/utils.test.js +29 -0
  261. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +30 -10
  262. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  263. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  264. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  265. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  266. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  267. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  268. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +57 -18
  269. package/tests/jest/setup.js +3 -0
  270. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  271. package/tests/jest/util/docCookies.test.js +24 -0
  272. package/tests/{util → jest/util}/strings.test.js +1 -1
  273. package/tests/{utils.js → jest/utils.js} +38 -0
  274. package/webpack.config.js +16 -10
  275. package/.babelrc +0 -12
  276. package/.dependabot/config.yml +0 -6
  277. package/.testcaferc.json +0 -5
  278. package/BookReader/bookreader-component-bundle.js +0 -14330
  279. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  280. package/BookReader/bookreader-component-bundle.js.map +0 -1
  281. package/BookReader/icons/sort-ascending.svg +0 -1
  282. package/BookReader/icons/sort-descending.svg +0 -1
  283. package/BookReader/jquery-1.10.1.js +0 -108
  284. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  285. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  286. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  287. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  288. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  289. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  290. package/BookReaderDemo/IIIFBookReader.js +0 -207
  291. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  292. package/BookReaderDemo/demo-autoplay.html +0 -38
  293. package/BookReaderDemo/demo-iiif.js +0 -26
  294. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  295. package/karma.conf.js +0 -23
  296. package/src/BookNavigator/BookModel.js +0 -14
  297. package/src/BookNavigator/BookNavigator.js +0 -452
  298. package/src/BookNavigator/assets/book-loader.js +0 -27
  299. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  300. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  301. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  302. package/src/BookNavigator/search/a-search-result.js +0 -55
  303. package/src/BookNavigator/volumes/volumes-provider.js +0 -108
  304. package/src/BookNavigator/volumes/volumes.js +0 -162
  305. package/src/BookReader/DebugConsole.js +0 -54
  306. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  307. package/src/ItemNavigator/ItemNavigator.js +0 -372
  308. package/src/ItemNavigator/providers/sharing.js +0 -29
  309. package/src/assets/icons/sort-ascending.svg +0 -1
  310. package/src/assets/icons/sort-descending.svg +0 -1
  311. package/src/css/_MobileNav.scss +0 -194
  312. package/src/dragscrollable-br.js +0 -261
  313. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  314. package/src/plugins/plugin.mobile_nav.js +0 -287
  315. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  316. package/tests/BookReader/DebugConsole.test.js +0 -25
  317. package/tests/BookReader/Mode1Up.test.js +0 -164
  318. package/tests/BookReader/Mode2Up.test.js +0 -247
  319. package/tests/BookReader/PageContainer.test.js +0 -115
  320. package/tests/BookReader/utils.test.js +0 -109
  321. package/tests/e2e/helpers/desktopSearch.js +0 -72
  322. package/tests/e2e/helpers/mobileSearch.js +0 -85
  323. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  324. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  325. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  326. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  327. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  328. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  329. package/tests/plugins/plugin.autoplay.test.js +0 -52
  330. package/tests/plugins/plugin.chapters.test.js +0 -130
  331. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  332. package/tests/plugins/plugin.text_selection.test.js +0 -203
  333. package/tests/util/docCookies.test.js +0 -15
@@ -8,7 +8,7 @@ if (!isMobile()) {
8
8
 
9
9
  jQuery.extend(BookReader.defaultOptions, {
10
10
  /** @type {boolean} */
11
- enableVendorFullscreenPlugin: true
11
+ enableVendorFullscreenPlugin: true,
12
12
  });
13
13
 
14
14
  /** @override */
@@ -56,7 +56,7 @@ if (!isMobile()) {
56
56
  $(document.body).append(cboxOverlay).append(cbox);
57
57
  }
58
58
  });
59
- }
59
+ };
60
60
  })(BookReader.prototype.init);
61
61
 
62
62
  /**
@@ -92,7 +92,7 @@ if (!isMobile()) {
92
92
  $(document).off('keyup' + EVENT_NAMESPACE);
93
93
 
94
94
  this.isFullscreenActive = false;
95
- this.updateBrClasses()
95
+ this.updateBrClasses();
96
96
 
97
97
  this.resize();
98
98
  this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
@@ -225,16 +225,16 @@ export function fullscreenAllowed() {
225
225
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event
226
226
  */
227
227
  export function bindFullscreenChangeListener(
228
- data, fullscreenchangeListener
228
+ data, fullscreenchangeListener,
229
229
  ) {
230
230
  const event = 'fullscreenchange ';
231
231
  const vendor_prefixes = [
232
232
  'webkit',
233
233
  'moz',
234
- 'ms'
234
+ 'ms',
235
235
  ];
236
- const all_events = $.trim(event + vendor_prefixes.join(event) + event);
237
- $(document).bind(all_events, data, fullscreenchangeListener);
236
+ const all_events = (event + vendor_prefixes.join(event) + event).trim();
237
+ $(document).on(all_events, data, fullscreenchangeListener);
238
238
  }
239
239
 
240
240
  /**
@@ -1,9 +1,7 @@
1
+ // @ts-check
1
2
  /* global BookReader */
2
3
  /**
3
4
  * 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
5
  * Events fired at various points throughout search processing are published
8
6
  * on the document DOM element. These can be subscribed to using jQuery's event
9
7
  * binding method `$.fn.on`. All of the events are prefixed with a BookReader
@@ -20,8 +18,17 @@
20
18
  * the book has not had OCR text indexed yet. Receives `instance`
21
19
  * @event BookReader:SearchCallbackEmpty - When no results found. Receives
22
20
  * `instance`
21
+ * @event BookReader:SearchCanceled - When no results found. Receives
22
+ * `instance`
23
23
  */
24
+ import { poll } from '../../BookReader/utils.js';
25
+ import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
24
26
  import SearchView from './view.js';
27
+ import { marshallSearchResults } from './utils.js';
28
+ /** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
29
+ /** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
30
+ /** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */
31
+ /** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */
25
32
 
26
33
  jQuery.extend(BookReader.defaultOptions, {
27
34
  server: 'ia600609.us.archive.org',
@@ -29,7 +36,10 @@ jQuery.extend(BookReader.defaultOptions, {
29
36
  subPrefix: '',
30
37
  bookPath: '',
31
38
  enableSearch: true,
39
+ searchInsideProtocol: 'https',
32
40
  searchInsideUrl: '/fulltext/inside.php',
41
+ searchInsidePreTag: '{{{',
42
+ searchInsidePostTag: '}}}',
33
43
  initialSearchTerm: null,
34
44
  });
35
45
 
@@ -42,7 +52,6 @@ BookReader.prototype.setup = (function (super_) {
42
52
  this.searchResults = null;
43
53
  this.searchInsideUrl = options.searchInsideUrl;
44
54
  this.enableSearch = options.enableSearch;
45
- this.goToFirstResult = false;
46
55
 
47
56
  // Base server used by some api calls
48
57
  this.bookId = options.bookId;
@@ -50,11 +59,24 @@ BookReader.prototype.setup = (function (super_) {
50
59
  this.subPrefix = options.subPrefix;
51
60
  this.bookPath = options.bookPath;
52
61
 
53
- if (this.searchView) { return; }
54
- this.searchView = new SearchView({
55
- br: this,
56
- selector: '#BRsearch_tray',
57
- });
62
+ this.searchXHR = null;
63
+ this._cancelSearch.bind(this);
64
+ this.cancelSearchRequest.bind(this);
65
+
66
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
67
+ this._searchBoxesByIndex = {};
68
+
69
+ if (this.enableSearch) {
70
+ this.searchView = new SearchView({
71
+ br: this,
72
+ searchCancelledCallback: () => {
73
+ this._cancelSearch();
74
+ this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
75
+ },
76
+ });
77
+ } else {
78
+ this.searchView = null;
79
+ }
58
80
  };
59
81
  })(BookReader.prototype.setup);
60
82
 
@@ -62,28 +84,26 @@ BookReader.prototype.setup = (function (super_) {
62
84
  BookReader.prototype.init = (function (super_) {
63
85
  return function () {
64
86
  super_.call(this);
65
-
66
- if (this.options.enableSearch && this.options.initialSearchTerm) {
87
+ if (!this.enableSearch) return;
88
+
89
+ this.searchView.init();
90
+ if (this.options.initialSearchTerm) {
91
+ /**
92
+ * this.search() take two parameter
93
+ * 1. this.options.initialSearchTerm - search term
94
+ * 2. {
95
+ * goToFirstResult: this.options.goToFirstResult,
96
+ * suppressFragmentChange: false // always want to change fragment in URL
97
+ * }
98
+ */
67
99
  this.search(
68
100
  this.options.initialSearchTerm,
69
- { goToFirstResult: this.goToFirstResult, suppressFragmentChange: true }
101
+ { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false },
70
102
  );
71
103
  }
72
104
  };
73
105
  })(BookReader.prototype.init);
74
106
 
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
107
  /** @override */
88
108
  BookReader.prototype.buildToolbarElement = (function (super_) {
89
109
  return function () {
@@ -96,6 +116,25 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
96
116
  };
97
117
  })(BookReader.prototype.buildToolbarElement);
98
118
 
119
+ /** @override */
120
+ BookReader.prototype._createPageContainer = (function (super_) {
121
+ return function (index) {
122
+ const pageContainer = super_.call(this, index);
123
+ if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {
124
+ const pageIndex = pageContainer.page.index;
125
+ const boxes = this._searchBoxesByIndex[pageIndex];
126
+ renderBoxesInPageContainerLayer(
127
+ 'searchHiliteLayer',
128
+ boxes,
129
+ pageContainer.page,
130
+ pageContainer.$container[0],
131
+ boxes.map(b => `match-index-${b.matchIndex}`),
132
+ );
133
+ }
134
+ return pageContainer;
135
+ };
136
+ })(BookReader.prototype._createPageContainer);
137
+
99
138
  /**
100
139
  * @typedef {object} SearchOptions
101
140
  * @property {boolean} goToFirstResult
@@ -110,7 +149,7 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
110
149
  * @param {string} term
111
150
  * @param {SearchOptions} overrides
112
151
  */
113
- BookReader.prototype.search = function(term = '', overrides = {}) {
152
+ BookReader.prototype.search = async function(term = '', overrides = {}) {
114
153
  /** @type {SearchOptions} */
115
154
  const defaultOptions = {
116
155
  goToFirstResult: false, /* jump to the first result (default=false) */
@@ -122,6 +161,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
122
161
  };
123
162
  const options = jQuery.extend({}, defaultOptions, overrides);
124
163
  this.suppressFragmentChange = options.suppressFragmentChange;
164
+ this.searchCancelled = false;
125
165
 
126
166
  // strip slashes, since this goes in the url
127
167
  this.searchTerm = term.replace(/\//g, ' ');
@@ -136,7 +176,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
136
176
 
137
177
  // Remove the port and userdir
138
178
  const serverPath = this.server.replace(/:.+/, '');
139
- const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;
179
+ const baseUrl = `${this.options.searchInsideProtocol}://${serverPath}${this.searchInsideUrl}?`;
140
180
 
141
181
  // Remove subPrefix from end of path
142
182
  let path = this.bookPath;
@@ -150,6 +190,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
150
190
  doc: this.subPrefix,
151
191
  path,
152
192
  q: term,
193
+ pre_tag: this.options.searchInsidePreTag,
194
+ post_tag: this.options.searchInsidePostTag,
153
195
  };
154
196
 
155
197
  // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
@@ -157,12 +199,16 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
157
199
 
158
200
  const url = `${baseUrl}${paramStr}`;
159
201
 
160
- const processSearchResults = (searchInsideResults) => {
202
+ const callSearchResultsCallback = (searchInsideResults) => {
203
+ if (this.searchCancelled) {
204
+ return;
205
+ }
161
206
  const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
162
207
  const hasCustomError = typeof options.error === 'function';
163
208
  const hasCustomSuccess = typeof options.success === 'function';
164
209
 
165
210
  if (responseHasError) {
211
+ console.error('Search Inside Response Error', searchInsideResults.error || 'matches.length == 0');
166
212
  hasCustomError
167
213
  ? options.error.call(this, searchInsideResults, options)
168
214
  : this.BRSearchCallbackError(searchInsideResults, options);
@@ -173,11 +219,41 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
173
219
  }
174
220
  };
175
221
 
176
- this.trigger('SearchStarted', { term: this.searchTerm });
177
- return $.ajax({
222
+ this.trigger('SearchStarted', { term: this.searchTerm, instance: this });
223
+ callSearchResultsCallback(await $.ajax({
178
224
  url: url,
179
- dataType: 'jsonp'
180
- }).then(processSearchResults);
225
+ cache: true,
226
+ xhrFields: {
227
+ withCredentials: this.protected,
228
+ },
229
+ beforeSend: xhr => { this.searchXHR = xhr; },
230
+ }));
231
+ };
232
+
233
+ /**
234
+ * cancels AJAX Call
235
+ * emits custom event
236
+ */
237
+ BookReader.prototype._cancelSearch = function () {
238
+ this.searchXHR?.abort();
239
+ this.searchView.clearSearchFieldAndResults(false);
240
+ this.searchTerm = '';
241
+ this.searchXHR = null;
242
+ this.searchCancelled = true;
243
+ this.searchResults = [];
244
+ };
245
+
246
+ /**
247
+ * External function to cancel search
248
+ * checks for term & xhr in flight before running
249
+ */
250
+ BookReader.prototype.cancelSearchRequest = function () {
251
+ this.searchCancelled = true;
252
+ if (this.searchXHR !== null) {
253
+ this._cancelSearch();
254
+ this.searchView.toggleSearchPending();
255
+ this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
256
+ }
181
257
  };
182
258
 
183
259
  /**
@@ -188,10 +264,14 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
188
264
  * @property {number} b
189
265
  * @property {number} t
190
266
  * @property {HTMLDivElement} [div]
267
+ * @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.
191
268
  */
192
269
 
193
270
  /**
194
271
  * @typedef {object} SearchInsideMatch
272
+ * @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.
273
+ * @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
274
+ * @property {string} html (computed field) The html-escaped raw html to display in the UI.
195
275
  * @property {string} text
196
276
  * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
197
277
  */
@@ -205,21 +285,26 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
205
285
 
206
286
  /**
207
287
  * Search Results return handler
208
- * @callback
209
288
  * @param {SearchInsideResults} results
210
289
  * @param {object} options
211
290
  * @param {boolean} options.goToFirstResult
212
291
  */
213
292
  BookReader.prototype.BRSearchCallback = function(results, options) {
214
- this.searchResults = results;
293
+ marshallSearchResults(
294
+ results,
295
+ pageNum => this.book.getPageNum(this.book.leafNumToIndex(pageNum)),
296
+ this.options.searchInsidePreTag,
297
+ this.options.searchInsidePostTag,
298
+ );
299
+ this.searchResults = results || [];
215
300
 
216
301
  this.updateSearchHilites();
217
302
  this.removeProgressPopup();
218
303
  if (options.goToFirstResult) {
219
- this._searchPluginGoToResult(results.matches[0].par[0].page);
304
+ this._searchPluginGoToResult(0);
220
305
  }
221
306
  this.trigger('SearchCallback', { results, options, instance: this });
222
- }
307
+ };
223
308
 
224
309
  /**
225
310
  * Main search results error handler
@@ -259,95 +344,41 @@ BookReader.prototype._BRSearchCallbackError = function(results) {
259
344
  * updates search on-page highlights controller
260
345
  */
261
346
  BookReader.prototype.updateSearchHilites = function() {
262
- if (this.constMode2up == this.mode) {
263
- this.updateSearchHilites2UP();
264
- return;
347
+ /** @type {SearchInsideMatch[]} */
348
+ const matches = this.searchResults?.matches || [];
349
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
350
+ const boxesByIndex = {};
351
+
352
+ // Clear any existing svg layers
353
+ this.removeSearchHilites();
354
+
355
+ // Group by pageIndex
356
+ for (const match of matches) {
357
+ for (const box of match.par[0].boxes) {
358
+ const pageIndex = this.book.leafNumToIndex(box.page);
359
+ const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
360
+ pageBoxes.push(box);
361
+ }
265
362
  }
266
- this.updateSearchHilites1UP();
267
- };
268
-
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
- }
298
- }
299
- });
300
- });
301
- };
302
363
 
303
- /**
304
- * update search on-page highlights in 2up mode
305
- */
306
- BookReader.prototype.updateSearchHilites2UP = function() {
307
- const results = this.searchResults;
364
+ // update any already created pages
365
+ for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
366
+ const pageIndex = parseFloat(pageIndexString);
367
+ const page = this.book.getPage(pageIndex);
368
+ const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
369
+ for (const container of pageContainers) {
370
+ renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));
371
+ }
372
+ }
308
373
 
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
- }
332
- }
333
- });
334
- });
374
+ this._searchBoxesByIndex = boxesByIndex;
335
375
  };
336
376
 
337
377
  /**
338
378
  * remove search highlights
339
379
  */
340
380
  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;
348
- }
349
- });
350
- });
381
+ $(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
351
382
  };
352
383
 
353
384
  /**
@@ -355,11 +386,14 @@ BookReader.prototype.removeSearchHilites = function() {
355
386
  * Goes to the page specified. If the page is not viewable, tries to load the page
356
387
  * FIXME Most of this logic is IA specific, and should be less integrated into here
357
388
  * or at least more configurable.
358
- * @param {PageIndex} pageIndex
389
+ * @param {number} matchIndex
359
390
  */
360
- BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
361
- const { book } = this._models;
391
+ BookReader.prototype._searchPluginGoToResult = async function (matchIndex) {
392
+ const match = this.searchResults?.matches[matchIndex];
393
+ const book = this.book;
394
+ const pageIndex = book.leafNumToIndex(match.par[0].page);
362
395
  const page = book.getPage(pageIndex);
396
+ const onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;
363
397
  let makeUnviewableAtEnd = false;
364
398
  if (!page.isViewable) {
365
399
  const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
@@ -378,15 +412,43 @@ BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
378
412
  book.getPage(pageIndex).makeViewable();
379
413
  makeUnviewableAtEnd = true;
380
414
  }
415
+
416
+ // Trigger an update of book
417
+ this._modes.mode1Up.mode1UpLit.updatePages();
418
+ if (this.activeMode == this._modes.mode1Up) {
419
+ await this._modes.mode1Up.mode1UpLit.updateComplete;
420
+ }
381
421
  }
382
422
  /* this updates the URL */
383
- this.suppressFragmentChange = false;
384
- this.jumpToIndex(pageIndex);
423
+ if (!this._isIndexDisplayed(pageIndex)) {
424
+ this.suppressFragmentChange = false;
425
+ this.jumpToIndex(pageIndex);
426
+ }
385
427
 
386
428
  // Reset it to unviewable if it wasn't resolved
387
429
  if (makeUnviewableAtEnd) {
388
430
  book.getPage(pageIndex).makeViewable(false);
389
431
  }
432
+
433
+ // Scroll/flash in the ui
434
+ const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });
435
+ if ($boxes.length) {
436
+ $boxes.css('animation', 'none');
437
+ $boxes[0].scrollIntoView({
438
+ // Only vertically center the highlight if we're in 1up or in full screen. In
439
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
440
+ // center the highlight 🙄 See:
441
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
442
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
443
+ // full-width, and covers up the last line of the highlight.
444
+ block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
445
+ inline: 'center',
446
+ behavior: onNearbyPage ? 'smooth' : 'auto',
447
+ });
448
+ // wait for animation to start
449
+ await new Promise(resolve => setTimeout(resolve, 100));
450
+ $boxes.removeAttr("style");
451
+ }
390
452
  };
391
453
 
392
454
  /**
@@ -420,7 +482,7 @@ BookReader.prototype.searchHighlightVisible = function() {
420
482
 
421
483
  results.matches.some(match => {
422
484
  return match.par[0].boxes.some(box => {
423
- const pageIndex = this.leafNumToIndex(box.page);
485
+ const pageIndex = this.book.leafNumToIndex(box.page);
424
486
  if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
425
487
  return true;
426
488
  }
@@ -0,0 +1,43 @@
1
+ import { escapeHTML, escapeRegExp } from '../../BookReader/utils.js';
2
+
3
+ /**
4
+ * @param {string} match
5
+ * @param {string} preTag
6
+ * @param {string} postTag
7
+ * @returns {string}
8
+ */
9
+ export function renderMatch(match, preTag, postTag) {
10
+ // Search results are returned as a text blob with the hits wrapped in
11
+ // triple mustaches. Hits occasionally include text beyond the search
12
+ // term, so everything within the staches is captured and wrapped.
13
+ const preTagRe = escapeRegExp(escapeHTML(preTag));
14
+ const postTagRe = escapeRegExp(escapeHTML(postTag));
15
+ // [^] matches any character, including line breaks
16
+ const regex = new RegExp(`${preTagRe}([^]+?)${postTagRe}`, 'g');
17
+ return escapeHTML(match)
18
+ .replace(regex, '<mark>$1</mark>')
19
+ // Fix trailing hyphens. This over-corrects but is net useful.
20
+ .replace(/(\b)- /g, '$1');
21
+ }
22
+
23
+ /**
24
+ * Attach some fields to search inside results
25
+ * @param {SearchInsideResults} results
26
+ * @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn
27
+ * @param {string} preTag
28
+ * @param {string} postTag
29
+ */
30
+ export function marshallSearchResults(results, displayPageNumberFn, preTag, postTag) {
31
+ // Attach matchIndex to a few things to make it easier to identify
32
+ // an active/selected match
33
+ for (const [index, match] of results.matches.entries()) {
34
+ match.matchIndex = index;
35
+ match.displayPageNumber = displayPageNumberFn(match.par[0].page);
36
+ match.html = renderMatch(match.text, preTag, postTag);
37
+ for (const par of match.par) {
38
+ for (const box of par.boxes) {
39
+ box.matchIndex = index;
40
+ }
41
+ }
42
+ }
43
+ }