@internetarchive/bookreader 5.0.0-11 → 5.0.0-110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +604 -1239
  4. package/BookReader/BookReader.js +1 -1
  5. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  6. package/BookReader/BookReader.js.map +1 -1
  7. package/BookReader/bergamot-translator-worker.js +2966 -0
  8. package/BookReader/bergamot-translator-worker.wasm +0 -0
  9. package/BookReader/hypothesis/LICENSE +50 -0
  10. package/BookReader/hypothesis/README.md +55 -0
  11. package/BookReader/hypothesis/build/boot.js +1 -0
  12. package/BookReader/hypothesis/build/manifest.json +20 -0
  13. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +184 -0
  14. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +798 -0
  16. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  17. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +711 -0
  18. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  19. package/BookReader/hypothesis/build/styles/annotator.css +2235 -0
  20. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  38. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  39. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  40. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  41. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  42. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/katex.min.css +2 -0
  44. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +2 -0
  46. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  47. package/BookReader/hypothesis/build/styles/sidebar.css +2731 -0
  48. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  49. package/BookReader/hypothesis/build/styles/ui-playground.css +2659 -0
  50. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  51. package/BookReader/hypothesis/package.json +126 -0
  52. package/BookReader/ia-bookreader-bundle.js +1907 -0
  53. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  54. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  55. package/BookReader/icons/1up.svg +1 -1
  56. package/BookReader/icons/2up.svg +1 -1
  57. package/BookReader/icons/advance.svg +1 -1
  58. package/BookReader/icons/chevron-right.svg +1 -1
  59. package/BookReader/icons/close-circle-dark.svg +1 -1
  60. package/BookReader/icons/close-circle.svg +1 -1
  61. package/BookReader/icons/fullscreen.svg +1 -1
  62. package/BookReader/icons/fullscreen_exit.svg +1 -1
  63. package/BookReader/icons/hamburger.svg +1 -1
  64. package/BookReader/icons/left-arrow.svg +1 -1
  65. package/BookReader/icons/magnify-minus.svg +1 -1
  66. package/BookReader/icons/magnify-plus.svg +1 -1
  67. package/BookReader/icons/magnify.svg +1 -1
  68. package/BookReader/icons/pause.svg +1 -1
  69. package/BookReader/icons/play.svg +1 -1
  70. package/BookReader/icons/playback-speed.svg +1 -1
  71. package/BookReader/icons/read-aloud.svg +1 -1
  72. package/BookReader/icons/review.svg +1 -1
  73. package/BookReader/icons/slider-toggle.svg +1 -0
  74. package/BookReader/icons/thumbnails.svg +1 -1
  75. package/BookReader/icons/voice.svg +1 -0
  76. package/BookReader/icons/volume-full.svg +1 -1
  77. package/BookReader/images/BRicons.svg +3 -3
  78. package/BookReader/images/books_graphic.svg +1 -1
  79. package/BookReader/images/hypothesis.ico +0 -0
  80. package/BookReader/images/icon_book.svg +1 -1
  81. package/BookReader/images/icon_bookmark.svg +1 -1
  82. package/BookReader/images/icon_experiment.svg +1 -0
  83. package/BookReader/images/icon_gear.svg +1 -1
  84. package/BookReader/images/icon_hamburger.svg +1 -1
  85. package/BookReader/images/icon_home.svg +1 -1
  86. package/BookReader/images/icon_info.svg +1 -1
  87. package/BookReader/images/icon_one_page.svg +1 -1
  88. package/BookReader/images/icon_pause.svg +1 -1
  89. package/BookReader/images/icon_play.svg +1 -1
  90. package/BookReader/images/icon_playback-rate.svg +1 -1
  91. package/BookReader/images/icon_search_button.svg +1 -1
  92. package/BookReader/images/icon_share.svg +1 -1
  93. package/BookReader/images/icon_skip-ahead.svg +1 -1
  94. package/BookReader/images/icon_skip-back.svg +1 -1
  95. package/BookReader/images/icon_speaker.svg +1 -1
  96. package/BookReader/images/icon_speaker_open.svg +1 -1
  97. package/BookReader/images/icon_thumbnails.svg +1 -1
  98. package/BookReader/images/icon_toc.svg +1 -1
  99. package/BookReader/images/icon_two_pages.svg +1 -1
  100. package/BookReader/images/marker_chap-off.svg +1 -1
  101. package/BookReader/images/marker_chap-on.svg +1 -1
  102. package/BookReader/images/marker_srch-on.svg +1 -1
  103. package/BookReader/images/translate.svg +1 -0
  104. package/BookReader/images/unviewable_page.png +0 -0
  105. package/BookReader/jquery-3.js +2 -0
  106. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  107. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  108. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js +1 -1
  110. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  111. package/BookReader/plugins/plugin.chapters.js +22 -1
  112. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  113. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  114. package/BookReader/plugins/plugin.experiments.js +3 -0
  115. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  116. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  117. package/BookReader/plugins/plugin.iframe.js +1 -1
  118. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  119. package/BookReader/plugins/plugin.iiif.js +2 -0
  120. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  121. package/BookReader/plugins/plugin.resume.js +1 -1
  122. package/BookReader/plugins/plugin.resume.js.map +1 -1
  123. package/BookReader/plugins/plugin.search.js +2 -1
  124. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  125. package/BookReader/plugins/plugin.search.js.map +1 -1
  126. package/BookReader/plugins/plugin.text_selection.js +2 -1
  127. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  128. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  129. package/BookReader/plugins/plugin.translate.js +137 -0
  130. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  131. package/BookReader/plugins/plugin.translate.js.map +1 -0
  132. package/BookReader/plugins/plugin.tts.js +1 -1
  133. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  134. package/BookReader/plugins/plugin.tts.js.map +1 -1
  135. package/BookReader/plugins/plugin.url.js +1 -1
  136. package/BookReader/plugins/plugin.url.js.map +1 -1
  137. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  138. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  139. package/BookReader/plugins/translator-worker.js +2 -0
  140. package/BookReader/plugins/translator-worker.js.map +1 -0
  141. package/BookReader/silence.mp3 +0 -0
  142. package/BookReader/translator-worker.js +475 -0
  143. package/BookReader/webcomponents-bundle.js +3 -0
  144. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  145. package/BookReader/webcomponents-bundle.js.map +1 -0
  146. package/README.md +14 -3
  147. package/jsconfig.json +19 -0
  148. package/package.json +92 -70
  149. package/src/BookReader/BookModel.js +92 -46
  150. package/src/BookReader/DragScrollable.js +233 -0
  151. package/src/BookReader/ImageCache.js +49 -16
  152. package/src/BookReader/Mode1Up.js +66 -365
  153. package/src/BookReader/Mode1UpLit.js +392 -0
  154. package/src/BookReader/Mode2Up.js +87 -1315
  155. package/src/BookReader/Mode2UpLit.js +788 -0
  156. package/src/BookReader/ModeAbstract.js +43 -0
  157. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  158. package/src/BookReader/ModeSmoothZoom.js +312 -0
  159. package/src/BookReader/ModeThumb.js +29 -15
  160. package/src/BookReader/Navbar/Navbar.js +201 -76
  161. package/src/BookReader/PageContainer.js +120 -23
  162. package/src/BookReader/ReduceSet.js +2 -2
  163. package/src/BookReader/Toolbar/Toolbar.js +18 -40
  164. package/src/BookReader/events.js +3 -3
  165. package/src/BookReader/options.js +94 -17
  166. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  167. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  168. package/src/BookReader/utils/SelectionObserver.js +45 -0
  169. package/src/BookReader/utils/classes.js +1 -1
  170. package/src/BookReader/utils.js +136 -12
  171. package/src/BookReader.js +678 -1226
  172. package/src/BookReaderPlugin.js +52 -0
  173. package/src/assets/icons/magnify-minus.svg +3 -7
  174. package/src/assets/icons/magnify-plus.svg +3 -7
  175. package/src/assets/icons/slider-toggle.svg +1 -0
  176. package/src/assets/icons/voice.svg +1 -0
  177. package/src/assets/images/hypothesis.ico +0 -0
  178. package/src/assets/images/icon_experiment.svg +1 -0
  179. package/src/assets/images/translate.svg +1 -0
  180. package/src/assets/images/unviewable_page.png +0 -0
  181. package/src/assets/silence.mp3 +0 -0
  182. package/src/css/BookReader.scss +1 -5
  183. package/src/css/_BRBookmarks.scss +1 -1
  184. package/src/css/_BRComponent.scss +1 -1
  185. package/src/css/_BRicon.scss +8 -2
  186. package/src/css/_BRmain.scss +16 -3
  187. package/src/css/_BRnav.scss +74 -70
  188. package/src/css/_BRpages.scss +171 -42
  189. package/src/css/_BRsearch.scss +69 -30
  190. package/src/css/_BRtoolbar.scss +5 -5
  191. package/src/css/_TextSelection.scss +129 -24
  192. package/src/css/_colorbox.scss +2 -2
  193. package/src/css/_controls.scss +24 -7
  194. package/src/css/_icons.scss +8 -1
  195. package/src/{BookNavigator/assets → css}/button-base.js +2 -2
  196. package/src/css/icon_checkmark.js +9 -0
  197. package/src/css/sharedStyles.js +15 -0
  198. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  199. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +25 -5
  200. package/src/ia-bookreader/ia-bookreader.js +666 -0
  201. package/src/ia-bookreader/sharing.js +27 -0
  202. package/src/ia-bookreader/viewable-files.js +98 -0
  203. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  204. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  205. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  206. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  207. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +43 -31
  208. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  209. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +3 -3
  210. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  211. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  212. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  213. package/src/plugins/plugin.archive_analytics.js +84 -78
  214. package/src/plugins/plugin.autoplay.js +99 -104
  215. package/src/plugins/plugin.chapters.js +314 -205
  216. package/src/plugins/plugin.experiments.js +321 -0
  217. package/src/plugins/plugin.iframe.js +1 -1
  218. package/src/plugins/plugin.iiif.js +141 -0
  219. package/src/plugins/plugin.resume.js +54 -51
  220. package/src/plugins/plugin.text_selection.js +522 -219
  221. package/src/plugins/plugin.vendor-fullscreen.js +5 -5
  222. package/src/plugins/search/plugin.search.js +374 -392
  223. package/src/{BookNavigator → plugins}/search/search-provider.js +59 -27
  224. package/src/{BookNavigator → plugins}/search/search-results.js +105 -76
  225. package/src/plugins/search/utils.js +50 -0
  226. package/src/plugins/search/view.js +50 -68
  227. package/src/plugins/translate/TranslationManager.js +164 -0
  228. package/src/plugins/translate/plugin.translate.js +512 -0
  229. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  230. package/src/plugins/tts/FestivalTTSEngine.js +20 -30
  231. package/src/plugins/tts/PageChunk.js +33 -21
  232. package/src/plugins/tts/PageChunkIterator.js +11 -17
  233. package/src/plugins/tts/WebTTSEngine.js +131 -91
  234. package/src/plugins/tts/plugin.tts.js +345 -350
  235. package/src/plugins/tts/utils.js +77 -49
  236. package/src/plugins/url/UrlPlugin.js +191 -0
  237. package/src/plugins/{plugin.url.js → url/plugin.url.js} +44 -15
  238. package/src/util/TextSelectionManager.js +282 -0
  239. package/src/util/browserSniffing.js +33 -1
  240. package/src/util/cache.js +20 -0
  241. package/src/util/docCookies.js +21 -2
  242. package/src/util/lit.js +15 -0
  243. package/src/util/strings.js +1 -0
  244. package/.babelrc +0 -12
  245. package/.dependabot/config.yml +0 -6
  246. package/.eslintrc.js +0 -50
  247. package/.gitattributes +0 -2
  248. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  249. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  250. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  251. package/.github/workflows/node.js.yml +0 -37
  252. package/.github/workflows/npm-publish.yml +0 -47
  253. package/.testcaferc.json +0 -5
  254. package/BookReader/bookreader-component-bundle.js +0 -1450
  255. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  256. package/BookReader/bookreader-component-bundle.js.map +0 -1
  257. package/BookReader/jquery-1.10.1.js +0 -2
  258. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  259. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  260. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  261. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  262. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  263. package/BookReaderDemo/BookReaderDemo.css +0 -41
  264. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  265. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  266. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  267. package/BookReaderDemo/IIIFBookReader.js +0 -207
  268. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  269. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  270. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  273. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  274. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  275. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  276. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  277. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  278. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  279. package/BookReaderDemo/demo-advanced.html +0 -33
  280. package/BookReaderDemo/demo-autoplay.html +0 -38
  281. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  282. package/BookReaderDemo/demo-embed.html +0 -26
  283. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  284. package/BookReaderDemo/demo-fullscreen.html +0 -33
  285. package/BookReaderDemo/demo-iiif.html +0 -34
  286. package/BookReaderDemo/demo-iiif.js +0 -26
  287. package/BookReaderDemo/demo-internetarchive.html +0 -74
  288. package/BookReaderDemo/demo-multiple.html +0 -43
  289. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  290. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  291. package/BookReaderDemo/demo-simple.html +0 -34
  292. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  293. package/BookReaderDemo/immersion-1up.html +0 -64
  294. package/BookReaderDemo/immersion-mode.html +0 -35
  295. package/BookReaderDemo/toggle_controls.html +0 -53
  296. package/BookReaderDemo/view_mode.html +0 -39
  297. package/BookReaderDemo/viewmode-cycle.html +0 -41
  298. package/CHANGELOG.md +0 -495
  299. package/CONTRIBUTING.md +0 -7
  300. package/codecov.yml +0 -17
  301. package/index.html +0 -31
  302. package/karma.conf.js +0 -23
  303. package/screenshot.png +0 -0
  304. package/scripts/postversion.js +0 -10
  305. package/scripts/preversion.js +0 -14
  306. package/scripts/version.js +0 -26
  307. package/src/BookNavigator/BookModel.js +0 -14
  308. package/src/BookNavigator/BookNavigator.js +0 -446
  309. package/src/BookNavigator/assets/book-loader.js +0 -27
  310. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  311. package/src/BookNavigator/assets/icon_close.js +0 -3
  312. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  313. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  314. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  315. package/src/BookNavigator/search/a-search-result.js +0 -55
  316. package/src/BookReader/DebugConsole.js +0 -54
  317. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  318. package/src/ItemNavigator/ItemNavigator.js +0 -376
  319. package/src/ItemNavigator/providers/sharing.js +0 -29
  320. package/src/css/_MobileNav.scss +0 -194
  321. package/src/dragscrollable-br.js +0 -261
  322. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  323. package/src/plugins/plugin.mobile_nav.js +0 -287
  324. package/tests/BookReader/BookModel.test.js +0 -312
  325. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  326. package/tests/BookReader/DebugConsole.test.js +0 -25
  327. package/tests/BookReader/ImageCache.test.js +0 -150
  328. package/tests/BookReader/Mode1Up.test.js +0 -164
  329. package/tests/BookReader/Mode2Up.test.js +0 -247
  330. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  331. package/tests/BookReader/PageContainer.test.js +0 -115
  332. package/tests/BookReader/ReduceSet.test.js +0 -38
  333. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  334. package/tests/BookReader/utils/classes.test.js +0 -88
  335. package/tests/BookReader/utils.test.js +0 -109
  336. package/tests/BookReader.options.test.js +0 -39
  337. package/tests/BookReader.test.js +0 -301
  338. package/tests/e2e/README.md +0 -75
  339. package/tests/e2e/autoplay.test.js +0 -13
  340. package/tests/e2e/base.test.js +0 -35
  341. package/tests/e2e/helpers/base.js +0 -263
  342. package/tests/e2e/helpers/debug.js +0 -13
  343. package/tests/e2e/helpers/desktopSearch.js +0 -72
  344. package/tests/e2e/helpers/mobileSearch.js +0 -85
  345. package/tests/e2e/helpers/mockSearch.js +0 -93
  346. package/tests/e2e/helpers/rightToLeft.js +0 -29
  347. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  348. package/tests/e2e/models/BookReader.js +0 -11
  349. package/tests/e2e/models/Navigation.js +0 -56
  350. package/tests/e2e/rightToLeft.test.js +0 -20
  351. package/tests/e2e/viewmode.test.js +0 -37
  352. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  353. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  354. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  355. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  356. package/tests/karma/BookNavigator/search/search-results.test.js +0 -240
  357. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  358. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  359. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  360. package/tests/plugins/plugin.autoplay.test.js +0 -52
  361. package/tests/plugins/plugin.chapters.test.js +0 -130
  362. package/tests/plugins/plugin.iframe.test.js +0 -42
  363. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  364. package/tests/plugins/plugin.resume.test.js +0 -98
  365. package/tests/plugins/plugin.text_selection.test.js +0 -203
  366. package/tests/plugins/plugin.url.test.js +0 -129
  367. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  368. package/tests/plugins/search/plugin.search.test.js +0 -173
  369. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  370. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  371. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  372. package/tests/plugins/tts/PageChunk.test.js +0 -57
  373. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  374. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  375. package/tests/plugins/tts/utils.test.js +0 -133
  376. package/tests/util/browserSniffing.test.js +0 -56
  377. package/tests/util/docCookies.test.js +0 -15
  378. package/tests/util/strings.test.js +0 -63
  379. package/tests/utils.js +0 -42
  380. package/webpack.config.js +0 -86
@@ -1,9 +1,11 @@
1
+ // @ts-check
1
2
  /** @typedef {import("../../BookReader.js").default} BookReader */
2
3
 
3
4
  import 'jquery-ui/ui/widget.js';
4
5
  import 'jquery-ui/ui/widgets/mouse.js';
5
6
  import 'jquery-ui/ui/widgets/slider.js';
6
7
  import { EVENTS } from '../events.js';
8
+ import { throttle } from '../utils.js';
7
9
 
8
10
  export class Navbar {
9
11
  /**
@@ -21,16 +23,23 @@ export class Navbar {
21
23
 
22
24
  /** @type {Object} controls will be switch over "this.maximumControls" */
23
25
  this.minimumControls = [
24
- 'viewmode'
26
+ 'toggle_slider', 'viewmode',
25
27
  ];
26
28
  /** @type {Object} controls will be switch over "this.minimumControls" */
27
29
  this.maximumControls = [
28
- 'book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb'
30
+ 'BRnavpos', 'book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb',
29
31
  ];
32
+
33
+ this.updateNavIndexThrottled = throttle(this.updateNavIndex.bind(this), 250, false);
30
34
  }
31
35
 
32
- controlFor(controlName) {
33
- const option = this.br.options.controls[controlName];
36
+ /**
37
+ * @param {string} controlName
38
+ * @param {Object} optionOverrides
39
+ */
40
+ controlFor(controlName, optionOverrides = null) {
41
+ const brOption = this.br.options.controls[controlName];
42
+ const option = Object.assign({},brOption, optionOverrides);
34
43
  if (!option.visible) { return ''; }
35
44
  if (option.template) {
36
45
  return `<li>${option.template(this.br)}</li>`;
@@ -38,7 +47,7 @@ export class Navbar {
38
47
  return `<li>
39
48
  <button class="BRicon ${option.className}" title="${option.label}">
40
49
  <div class="icon icon-${option.iconClassName}"></div>
41
- <span class="tooltip">${option.label}</span>
50
+ <span class="BRtooltip">${option.label}</span>
42
51
  </button>
43
52
  </li>`;
44
53
  }
@@ -46,6 +55,7 @@ export class Navbar {
46
55
  /** @private */
47
56
  _renderControls() {
48
57
  return [
58
+ 'toggleSlider',
49
59
  'bookLeft',
50
60
  'bookRight',
51
61
  'onePage',
@@ -112,11 +122,68 @@ export class Navbar {
112
122
  this.updateViewModeButton(
113
123
  $button,
114
124
  currentViewModeButton.className,
115
- currentViewModeButton.title
125
+ currentViewModeButton.title,
116
126
  );
117
127
  });
118
128
  }
119
129
 
130
+ bindControlClickHandlers() {
131
+ const jIcons = this.$nav.find('.BRicon');
132
+
133
+ // Map of jIcon class -> click handler
134
+ const navigationControls = {
135
+ toggle_slider: () => {
136
+ this.br.toggleSlider();
137
+ },
138
+ book_left: this.br.left.bind(this.br),
139
+ book_right: this.br.right.bind(this.br),
140
+ book_top: this.br.first.bind(this.br),
141
+ book_bottom: this.br.last.bind(this.br),
142
+ book_leftmost: this.br.leftmost.bind(this.br),
143
+ book_rightmost: this.br.rightmost.bind(this.br),
144
+ onepg: () => {
145
+ this.br.switchMode('1up');
146
+ },
147
+ thumb: () => {
148
+ this.br.switchMode('thumb');
149
+ },
150
+ twopg: () => {
151
+ this.br.switchMode('2up');
152
+ },
153
+ zoom_in: () => {
154
+ this.br.trigger(EVENTS.stop);
155
+ this.br.zoom(1);
156
+ this.br.trigger(EVENTS.zoomIn);
157
+ },
158
+ zoom_out: () => {
159
+ this.br.trigger(EVENTS.stop);
160
+ this.br.zoom(-1);
161
+ this.br.trigger(EVENTS.zoomOut);
162
+ },
163
+ full: () => {
164
+ if (this.br.ui == 'embed') {
165
+ const url = this.br.$('.BRembedreturn a').attr('href');
166
+ window.open(url);
167
+ } else {
168
+ this.br.toggleFullscreen();
169
+ }
170
+ },
171
+ };
172
+
173
+ // custom event for auto-loan-renew in ia-book-actions
174
+ // - to know if user is actively reading
175
+ this.$nav.find('nav.BRcontrols li button').on('click', () => {
176
+ this.br.trigger(EVENTS.userAction);
177
+ });
178
+
179
+ for (const control in navigationControls) {
180
+ jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
181
+ navigationControls[control]();
182
+ return false;
183
+ });
184
+ }
185
+ }
186
+
120
187
  /**
121
188
  * Toggle viewmode button to change page view
122
189
  */
@@ -127,7 +194,7 @@ export class Navbar {
127
194
  .removeClass()
128
195
  .addClass(`icon icon-${iconClass}`)
129
196
  .end()
130
- .find('.tooltip')
197
+ .find('.BRtooltip')
131
198
  .text(tooltipText);
132
199
  }
133
200
 
@@ -138,41 +205,45 @@ export class Navbar {
138
205
  // we don't want navbar controls switching with liner-notes
139
206
  if (this.br.options.bookType !== 'linerNotes') {
140
207
  if (this.br.refs.$brContainer.prop('clientWidth') < 640) {
141
- this.showMinimumNavbarControls();
208
+ this.showMobileControls();
142
209
  } else {
143
- this.showMaximumNavbarControls();
210
+ this.showDesktopControls();
144
211
  }
145
212
  }
146
213
  }
147
214
 
148
215
  /**
149
- * Switch Book Navbar controls to minimised
150
- * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
216
+ * Switch Book controls to mobile mode
217
+ * NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
151
218
  */
152
- showMinimumNavbarControls() {
219
+ showMobileControls() {
153
220
  this.minimumControls.forEach((control) => {
154
- const element = document.querySelector(`.controls .${control}`);
221
+ const element = document.querySelector(`.BRnavMain .controls .${control}`);
155
222
  if (element) element.classList.remove('hide');
156
223
  });
157
224
  this.maximumControls.forEach((control) => {
158
- const element = document.querySelector(`.controls .${control}`);
225
+ const element = document.querySelector(`.BRnavMain .controls .${control}`);
159
226
  if (element) element.classList.add('hide');
160
227
  });
228
+ const mobileNav = document.querySelector(`.BRnavMobile`);
229
+ if (mobileNav) mobileNav.classList.remove('hide');
161
230
  }
162
231
 
163
232
  /**
164
- * Switch Book Navbar controls to maximized
165
- * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
233
+ * Switch Book controls to desktop mode
234
+ * NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
166
235
  */
167
- showMaximumNavbarControls() {
236
+ showDesktopControls() {
168
237
  this.maximumControls.forEach((control) => {
169
- const element = document.querySelector(`.controls .${control}`);
238
+ const element = document.querySelector(`.BRnavMain .controls .${control}`);
170
239
  if (element) element.classList.remove('hide');
171
240
  });
172
241
  this.minimumControls.forEach((control) => {
173
- const element = document.querySelector(`.controls .${control}`);
242
+ const element = document.querySelector(`.BRnavMain .controls .${control}`);
174
243
  if (element) element.classList.add('hide');
175
244
  });
245
+ const mobileNav = document.querySelector(`.BRnavMobile`);
246
+ if (mobileNav) mobileNav.classList.add('hide');
176
247
  }
177
248
 
178
249
  /**
@@ -191,7 +262,7 @@ export class Navbar {
191
262
 
192
263
  br.refs.$BRfooter = this.$root = $(`<div class="BRfooter"></div>`);
193
264
  br.refs.$BRnav = this.$nav = $(
194
- `<div class="BRnav BRnavDesktop">
265
+ `<div class="BRnav BRnavMobile docked">
195
266
  ${title ? `<div class="BRnavTitle">${title}</div>` : ''}
196
267
  <nav class="BRcontrols">
197
268
  <ul class="controls">
@@ -200,7 +271,24 @@ export class Navbar {
200
271
  <div class="BRpager"></div>
201
272
  <div class="BRnavline"></div>
202
273
  </div>
203
- <p><span class='BRcurrentpage'></span></p>
274
+ </li>
275
+ ${this.controlFor('bookLeft', {visible: true})}
276
+ ${this.controlFor('bookRight', {visible: true})}
277
+ </ul>
278
+ </nav>
279
+ </div>
280
+ <div class="BRnav BRnavMain">
281
+ ${title ? `<div class="BRnavTitle">${title}</div>` : ''}
282
+ <nav class="BRcontrols">
283
+ <ul class="controls">
284
+ <li class="scrubber">
285
+ <p>
286
+ <span class="BRcurrentpage"></span>
287
+ </p>
288
+ <div class="BRnavpos hide">
289
+ <div class="BRpager"></div>
290
+ <div class="BRnavline"></div>
291
+ </div>
204
292
  </li>
205
293
  ${this._renderControls()}
206
294
  </ul>
@@ -210,63 +298,95 @@ export class Navbar {
210
298
  this.$root.append(this.$nav);
211
299
  br.refs.$br.append(this.$root);
212
300
 
213
- const $slider = this.$root.find('.BRpager').slider({
301
+ this.br.on(EVENTS.beforePageChanged, (ev, { ariaLive }) => {
302
+ if (ariaLive) {
303
+ // So screen readers read out change
304
+ this.$root.find('.BRcurrentpage').attr('role', 'status');
305
+ } else {
306
+ this.$root.find('.BRcurrentpage').removeAttr('role');
307
+ }
308
+ });
309
+ this.br.on(EVENTS.pageChanged, (ev, { index }) => this.updateNavIndexThrottled(index));
310
+ br.options.controls.viewmode.visible && this._bindViewModeButton();
311
+ this.updateNavPageNum(br.currentIndex());
312
+
313
+ /** @type {JQuery} sliders */
314
+ const $sliders = this.$root.find('.BRpager').slider({
214
315
  animate: true,
215
316
  min: 0,
216
- max: br.getNumLeafs() - 1,
317
+ max: br.book.getNumLeafs() - 1,
217
318
  value: br.currentIndex(),
218
- range: "min"
319
+ range: "min",
219
320
  });
220
321
 
221
- $slider.on('slide', (event, ui) => {
222
- this.updateNavPageNum(ui.value);
223
- return true;
322
+ // The jQuery UI slider handles the keyboard shortcuts on the slider's
323
+ // handle, so need the aria labels there.
324
+ $sliders.find('.ui-slider-handle').attr({
325
+ 'role': 'slider',
326
+ 'aria-label': 'Page navigation slider',
327
+ 'aria-valuemin': 1,
328
+ 'aria-valuemax': br.book.getNumLeafs(),
224
329
  });
225
330
 
226
- $slider.on('slidechange', (event, ui) => {
331
+ // Ignore up/down arrow keys and page up/down keys, since they're confusingly different
332
+ // between slider movement and page movement. Down decreases slider value, which would move
333
+ // the scroll _up_ in 1up.
334
+ $sliders.find('.ui-slider-handle').off('keydown').on('keydown', (event) => {
335
+ switch (event.keyCode || event.which) {
336
+ case $.ui.keyCode.LEFT:
337
+ case $.ui.keyCode.RIGHT:
338
+ // Forward along to the default handler
339
+ if (isRTL) {
340
+ // Swap left/right for RTL
341
+ if (event.keyCode === $.ui.keyCode.LEFT) {
342
+ event.keyCode = $.ui.keyCode.RIGHT;
343
+ } else {
344
+ event.keyCode = $.ui.keyCode.LEFT;
345
+ }
346
+ }
347
+ $.ui.slider.prototype._handleEvents.keydown.call($(event.target).parent().data('ui-slider'), event);
348
+ event.stopPropagation();
349
+ break;
350
+ default:
351
+ return;
352
+ }
353
+ });
354
+
355
+ $sliders.on('slide', (event, ui) => {
356
+ if (this.br.mode === this.br.constMode2up) {
357
+ // in 2up, need to go to nearest page that is left page
358
+ const movingForward = ui.value > br.currentIndex();
359
+ const newPage = this.br.book.getPage(ui.value);
360
+ if (isRTL ? newPage.pageSide === 'L' : newPage.pageSide === 'R') {
361
+ ui.value += movingForward ? 1 : -1;
362
+ ui.value = Math.max(0, Math.min(ui.value, br.book.getNumLeafs() - 1));
363
+ }
364
+ }
227
365
  this.updateNavPageNum(ui.value);
366
+ });
367
+
368
+ $sliders.on('slidechange', (event, ui) => {
228
369
  // recursion prevention for jumpToIndex
229
- if ($slider.data('swallowchange')) {
230
- $slider.data('swallowchange', false);
231
- } else {
232
- br.jumpToIndex(ui.value);
370
+ if ($(event.target).data('swallowchange')) {
371
+ $(event.target).data('swallowchange', false);
372
+ return;
233
373
  }
234
- return true;
235
- });
236
374
 
237
- br.options.controls.viewmode.visible && this._bindViewModeButton();
238
- this.updateNavPageNum(br.currentIndex());
375
+ if (this.br.mode === this.br.constMode2up) {
376
+ // in 2up, need to go to nearest page that is left page
377
+ const movingForward = ui.value > br.currentIndex();
378
+ const newPage = this.br.book.getPage(ui.value);
379
+ if (isRTL ? newPage.pageSide === 'L' : newPage.pageSide === 'R') {
380
+ ui.value += movingForward ? 1 : -1;
381
+ ui.value = Math.max(0, Math.min(ui.value, br.book.getNumLeafs() - 1));
382
+ }
383
+ }
239
384
 
240
- return this.$nav;
241
- }
385
+ // Don't want this to be aria-live since the slider already announces the value
386
+ this.br.jumpToIndex(ui.value, {ariaLive: false});
387
+ });
242
388
 
243
- /**
244
- * Initialize the navigation bar when embedded
245
- */
246
- initEmbed() {
247
- const { br } = this;
248
- // IA-specific
249
- const thisLink = (window.location + '')
250
- .replace('?ui=embed','')
251
- .replace('/stream/', '/details/')
252
- .replace('#', '/');
253
- const logoHtml = br.showLogo ? `<a class="logo" href="${br.logoURL}" target="_blank"></a>` : '';
254
-
255
- br.refs.$BRfooter = this.$root = $('<div class="BRfooter"></div>');
256
- br.refs.$BRnav = this.$nav = $(
257
- `<div class="BRnav BRnavEmbed">
258
- ${logoHtml}
259
- <span class="BRembedreturn">
260
- <a href="${thisLink}" target="_blank">${br.bookTitle}</a>
261
- </span>
262
- <span class="BRtoolbarbuttons">
263
- <button class="BRicon book_left"></button>
264
- <button class="BRicon book_right"></button>
265
- <button class="BRicon full"></button>
266
- </span>
267
- </div>`);
268
- this.$root.append(this.$nav);
269
- br.refs.$br.append(this.$root);
389
+ return this.$nav;
270
390
  }
271
391
 
272
392
  /**
@@ -277,16 +397,16 @@ export class Navbar {
277
397
  getNavPageNumString(index) {
278
398
  const { br } = this;
279
399
  // Accessible index starts at 0 (alas) so we add 1 to make human
280
- const pageNum = br.getPageNum(index);
281
- const pageType = br.getPageProp(index, 'pageType');
282
- const numLeafs = br.getNumLeafs();
400
+ const pageNum = br.book.getPageNum(index);
401
+ const pageType = br.book.getPageProp(index, 'pageType');
402
+ const numLeafs = br.book.getNumLeafs();
283
403
 
284
404
  if (!this.maxPageNum) {
285
405
  // Calculate Max page num (used for pagination display)
286
406
  let maxPageNum = 0;
287
407
  let pageNumVal;
288
408
  for (let i = 0; i < numLeafs; i++) {
289
- pageNumVal = br.getPageNum(i);
409
+ pageNumVal = parseFloat(br.book.getPageNum(i));
290
410
  if (!isNaN(pageNumVal) && pageNumVal > maxPageNum) {
291
411
  maxPageNum = pageNumVal;
292
412
  }
@@ -295,6 +415,7 @@ export class Navbar {
295
415
  }
296
416
 
297
417
  return getNavPageNumHtml(index, numLeafs, pageNum, pageType, this.maxPageNum);
418
+
298
419
  }
299
420
 
300
421
  /**
@@ -303,6 +424,10 @@ export class Navbar {
303
424
  */
304
425
  updateNavPageNum(index) {
305
426
  this.$root.find('.BRcurrentpage').html(this.getNavPageNumString(index));
427
+ this.$root.find('.ui-slider-handle').attr({
428
+ 'aria-valuenow': index + 1,
429
+ 'aria-valuetext': this.getNavPageNumString(index),
430
+ });
306
431
  }
307
432
 
308
433
  /**
@@ -313,7 +438,9 @@ export class Navbar {
313
438
  // We want to update the value, but normally moving the slider
314
439
  // triggers jumpToIndex which triggers this method
315
440
  index = index !== undefined ? index : this.br.currentIndex();
316
- this.$root.find('.BRpager').data('swallowchange', true).slider('value', index);
441
+ this.$root.find('.BRpager').data('swallowchange', true);
442
+ this.$root.find('.BRpager').slider('value', index);
443
+ this.updateNavPageNum(index);
317
444
  }
318
445
  }
319
446
 
@@ -322,18 +449,16 @@ export class Navbar {
322
449
  * @param {number} index
323
450
  * @param {number} numLeafs
324
451
  * @param {number|string} pageNum
325
- * @param {*} pageType @deprecated
452
+ * @param {*} pageType - Deprecated
326
453
  * @param {number} maxPageNum
327
454
  * @return {string}
328
455
  */
329
456
  export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum) {
330
457
  const pageIsAsserted = pageNum[0] != 'n';
458
+ const pageIndex = index + 1;
331
459
 
332
460
  if (!pageIsAsserted) {
333
- const pageIndex = index + 1;
334
- return `(${pageIndex} of ${numLeafs})`; // Page (8 of 10)
461
+ pageNum = '—';
335
462
  }
336
-
337
- const bookLengthLabel = maxPageNum ? ` of ${maxPageNum}` : '';
338
- return `${pageNum}${bookLengthLabel}`;
463
+ return `Page ${pageNum} (${pageIndex}/${numLeafs})`;
339
464
  }
@@ -2,6 +2,8 @@
2
2
  /** @typedef {import('./BookModel.js').PageModel} PageModel */
3
3
  /** @typedef {import('./ImageCache.js').ImageCache} ImageCache */
4
4
 
5
+ import { sleep } from './utils.js';
6
+
5
7
 
6
8
  export class PageContainer {
7
9
  /**
@@ -9,16 +11,17 @@ export class PageContainer {
9
11
  * @param {object} opts
10
12
  * @param {boolean} opts.isProtected Whether we're in a protected book
11
13
  * @param {ImageCache} opts.imageCache
12
- * @param {string} opts.loadingImage
13
14
  */
14
- constructor(page, {isProtected, imageCache, loadingImage}) {
15
+ constructor(page, {isProtected, imageCache}) {
15
16
  this.page = page;
16
17
  this.imageCache = imageCache;
17
- this.loadingImage = loadingImage;
18
18
  this.$container = $('<div />', {
19
19
  'class': `BRpagecontainer ${page ? `pagediv${page.index}` : 'BRemptypage'}`,
20
20
  css: { position: 'absolute' },
21
- }).attr('data-side', page?.pageSide);
21
+ })
22
+ .attr('data-side', page?.pageSide)
23
+ .attr('data-index', page?.index)
24
+ .attr('data-page-num', page?.getPageNum());
22
25
 
23
26
  if (isProtected) {
24
27
  this.$container.append($('<div class="BRscreen" />'));
@@ -43,33 +46,127 @@ export class PageContainer {
43
46
  return;
44
47
  }
45
48
 
46
- const alreadyLoaded = this.imageCache.imageLoaded(this.page.index, reduce);
47
- const nextBestLoadedReduce = !alreadyLoaded && this.imageCache.getBestLoadedReduce(this.page.index, reduce);
49
+ const finalReduce = this.imageCache.getFinalReduce(this.page.index, reduce);
50
+ const newImageURI = this.page.getURI(finalReduce, 0);
48
51
 
49
- // Add the actual, highres image
50
- this.$img?.remove();
51
- this.$img = this.imageCache
52
- .image(this.page.index, reduce)
53
- .prependTo(this.$container);
52
+ // Note: These must be computed _before_ we call .image()
53
+ const alreadyLoaded = this.imageCache.imageLoaded(this.page.index, finalReduce);
54
+ const nextBestLoadedReduce = this.imageCache.getBestLoadedReduce(this.page.index, reduce);
54
55
 
55
- const backgroundLayers = [];
56
- if (!alreadyLoaded) {
57
- this.$container.addClass('BRpageloading');
58
- backgroundLayers.push(`url("${this.loadingImage}") center/20px no-repeat`);
56
+ // Avoid removing/re-adding the image if it's already there
57
+ // This can be called quite a bit, so we need to be fast
58
+ if (this.$img?.data('src') == newImageURI) {
59
+ return this;
59
60
  }
60
- if (nextBestLoadedReduce) {
61
- backgroundLayers.push(`url("${this.page.getURI(nextBestLoadedReduce, 0)}") center/100% no-repeat`);
61
+
62
+ let $oldImg = this.$img;
63
+ this.$img = this.imageCache.image(this.page.index, finalReduce);
64
+ if ($oldImg) {
65
+ this.$img.insertAfter($oldImg);
66
+ } else {
67
+ this.$img.prependTo(this.$container);
62
68
  }
63
69
 
64
70
  if (!alreadyLoaded) {
65
- this.$img
66
- .css('background', backgroundLayers.join(','))
67
- .one('loadend', async (ev) => {
68
- $(ev.target).css({ 'background': '' });
69
- $(ev.target).parent().removeClass('BRpageloading');
70
- });
71
+ this.$container.addClass('BRpageloading');
71
72
  }
72
73
 
74
+ if (!alreadyLoaded && nextBestLoadedReduce) {
75
+ // If we have a slightly lower quality image loaded, use that as the background
76
+ // while the higher res one loads
77
+ const nextBestUri = this.page.getURI(nextBestLoadedReduce, 0);
78
+ if ($oldImg) {
79
+ if ($oldImg.data('src') == nextBestUri) {
80
+ // Do nothing! It's already showing the right thing
81
+ } else {
82
+ // We have a different src, need to update the src
83
+ this.imageCache.image(this.page.index, nextBestLoadedReduce, $oldImg[0]);
84
+ }
85
+ } else {
86
+ // We don't have an old <img>, so we need to create a new one
87
+ $oldImg = this.imageCache.image(this.page.index, nextBestLoadedReduce);
88
+ $oldImg.prependTo(this.$container);
89
+ }
90
+ }
91
+
92
+ this.$img
93
+ .one('load', async (ev) => {
94
+ this.$container.removeClass('BRpageloading');
95
+ // `load` can fire a little early, so wait a spell before removing the old image
96
+ // to avoid flicker
97
+ await sleep(100);
98
+ $oldImg?.remove();
99
+ });
100
+
73
101
  return this;
74
102
  }
75
103
  }
104
+
105
+
106
+ /**
107
+ * @param {PageModel} page
108
+ * @param {string} className
109
+ */
110
+ export function createSVGPageLayer(page, className) {
111
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
112
+ svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
113
+ svg.setAttribute("viewBox", `0 0 ${page.width} ${page.height}`);
114
+ svg.setAttribute('class', `BRPageLayer ${className}`);
115
+ svg.setAttribute('preserveAspectRatio', 'none');
116
+ return svg;
117
+ }
118
+
119
+ /**
120
+ * @param {PageModel} page
121
+ * @param {string} className
122
+ */
123
+ export function createDIVPageLayer(page, className) {
124
+ const div = document.createElement("div");
125
+ div.style.width = `${page.width}px`;
126
+ div.style.height = `${page.height}px`;
127
+ div.setAttribute('class', `BRPageLayer ${className}`);
128
+ return div;
129
+ }
130
+
131
+ /**
132
+ * @param {{ l: number, r: number, b: number, t: number }} box
133
+ */
134
+ export function boxToSVGRect({ l: left, r: right, b: bottom, t: top }) {
135
+ const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
136
+ rect.setAttribute("x", left.toString());
137
+ rect.setAttribute("y", top.toString());
138
+ rect.setAttribute("width", (right - left).toString());
139
+ rect.setAttribute("height", (bottom - top).toString());
140
+
141
+ // Some style; corner radius 4px. Can't set this in CSS yet
142
+ rect.setAttribute("rx", "4");
143
+ rect.setAttribute("ry", "4");
144
+ return rect;
145
+ }
146
+
147
+ /**
148
+ * @param {string} layerClass
149
+ * @param {Array<{ l: number, r: number, b: number, t: number }>} boxes
150
+ * @param {PageModel} page
151
+ * @param {HTMLElement} containerEl
152
+ * @param {string[]} [rectClasses] CSS classes to add to the rects
153
+ */
154
+ export function renderBoxesInPageContainerLayer(layerClass, boxes, page, containerEl, rectClasses = null) {
155
+ const mountedSvg = containerEl.querySelector(`.${layerClass}`);
156
+ // Create the layer if it's not there
157
+ const svg = mountedSvg || createSVGPageLayer(page, layerClass);
158
+ if (!mountedSvg) {
159
+ // Insert after the image if the image is already loaded.
160
+ const imgEl = containerEl.querySelector('.BRpageimage');
161
+ if (imgEl) $(svg).insertAfter(imgEl);
162
+ else $(svg).prependTo(containerEl);
163
+ }
164
+
165
+ for (const [i, box] of boxes.entries()) {
166
+ const rect = boxToSVGRect(box);
167
+ if (rectClasses) {
168
+ rect.setAttribute('class', rectClasses[i]);
169
+ }
170
+ svg.appendChild(rect);
171
+ }
172
+ }
@@ -7,7 +7,7 @@
7
7
  /** @type {ReduceSet} */
8
8
  export const IntegerReduceSet = {
9
9
  floor: Math.floor,
10
- decr(n) { return n - 1; }
10
+ decr(n) { return n - 1; },
11
11
  };
12
12
 
13
13
  /** @type {ReduceSet} */
@@ -17,7 +17,7 @@ export const Pow2ReduceSet = {
17
17
  },
18
18
  decr(n) {
19
19
  return 2 ** (Math.log2(n) - 1);
20
- }
20
+ },
21
21
  };
22
22
 
23
23
  export const NAMED_REDUCE_SETS = {