@internetarchive/bookreader 5.0.0-7 → 5.0.0-70-a1

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 (307) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +73 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +396 -1129
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1788 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -1
  13. package/BookReader/icons/2up.svg +1 -1
  14. package/BookReader/icons/advance.svg +1 -1
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -1
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -1
  19. package/BookReader/icons/fullscreen_exit.svg +1 -1
  20. package/BookReader/icons/hamburger.svg +1 -1
  21. package/BookReader/icons/left-arrow.svg +1 -1
  22. package/BookReader/icons/magnify-minus.svg +1 -1
  23. package/BookReader/icons/magnify-plus.svg +1 -1
  24. package/BookReader/icons/magnify.svg +1 -1
  25. package/BookReader/icons/pause.svg +1 -1
  26. package/BookReader/icons/play.svg +1 -1
  27. package/BookReader/icons/playback-speed.svg +1 -1
  28. package/BookReader/icons/read-aloud.svg +1 -1
  29. package/BookReader/icons/review.svg +1 -1
  30. package/BookReader/icons/thumbnails.svg +1 -1
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -1
  33. package/BookReader/images/BRicons.svg +3 -3
  34. package/BookReader/images/books_graphic.svg +1 -1
  35. package/BookReader/images/icon_book.svg +1 -1
  36. package/BookReader/images/icon_bookmark.svg +1 -1
  37. package/BookReader/images/icon_gear.svg +1 -1
  38. package/BookReader/images/icon_hamburger.svg +1 -1
  39. package/BookReader/images/icon_home.svg +1 -1
  40. package/BookReader/images/icon_info.svg +1 -1
  41. package/BookReader/images/icon_one_page.svg +1 -1
  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 -1
  45. package/BookReader/images/icon_search_button.svg +1 -1
  46. package/BookReader/images/icon_share.svg +1 -1
  47. package/BookReader/images/icon_skip-ahead.svg +1 -1
  48. package/BookReader/images/icon_skip-back.svg +1 -1
  49. package/BookReader/images/icon_speaker.svg +1 -1
  50. package/BookReader/images/icon_speaker_open.svg +1 -1
  51. package/BookReader/images/icon_thumbnails.svg +1 -1
  52. package/BookReader/images/icon_toc.svg +1 -1
  53. package/BookReader/images/icon_two_pages.svg +1 -1
  54. package/BookReader/images/marker_chap-off.svg +1 -1
  55. package/BookReader/images/marker_chap-on.svg +1 -1
  56. package/BookReader/images/marker_srch-on.svg +1 -1
  57. package/BookReader/jquery-3.js +2 -0
  58. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  59. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +25 -1
  64. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  65. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  66. package/BookReader/plugins/plugin.iframe.js +1 -1
  67. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  68. package/BookReader/plugins/plugin.resume.js +1 -1
  69. package/BookReader/plugins/plugin.resume.js.map +1 -1
  70. package/BookReader/plugins/plugin.search.js +2 -1
  71. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  72. package/BookReader/plugins/plugin.search.js.map +1 -1
  73. package/BookReader/plugins/plugin.text_selection.js +2 -1
  74. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  76. package/BookReader/plugins/plugin.tts.js +1 -1
  77. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  78. package/BookReader/plugins/plugin.tts.js.map +1 -1
  79. package/BookReader/plugins/plugin.url.js +1 -1
  80. package/BookReader/plugins/plugin.url.js.map +1 -1
  81. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  82. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  83. package/BookReader/webcomponents-bundle.js +3 -0
  84. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  85. package/BookReader/webcomponents-bundle.js.map +1 -0
  86. package/BookReaderDemo/BookReaderDemo.css +16 -19
  87. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  88. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  89. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  90. package/BookReaderDemo/IADemoBr.js +147 -0
  91. package/BookReaderDemo/demo-advanced.html +2 -2
  92. package/BookReaderDemo/demo-autoplay.html +2 -3
  93. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  94. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  95. package/BookReaderDemo/demo-fullscreen.html +2 -4
  96. package/BookReaderDemo/demo-iiif.html +2 -1
  97. package/BookReaderDemo/demo-iiif.js +0 -1
  98. package/BookReaderDemo/demo-internetarchive.html +213 -17
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +2 -1
  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 +279 -0
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +4 -1
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +69 -60
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +4 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +4 -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 +586 -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 +3 -8
  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 +41 -25
  134. package/src/BookNavigator/search/search-provider.js +49 -27
  135. package/src/BookNavigator/search/search-results.js +23 -9
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  139. package/src/BookNavigator/volumes/volumes-provider.js +95 -0
  140. package/src/BookReader/BookModel.js +64 -34
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/Mode1Up.js +56 -351
  143. package/src/BookReader/Mode1UpLit.js +388 -0
  144. package/src/BookReader/Mode2Up.js +73 -1318
  145. package/src/BookReader/Mode2UpLit.js +776 -0
  146. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  147. package/src/BookReader/ModeSmoothZoom.js +312 -0
  148. package/src/BookReader/ModeThumb.js +18 -12
  149. package/src/BookReader/Navbar/Navbar.js +12 -38
  150. package/src/BookReader/PageContainer.js +81 -6
  151. package/src/BookReader/ReduceSet.js +1 -1
  152. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  153. package/src/BookReader/events.js +2 -3
  154. package/src/BookReader/options.js +24 -2
  155. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  156. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  157. package/src/BookReader/utils/SelectionObserver.js +43 -0
  158. package/src/BookReader/utils.js +118 -13
  159. package/src/BookReader.js +423 -1056
  160. package/src/assets/icons/magnify-minus.svg +3 -7
  161. package/src/assets/icons/magnify-plus.svg +3 -7
  162. package/src/assets/icons/voice.svg +1 -0
  163. package/src/css/BookReader.scss +1 -5
  164. package/src/css/_BRBookmarks.scss +1 -1
  165. package/src/css/_BRComponent.scss +1 -1
  166. package/src/css/_BRmain.scss +16 -0
  167. package/src/css/_BRnav.scss +11 -38
  168. package/src/css/_BRpages.scss +149 -40
  169. package/src/css/_BRsearch.scss +67 -21
  170. package/src/css/_TextSelection.scss +87 -27
  171. package/src/css/_colorbox.scss +2 -2
  172. package/src/css/_controls.scss +20 -7
  173. package/src/css/_icons.scss +1 -1
  174. package/src/ia-bookreader/ia-bookreader.js +224 -0
  175. package/src/plugins/plugin.archive_analytics.js +3 -3
  176. package/src/plugins/plugin.autoplay.js +5 -11
  177. package/src/plugins/plugin.chapters.js +211 -186
  178. package/src/plugins/plugin.resume.js +3 -3
  179. package/src/plugins/plugin.text_selection.js +464 -134
  180. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  181. package/src/plugins/search/plugin.search.js +142 -125
  182. package/src/plugins/search/utils.js +43 -0
  183. package/src/plugins/search/view.js +33 -58
  184. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  185. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  186. package/src/plugins/tts/PageChunk.js +15 -21
  187. package/src/plugins/tts/PageChunkIterator.js +8 -12
  188. package/src/plugins/tts/WebTTSEngine.js +87 -71
  189. package/src/plugins/tts/plugin.tts.js +95 -126
  190. package/src/plugins/tts/utils.js +0 -25
  191. package/src/plugins/url/UrlPlugin.js +193 -0
  192. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  193. package/src/util/browserSniffing.js +22 -0
  194. package/src/util/docCookies.js +21 -2
  195. package/tests/e2e/README.md +37 -0
  196. package/tests/e2e/autoplay.test.js +2 -2
  197. package/tests/e2e/base.test.js +8 -16
  198. package/tests/e2e/helpers/base.js +53 -48
  199. package/tests/e2e/helpers/debug.js +1 -1
  200. package/tests/e2e/helpers/params.js +17 -0
  201. package/tests/e2e/helpers/rightToLeft.js +8 -14
  202. package/tests/e2e/helpers/search.js +73 -0
  203. package/tests/e2e/models/Navigation.js +20 -37
  204. package/tests/e2e/rightToLeft.test.js +4 -5
  205. package/tests/e2e/viewmode.test.js +40 -33
  206. package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
  207. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  208. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  209. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  210. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  211. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  212. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  213. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  214. package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
  215. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  216. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  217. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +80 -0
  218. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  219. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  220. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  221. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  222. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  223. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  224. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  225. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  226. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  227. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  228. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  229. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  230. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  231. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  232. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  233. package/tests/jest/BookReader/utils/SelectionObserver.test.js +43 -0
  234. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  235. package/tests/jest/BookReader/utils.test.js +229 -0
  236. package/tests/jest/BookReader.keyboard.test.js +190 -0
  237. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  238. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  239. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  240. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  241. package/tests/jest/plugins/plugin.chapters.test.js +145 -0
  242. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  243. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  244. package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
  245. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  246. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
  247. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
  248. package/tests/jest/plugins/search/utils.js +25 -0
  249. package/tests/jest/plugins/search/utils.test.js +29 -0
  250. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  251. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  252. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  253. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  254. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  255. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  256. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  257. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  258. package/tests/jest/setup.js +3 -0
  259. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  260. package/tests/jest/util/docCookies.test.js +24 -0
  261. package/tests/{util → jest/util}/strings.test.js +1 -1
  262. package/tests/{utils.js → jest/utils.js} +38 -0
  263. package/webpack.config.js +11 -6
  264. package/.babelrc +0 -12
  265. package/.dependabot/config.yml +0 -6
  266. package/.testcaferc.json +0 -5
  267. package/BookReader/bookreader-component-bundle.js +0 -1450
  268. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  269. package/BookReader/bookreader-component-bundle.js.map +0 -1
  270. package/BookReader/jquery-1.10.1.js +0 -2
  271. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  272. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  273. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  274. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  275. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  276. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  277. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  278. package/karma.conf.js +0 -23
  279. package/src/BookNavigator/BookModel.js +0 -14
  280. package/src/BookNavigator/BookNavigator.js +0 -446
  281. package/src/BookNavigator/assets/book-loader.js +0 -27
  282. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  283. package/src/BookNavigator/search/a-search-result.js +0 -55
  284. package/src/BookReader/DebugConsole.js +0 -54
  285. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  286. package/src/ItemNavigator/ItemNavigator.js +0 -376
  287. package/src/ItemNavigator/providers/sharing.js +0 -29
  288. package/src/css/_MobileNav.scss +0 -194
  289. package/src/dragscrollable-br.js +0 -261
  290. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  291. package/src/plugins/plugin.mobile_nav.js +0 -287
  292. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  293. package/tests/BookReader/DebugConsole.test.js +0 -25
  294. package/tests/BookReader/Mode1Up.test.js +0 -164
  295. package/tests/BookReader/Mode2Up.test.js +0 -247
  296. package/tests/BookReader/utils.test.js +0 -109
  297. package/tests/e2e/helpers/desktopSearch.js +0 -72
  298. package/tests/e2e/helpers/mobileSearch.js +0 -85
  299. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  300. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  301. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  302. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  303. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  304. package/tests/plugins/plugin.chapters.test.js +0 -130
  305. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  306. package/tests/plugins/plugin.text_selection.test.js +0 -203
  307. package/tests/util/docCookies.test.js +0 -15
@@ -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');
@@ -233,8 +233,8 @@ export function bindFullscreenChangeListener(
233
233
  'moz',
234
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
@@ -23,7 +21,14 @@
23
21
  * @event BookReader:SearchCanceled - When no results found. Receives
24
22
  * `instance`
25
23
  */
24
+ import { poll } from '../../BookReader/utils.js';
25
+ import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
26
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 */
27
32
 
28
33
  jQuery.extend(BookReader.defaultOptions, {
29
34
  server: 'ia600609.us.archive.org',
@@ -31,7 +36,10 @@ jQuery.extend(BookReader.defaultOptions, {
31
36
  subPrefix: '',
32
37
  bookPath: '',
33
38
  enableSearch: true,
39
+ searchInsideProtocol: 'https',
34
40
  searchInsideUrl: '/fulltext/inside.php',
41
+ searchInsidePreTag: '{{{',
42
+ searchInsidePostTag: '}}}',
35
43
  initialSearchTerm: null,
36
44
  });
37
45
 
@@ -44,7 +52,6 @@ BookReader.prototype.setup = (function (super_) {
44
52
  this.searchResults = null;
45
53
  this.searchInsideUrl = options.searchInsideUrl;
46
54
  this.enableSearch = options.enableSearch;
47
- this.goToFirstResult = false;
48
55
 
49
56
  // Base server used by some api calls
50
57
  this.bookId = options.bookId;
@@ -56,14 +63,10 @@ BookReader.prototype.setup = (function (super_) {
56
63
  this._cancelSearch.bind(this);
57
64
  this.cancelSearchRequest.bind(this);
58
65
 
59
- if (this.searchView) { return; }
60
- this.searchView = new SearchView({
61
- br: this,
62
- cancelSearch: () => {
63
- this._cancelSearch();
64
- this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
65
- }
66
- });
66
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
67
+ this._searchBoxesByIndex = {};
68
+
69
+ this.searchView = undefined;
67
70
  };
68
71
  })(BookReader.prototype.setup);
69
72
 
@@ -71,11 +74,26 @@ BookReader.prototype.setup = (function (super_) {
71
74
  BookReader.prototype.init = (function (super_) {
72
75
  return function () {
73
76
  super_.call(this);
74
-
77
+ // give SearchView the most complete bookreader state
78
+ this.searchView = new SearchView({
79
+ br: this,
80
+ searchCancelledCallback: () => {
81
+ this._cancelSearch();
82
+ this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
83
+ }
84
+ });
75
85
  if (this.options.enableSearch && this.options.initialSearchTerm) {
86
+ /**
87
+ * this.search() take two parameter
88
+ * 1. this.options.initialSearchTerm - search term
89
+ * 2. {
90
+ * goToFirstResult: this.options.goToFirstResult,
91
+ * suppressFragmentChange: false // always want to change fragment in URL
92
+ * }
93
+ */
76
94
  this.search(
77
95
  this.options.initialSearchTerm,
78
- { goToFirstResult: this.goToFirstResult, suppressFragmentChange: true }
96
+ { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false }
79
97
  );
80
98
  }
81
99
  };
@@ -93,6 +111,25 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
93
111
  };
94
112
  })(BookReader.prototype.buildToolbarElement);
95
113
 
114
+ /** @override */
115
+ BookReader.prototype._createPageContainer = (function (super_) {
116
+ return function (index) {
117
+ const pageContainer = super_.call(this, index);
118
+ if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {
119
+ const pageIndex = pageContainer.page.index;
120
+ const boxes = this._searchBoxesByIndex[pageIndex];
121
+ renderBoxesInPageContainerLayer(
122
+ 'searchHiliteLayer',
123
+ boxes,
124
+ pageContainer.page,
125
+ pageContainer.$container[0],
126
+ boxes.map(b => `match-index-${b.matchIndex}`),
127
+ );
128
+ }
129
+ return pageContainer;
130
+ };
131
+ })(BookReader.prototype._createPageContainer);
132
+
96
133
  /**
97
134
  * @typedef {object} SearchOptions
98
135
  * @property {boolean} goToFirstResult
@@ -107,7 +144,7 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
107
144
  * @param {string} term
108
145
  * @param {SearchOptions} overrides
109
146
  */
110
- BookReader.prototype.search = function(term = '', overrides = {}) {
147
+ BookReader.prototype.search = async function(term = '', overrides = {}) {
111
148
  /** @type {SearchOptions} */
112
149
  const defaultOptions = {
113
150
  goToFirstResult: false, /* jump to the first result (default=false) */
@@ -119,6 +156,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
119
156
  };
120
157
  const options = jQuery.extend({}, defaultOptions, overrides);
121
158
  this.suppressFragmentChange = options.suppressFragmentChange;
159
+ this.searchCancelled = false;
122
160
 
123
161
  // strip slashes, since this goes in the url
124
162
  this.searchTerm = term.replace(/\//g, ' ');
@@ -133,7 +171,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
133
171
 
134
172
  // Remove the port and userdir
135
173
  const serverPath = this.server.replace(/:.+/, '');
136
- const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;
174
+ const baseUrl = `${this.options.searchInsideProtocol}://${serverPath}${this.searchInsideUrl}?`;
137
175
 
138
176
  // Remove subPrefix from end of path
139
177
  let path = this.bookPath;
@@ -147,6 +185,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
147
185
  doc: this.subPrefix,
148
186
  path,
149
187
  q: term,
188
+ pre_tag: this.options.searchInsidePreTag,
189
+ post_tag: this.options.searchInsidePostTag,
150
190
  };
151
191
 
152
192
  // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
@@ -154,13 +194,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
154
194
 
155
195
  const url = `${baseUrl}${paramStr}`;
156
196
 
157
- const cleanup = () => {
158
- this.searchXHR = null
159
- window.BRSearchInProgress = () => {};
160
- };
161
-
162
- const processSearchResults = (searchInsideResults) => {
163
- if (!this.searchXHR) {
197
+ const callSearchResultsCallback = (searchInsideResults) => {
198
+ if (this.searchCancelled) {
164
199
  return;
165
200
  }
166
201
  const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
@@ -168,6 +203,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
168
203
  const hasCustomSuccess = typeof options.success === 'function';
169
204
 
170
205
  if (responseHasError) {
206
+ console.error('Search Inside Response Error', searchInsideResults.error || 'matches.length == 0');
171
207
  hasCustomError
172
208
  ? options.error.call(this, searchInsideResults, options)
173
209
  : this.BRSearchCallbackError(searchInsideResults, options);
@@ -176,21 +212,15 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
176
212
  ? options.success.call(this, searchInsideResults, options)
177
213
  : this.BRSearchCallback(searchInsideResults, options);
178
214
  }
179
- cleanup();
180
- };
181
-
182
- const beforeSend = (xhr) => {
183
- this.searchXHR = xhr;
184
- window.BRSearchInProgress = processSearchResults;
185
215
  };
186
216
 
187
217
  this.trigger('SearchStarted', { term: this.searchTerm, instance: this });
188
- return $.ajax({
218
+ callSearchResultsCallback(await $.ajax({
189
219
  url: url,
190
220
  dataType: 'jsonp',
191
- beforeSend,
192
- jsonpCallback: 'BRSearchInProgress'
193
- }).then(processSearchResults)
221
+ cache: true,
222
+ beforeSend: xhr => { this.searchXHR = xhr; },
223
+ }));
194
224
  };
195
225
 
196
226
  /**
@@ -202,21 +232,22 @@ BookReader.prototype._cancelSearch = function () {
202
232
  this.searchView.clearSearchFieldAndResults(false);
203
233
  this.searchTerm = '';
204
234
  this.searchXHR = null;
235
+ this.searchCancelled = true;
205
236
  this.searchResults = [];
206
- window.BRSearchInProgress = () => {};
207
- }
237
+ };
208
238
 
209
239
  /**
210
240
  * External function to cancel search
211
241
  * checks for term & xhr in flight before running
212
242
  */
213
243
  BookReader.prototype.cancelSearchRequest = function () {
244
+ this.searchCancelled = true;
214
245
  if (this.searchXHR !== null) {
215
246
  this._cancelSearch();
216
247
  this.searchView.toggleSearchPending();
217
248
  this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
218
249
  }
219
- }
250
+ };
220
251
 
221
252
  /**
222
253
  * @typedef {object} SearchInsideMatchBox
@@ -226,10 +257,14 @@ BookReader.prototype.cancelSearchRequest = function () {
226
257
  * @property {number} b
227
258
  * @property {number} t
228
259
  * @property {HTMLDivElement} [div]
260
+ * @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.
229
261
  */
230
262
 
231
263
  /**
232
264
  * @typedef {object} SearchInsideMatch
265
+ * @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.
266
+ * @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
267
+ * @property {string} html (computed field) The html-escaped raw html to display in the UI.
233
268
  * @property {string} text
234
269
  * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
235
270
  */
@@ -243,21 +278,26 @@ BookReader.prototype.cancelSearchRequest = function () {
243
278
 
244
279
  /**
245
280
  * Search Results return handler
246
- * @callback
247
281
  * @param {SearchInsideResults} results
248
282
  * @param {object} options
249
283
  * @param {boolean} options.goToFirstResult
250
284
  */
251
285
  BookReader.prototype.BRSearchCallback = function(results, options) {
286
+ marshallSearchResults(
287
+ results,
288
+ pageNum => this.book.getPageNum(this.book.leafNumToIndex(pageNum)),
289
+ this.options.searchInsidePreTag,
290
+ this.options.searchInsidePostTag,
291
+ );
252
292
  this.searchResults = results || [];
253
293
 
254
294
  this.updateSearchHilites();
255
295
  this.removeProgressPopup();
256
296
  if (options.goToFirstResult) {
257
- this._searchPluginGoToResult(results.matches[0].par[0].page);
297
+ this._searchPluginGoToResult(0);
258
298
  }
259
299
  this.trigger('SearchCallback', { results, options, instance: this });
260
- }
300
+ };
261
301
 
262
302
  /**
263
303
  * Main search results error handler
@@ -297,95 +337,41 @@ BookReader.prototype._BRSearchCallbackError = function(results) {
297
337
  * updates search on-page highlights controller
298
338
  */
299
339
  BookReader.prototype.updateSearchHilites = function() {
300
- if (this.constMode2up == this.mode) {
301
- this.updateSearchHilites2UP();
302
- return;
340
+ /** @type {SearchInsideMatch[]} */
341
+ const matches = this.searchResults?.matches || [];
342
+ /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
343
+ const boxesByIndex = {};
344
+
345
+ // Clear any existing svg layers
346
+ this.removeSearchHilites();
347
+
348
+ // Group by pageIndex
349
+ for (const match of matches) {
350
+ for (const box of match.par[0].boxes) {
351
+ const pageIndex = this.book.leafNumToIndex(box.page);
352
+ const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
353
+ pageBoxes.push(box);
354
+ }
303
355
  }
304
- this.updateSearchHilites1UP();
305
- };
306
-
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
- }
336
- }
337
- });
338
- });
339
- };
340
356
 
341
- /**
342
- * update search on-page highlights in 2up mode
343
- */
344
- BookReader.prototype.updateSearchHilites2UP = function() {
345
- const results = this.searchResults;
357
+ // update any already created pages
358
+ for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
359
+ const pageIndex = parseFloat(pageIndexString);
360
+ const page = this.book.getPage(pageIndex);
361
+ const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
362
+ for (const container of pageContainers) {
363
+ renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));
364
+ }
365
+ }
346
366
 
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
- }
370
- }
371
- });
372
- });
367
+ this._searchBoxesByIndex = boxesByIndex;
373
368
  };
374
369
 
375
370
  /**
376
371
  * remove search highlights
377
372
  */
378
373
  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;
386
- }
387
- });
388
- });
374
+ $(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
389
375
  };
390
376
 
391
377
  /**
@@ -393,11 +379,14 @@ BookReader.prototype.removeSearchHilites = function() {
393
379
  * Goes to the page specified. If the page is not viewable, tries to load the page
394
380
  * FIXME Most of this logic is IA specific, and should be less integrated into here
395
381
  * or at least more configurable.
396
- * @param {PageIndex} pageIndex
382
+ * @param {number} matchIndex
397
383
  */
398
- BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
399
- const { book } = this._models;
384
+ BookReader.prototype._searchPluginGoToResult = async function (matchIndex) {
385
+ const match = this.searchResults?.matches[matchIndex];
386
+ const book = this.book;
387
+ const pageIndex = book.leafNumToIndex(match.par[0].page);
400
388
  const page = book.getPage(pageIndex);
389
+ const onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;
401
390
  let makeUnviewableAtEnd = false;
402
391
  if (!page.isViewable) {
403
392
  const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
@@ -416,15 +405,43 @@ BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
416
405
  book.getPage(pageIndex).makeViewable();
417
406
  makeUnviewableAtEnd = true;
418
407
  }
408
+
409
+ // Trigger an update of book
410
+ this._modes.mode1Up.mode1UpLit.updatePages();
411
+ if (this.activeMode == this._modes.mode1Up) {
412
+ await this._modes.mode1Up.mode1UpLit.updateComplete;
413
+ }
419
414
  }
420
415
  /* this updates the URL */
421
- this.suppressFragmentChange = false;
422
- this.jumpToIndex(pageIndex);
416
+ if (!this._isIndexDisplayed(pageIndex)) {
417
+ this.suppressFragmentChange = false;
418
+ this.jumpToIndex(pageIndex);
419
+ }
423
420
 
424
421
  // Reset it to unviewable if it wasn't resolved
425
422
  if (makeUnviewableAtEnd) {
426
423
  book.getPage(pageIndex).makeViewable(false);
427
424
  }
425
+
426
+ // Scroll/flash in the ui
427
+ const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });
428
+ if ($boxes.length) {
429
+ $boxes.css('animation', 'none');
430
+ $boxes[0].scrollIntoView({
431
+ // Only vertically center the highlight if we're in 1up or in full screen. In
432
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
433
+ // center the highlight 🙄 See:
434
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
435
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
436
+ // full-width, and covers up the last line of the highlight.
437
+ block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
438
+ inline: 'center',
439
+ behavior: onNearbyPage ? 'smooth' : 'auto',
440
+ });
441
+ // wait for animation to start
442
+ await new Promise(resolve => setTimeout(resolve, 100));
443
+ $boxes.removeAttr("style");
444
+ }
428
445
  };
429
446
 
430
447
  /**
@@ -458,7 +475,7 @@ BookReader.prototype.searchHighlightVisible = function() {
458
475
 
459
476
  results.matches.some(match => {
460
477
  return match.par[0].boxes.some(box => {
461
- const pageIndex = this.leafNumToIndex(box.page);
478
+ const pageIndex = this.book.leafNumToIndex(box.page);
462
479
  if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
463
480
  return true;
464
481
  }
@@ -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
+ }
@@ -9,11 +9,6 @@ class SearchView {
9
9
  */
10
10
  constructor({ br, searchCancelledCallback = () => {} }) {
11
11
  this.br = br;
12
-
13
- // Search results are returned as a text blob with the hits wrapped in
14
- // triple mustaches. Hits occasionally include text beyond the search
15
- // term, so everything within the staches is captured and wrapped.
16
- this.matcher = new RegExp('{{{(.+?)}}}', 'g');
17
12
  this.matches = [];
18
13
  this.cacheDOMElements();
19
14
  this.bindEvents();
@@ -142,17 +137,19 @@ class SearchView {
142
137
  const start = pool.slice(0, pool.length / 2);
143
138
  const end = pool.slice(pool.length / 2);
144
139
  return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);
145
- }
140
+ };
146
141
 
147
142
  const closestPage = closestTo(matchPages, currentPage);
148
143
  return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));
149
144
  }
150
145
 
151
146
  updateResultsPosition() {
147
+ if (!this.dom.searchNavigation) return;
152
148
  this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
153
149
  }
154
150
 
155
151
  updateSearchNavigationButtons() {
152
+ if (!this.dom.searchNavigation) return;
156
153
  this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
157
154
  this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
158
155
  }
@@ -226,25 +223,20 @@ class SearchView {
226
223
  */
227
224
  renderPins(matches) {
228
225
  matches.forEach((match) => {
229
- const queryString = match.text;
230
- const pageIndex = this.br.leafNumToIndex(match.par[0].page);
231
- const pageNumber = this.br.getPageNum(pageIndex);
226
+ const pageIndex = this.br.book.leafNumToIndex(match.par[0].page);
232
227
  const uiStringSearch = "Search result"; // i18n
233
- const uiStringPage = "Page"; // i18n
234
-
235
- const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.getNumLeafs() - 1);
236
-
237
- const queryStringWithB = queryString.replace(this.matcher, '<b>$1</b>');
238
-
239
- let queryStringWithBTruncated = '';
240
-
241
- if (queryString.length > 100) {
242
- queryStringWithBTruncated = queryString
243
- .replace(/^(.{100}[^\s]*).*/, "$1")
244
- .replace(this.matcher, '<b>$1</b>')
245
- + '...';
228
+ const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.book.getNumLeafs() - 1);
229
+
230
+ let html = match.html;
231
+ if (html.length > 200) {
232
+ const start = Math.max(0, html.indexOf('<mark>') - 100);
233
+ if (start != 0) {
234
+ html = '' + match.html
235
+ .substring(start)
236
+ // Make sure at word boundary though
237
+ .replace(/^\S+/, '');
238
+ }
246
239
  }
247
-
248
240
  // draw marker
249
241
  $('<div>')
250
242
  .addClass('BRsearch')
@@ -254,35 +246,27 @@ class SearchView {
254
246
  .attr('title', uiStringSearch)
255
247
  .append(`
256
248
  <div class="BRquery">
257
- <div>${queryStringWithBTruncated || queryStringWithB}</div>
258
- <div>${uiStringPage} ${pageNumber}</div>
249
+ <main>${html}</main>
250
+ <footer>Page ${match.displayPageNumber}</footer>
259
251
  </div>
260
252
  `)
261
- .data({ pageIndex })
262
253
  .appendTo(this.br.$('.BRnavline'))
263
- .hover(
264
- (event) => {
265
- // remove from other markers then turn on just for this
266
- // XXX should be done when nav slider moves
267
- const marker = event.currentTarget;
268
- const tooltip = marker.querySelector('.BRquery');
269
- const tooltipOffset = tooltip.getBoundingClientRect();
270
- const targetOffset = marker.getBoundingClientRect();
271
- const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
272
- if (tooltipOffset.x - boxSizeAdjust < 0) {
273
- tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);
274
- }
275
- $('.BRsearch,.BRchapter').removeClass('front');
276
- $(event.target).addClass('front');
277
- },
278
- (event) => $(event.target).removeClass('front'))
279
- .click(function (event) {
280
- // closures are nested and deep, using an arrow function breaks references.
281
- // Todo: update to arrow function & clean up closures
282
- // to remove `bind` dependency
283
- this.br._searchPluginGoToResult(+$(event.target).data('pageIndex'));
284
- this.br.updateSearchHilites();
285
- }.bind(this));
254
+ .on("mouseenter", (event) => {
255
+ // remove from other markers then turn on just for this
256
+ // XXX should be done when nav slider moves
257
+ const marker = event.currentTarget;
258
+ const tooltip = marker.querySelector('.BRquery');
259
+ const tooltipOffset = tooltip.getBoundingClientRect();
260
+ const targetOffset = marker.getBoundingClientRect();
261
+ const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
262
+ if (tooltipOffset.x - boxSizeAdjust < 0) {
263
+ tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);
264
+ }
265
+ $('.BRsearch,.BRchapter').removeClass('front');
266
+ $(event.target).addClass('front');
267
+ })
268
+ .on("mouseleave", (event) => $(event.target).removeClass('front'))
269
+ .on("click", () => { this.br._searchPluginGoToResult(match.matchIndex); });
286
270
  });
287
271
  }
288
272
 
@@ -386,14 +370,6 @@ class SearchView {
386
370
  }
387
371
  }
388
372
 
389
- /**
390
- * @param {Event} e
391
- */
392
- handleNavToggledCallback(e) {
393
- const is_visible = this.br.navigationIsVisible();
394
- this.togglePinsFor(is_visible);
395
- }
396
-
397
373
  handleSearchStarted() {
398
374
  this.emptyMatches();
399
375
  this.br.removeSearchHilites();
@@ -428,7 +404,6 @@ class SearchView {
428
404
 
429
405
  window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));
430
406
  $(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))
431
- .on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))
432
407
  .on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))
433
408
  .on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))
434
409
  .on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))