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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +670 -1190
  4. package/BookReader/bergamot-translator-worker.js +2966 -0
  5. package/BookReader/bergamot-translator-worker.wasm +0 -0
  6. package/BookReader/hypothesis/LICENSE +50 -0
  7. package/BookReader/hypothesis/README.md +55 -0
  8. package/BookReader/hypothesis/build/boot-template.js +1 -0
  9. package/BookReader/hypothesis/build/boot.js +1 -0
  10. package/BookReader/hypothesis/build/manifest.json +20 -0
  11. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +199 -0
  12. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  13. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +811 -0
  14. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +437 -0
  16. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  17. package/BookReader/hypothesis/build/styles/annotator.css +4 -0
  18. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  19. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  20. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  38. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  39. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  40. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  41. package/BookReader/hypothesis/build/styles/katex.min.css +3 -0
  42. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +14 -0
  44. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/sidebar.css +4 -0
  46. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  47. package/BookReader/hypothesis/build/styles/ui-playground.css +4 -0
  48. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  49. package/BookReader/hypothesis/package.json +126 -0
  50. package/BookReader/ia-bookreader.js +1886 -0
  51. package/BookReader/{BookReader.js.LICENSE.txt → ia-bookreader.js.LICENSE.txt} +26 -20
  52. package/BookReader/ia-bookreader.js.map +1 -0
  53. package/BookReader/icons/1up.svg +1 -12
  54. package/BookReader/icons/2up.svg +1 -15
  55. package/BookReader/icons/advance.svg +3 -26
  56. package/BookReader/icons/chevron-right.svg +1 -1
  57. package/BookReader/icons/close-circle-dark.svg +1 -1
  58. package/BookReader/icons/close-circle.svg +1 -1
  59. package/BookReader/icons/fullscreen.svg +1 -17
  60. package/BookReader/icons/fullscreen_exit.svg +1 -17
  61. package/BookReader/icons/hamburger.svg +1 -15
  62. package/BookReader/icons/left-arrow.svg +1 -12
  63. package/BookReader/icons/magnify-minus.svg +1 -16
  64. package/BookReader/icons/magnify-plus.svg +1 -17
  65. package/BookReader/icons/magnify.svg +1 -15
  66. package/BookReader/icons/pause.svg +1 -23
  67. package/BookReader/icons/play.svg +1 -22
  68. package/BookReader/icons/playback-speed.svg +1 -34
  69. package/BookReader/icons/read-aloud.svg +1 -22
  70. package/BookReader/icons/review.svg +3 -22
  71. package/BookReader/icons/slider-toggle.svg +1 -0
  72. package/BookReader/icons/thumbnails.svg +1 -17
  73. package/BookReader/icons/voice.svg +1 -0
  74. package/BookReader/icons/volume-full.svg +1 -22
  75. package/BookReader/images/BRicons.svg +5 -94
  76. package/BookReader/images/books_graphic.svg +1 -177
  77. package/BookReader/images/hypothesis.ico +0 -0
  78. package/BookReader/images/icon_book.svg +1 -12
  79. package/BookReader/images/icon_bookmark.svg +1 -12
  80. package/BookReader/images/icon_experiment.svg +1 -0
  81. package/BookReader/images/icon_gear.svg +1 -14
  82. package/BookReader/images/icon_hamburger.svg +1 -20
  83. package/BookReader/images/icon_home.svg +1 -21
  84. package/BookReader/images/icon_info.svg +1 -11
  85. package/BookReader/images/icon_one_page.svg +1 -8
  86. package/BookReader/images/icon_pause.svg +1 -1
  87. package/BookReader/images/icon_play.svg +1 -1
  88. package/BookReader/images/icon_playback-rate.svg +1 -15
  89. package/BookReader/images/icon_search_button.svg +1 -8
  90. package/BookReader/images/icon_share.svg +1 -9
  91. package/BookReader/images/icon_skip-ahead.svg +1 -6
  92. package/BookReader/images/icon_skip-back.svg +2 -13
  93. package/BookReader/images/icon_speaker.svg +1 -18
  94. package/BookReader/images/icon_speaker_open.svg +1 -10
  95. package/BookReader/images/icon_thumbnails.svg +1 -12
  96. package/BookReader/images/icon_toc.svg +1 -5
  97. package/BookReader/images/icon_two_pages.svg +1 -9
  98. package/BookReader/images/marker_chap-off.svg +1 -11
  99. package/BookReader/images/marker_chap-on.svg +1 -11
  100. package/BookReader/images/marker_srch-on.svg +1 -11
  101. package/BookReader/images/translate.svg +1 -0
  102. package/BookReader/images/unviewable_page.png +0 -0
  103. package/BookReader/jquery-3.js +2 -0
  104. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  105. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  106. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  107. package/BookReader/plugins/plugin.autoplay.js +1 -165
  108. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  109. package/BookReader/plugins/plugin.chapters.js +19 -301
  110. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  111. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  112. package/BookReader/plugins/plugin.experiments.js +3 -0
  113. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  114. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  115. package/BookReader/plugins/plugin.iframe.js +1 -74
  116. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  117. package/BookReader/plugins/plugin.iiif.js +2 -0
  118. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  119. package/BookReader/plugins/plugin.resume.js +1 -368
  120. package/BookReader/plugins/plugin.resume.js.map +1 -1
  121. package/BookReader/plugins/plugin.search.js +2 -1385
  122. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  123. package/BookReader/plugins/plugin.search.js.map +1 -1
  124. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  125. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  126. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  127. package/BookReader/plugins/plugin.translate.js +3 -0
  128. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  129. package/BookReader/plugins/plugin.translate.js.map +1 -0
  130. package/BookReader/plugins/plugin.tts.js +2 -9193
  131. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  132. package/BookReader/plugins/plugin.tts.js.map +1 -1
  133. package/BookReader/plugins/plugin.url.js +1 -269
  134. package/BookReader/plugins/plugin.url.js.map +1 -1
  135. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  136. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  137. package/BookReader/plugins/translator-worker.js +2 -0
  138. package/BookReader/plugins/translator-worker.js.map +1 -0
  139. package/BookReader/silence.mp3 +0 -0
  140. package/BookReader/translator-worker.js +475 -0
  141. package/BookReader/webcomponents-bundle.js +3 -0
  142. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  143. package/BookReader/webcomponents-bundle.js.map +1 -0
  144. package/README.md +17 -4
  145. package/dist/esm/ia-bookreader.js +3 -0
  146. package/dist/esm/ia-bookreader.js.LICENSE.txt +17 -0
  147. package/dist/esm/ia-bookreader.js.map +1 -0
  148. package/dist/esm/plugins/plugin.archive_analytics.js +2 -0
  149. package/dist/esm/plugins/plugin.archive_analytics.js.map +1 -0
  150. package/dist/esm/plugins/plugin.autoplay.js +2 -0
  151. package/dist/esm/plugins/plugin.autoplay.js.map +1 -0
  152. package/dist/esm/plugins/plugin.chapters.js +2 -0
  153. package/dist/esm/plugins/plugin.chapters.js.map +1 -0
  154. package/dist/esm/plugins/plugin.experiments.js +2 -0
  155. package/dist/esm/plugins/plugin.experiments.js.map +1 -0
  156. package/dist/esm/plugins/plugin.iframe.js +2 -0
  157. package/dist/esm/plugins/plugin.iframe.js.map +1 -0
  158. package/dist/esm/plugins/plugin.iiif.js +2 -0
  159. package/dist/esm/plugins/plugin.iiif.js.map +1 -0
  160. package/dist/esm/plugins/plugin.resume.js +2 -0
  161. package/dist/esm/plugins/plugin.resume.js.map +1 -0
  162. package/dist/esm/plugins/plugin.search.js +2 -0
  163. package/dist/esm/plugins/plugin.search.js.map +1 -0
  164. package/dist/esm/plugins/plugin.text_selection.js +2 -0
  165. package/dist/esm/plugins/plugin.text_selection.js.map +1 -0
  166. package/dist/esm/plugins/plugin.translate.js +2 -0
  167. package/dist/esm/plugins/plugin.translate.js.map +1 -0
  168. package/dist/esm/plugins/plugin.tts.js +2 -0
  169. package/dist/esm/plugins/plugin.tts.js.map +1 -0
  170. package/dist/esm/plugins/plugin.url.js +2 -0
  171. package/dist/esm/plugins/plugin.url.js.map +1 -0
  172. package/dist/esm/plugins/plugin.vendor-fullscreen.js +2 -0
  173. package/dist/esm/plugins/plugin.vendor-fullscreen.js.map +1 -0
  174. package/jsconfig.json +18 -0
  175. package/package.json +113 -71
  176. package/src/BookReader/BookModel.js +92 -46
  177. package/src/BookReader/DragScrollable.js +233 -0
  178. package/src/BookReader/ImageCache.js +49 -16
  179. package/src/BookReader/Mode1Up.js +66 -365
  180. package/src/BookReader/Mode1UpLit.js +392 -0
  181. package/src/BookReader/Mode2Up.js +87 -1315
  182. package/src/BookReader/Mode2UpLit.js +786 -0
  183. package/src/BookReader/ModeAbstract.js +43 -0
  184. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  185. package/src/BookReader/ModeSmoothZoom.js +312 -0
  186. package/src/BookReader/ModeThumb.js +29 -15
  187. package/src/BookReader/Navbar/Navbar.js +204 -84
  188. package/src/BookReader/PageContainer.js +120 -23
  189. package/src/BookReader/ReduceSet.js +2 -2
  190. package/src/BookReader/Toolbar/Toolbar.js +18 -40
  191. package/src/BookReader/events.js +3 -3
  192. package/src/BookReader/options.js +105 -18
  193. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  194. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  195. package/src/BookReader/utils/SelectionObserver.js +72 -0
  196. package/src/BookReader/utils/classes.js +1 -1
  197. package/src/BookReader/utils.js +136 -12
  198. package/src/BookReader.js +732 -1231
  199. package/src/BookReaderPlugin.js +52 -0
  200. package/src/assets/icons/magnify-minus.svg +3 -7
  201. package/src/assets/icons/magnify-plus.svg +3 -7
  202. package/src/assets/icons/slider-toggle.svg +1 -0
  203. package/src/assets/icons/voice.svg +1 -0
  204. package/src/assets/images/hypothesis.ico +0 -0
  205. package/src/assets/images/icon_experiment.svg +1 -0
  206. package/src/assets/images/translate.svg +1 -0
  207. package/src/assets/images/unviewable_page.png +0 -0
  208. package/src/assets/silence.mp3 +0 -0
  209. package/src/css/BookReader.scss +1 -5
  210. package/src/css/_BRBookmarks.scss +1 -1
  211. package/src/css/_BRComponent.scss +1 -1
  212. package/src/css/_BRicon.scss +8 -2
  213. package/src/css/_BRmain.scss +16 -3
  214. package/src/css/_BRnav.scss +74 -70
  215. package/src/css/_BRpages.scss +174 -42
  216. package/src/css/_BRsearch.scss +69 -30
  217. package/src/css/_BRtoolbar.scss +5 -5
  218. package/src/css/_TextSelection.scss +249 -25
  219. package/src/css/_colorbox.scss +2 -2
  220. package/src/css/_controls.scss +24 -7
  221. package/src/css/_icons.scss +8 -1
  222. package/src/{BookNavigator/assets → css}/button-base.js +2 -2
  223. package/src/css/icon_checkmark.js +9 -0
  224. package/src/css/sharedStyles.js +15 -0
  225. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  226. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +25 -5
  227. package/src/ia-bookreader/ia-bookreader.js +686 -0
  228. package/src/ia-bookreader/sharing.js +27 -0
  229. package/src/ia-bookreader/viewable-files.js +98 -0
  230. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  231. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  232. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  233. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  234. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +43 -31
  235. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  236. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +3 -3
  237. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  238. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  239. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  240. package/src/plugins/plugin.archive_analytics.js +84 -78
  241. package/src/plugins/plugin.autoplay.js +99 -104
  242. package/src/plugins/plugin.chapters.js +323 -205
  243. package/src/plugins/plugin.experiments.js +375 -0
  244. package/src/plugins/plugin.iframe.js +36 -37
  245. package/src/plugins/plugin.iiif.js +147 -0
  246. package/src/plugins/plugin.resume.js +54 -51
  247. package/src/plugins/plugin.text_selection.js +464 -219
  248. package/src/plugins/plugin.vendor-fullscreen.js +5 -5
  249. package/src/plugins/search/plugin.search.js +347 -397
  250. package/src/{BookNavigator → plugins}/search/search-provider.js +59 -27
  251. package/src/{BookNavigator → plugins}/search/search-results.js +105 -76
  252. package/src/plugins/search/utils.js +50 -0
  253. package/src/plugins/search/view.js +51 -69
  254. package/src/plugins/translate/TranslationManager.js +164 -0
  255. package/src/plugins/translate/plugin.translate.js +559 -0
  256. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  257. package/src/plugins/tts/FestivalTTSEngine.js +20 -30
  258. package/src/plugins/tts/PageChunk.js +117 -23
  259. package/src/plugins/tts/PageChunkIterator.js +11 -17
  260. package/src/plugins/tts/WebTTSEngine.js +132 -92
  261. package/src/plugins/tts/plugin.tts.js +341 -351
  262. package/src/plugins/tts/utils.js +76 -67
  263. package/src/plugins/url/UrlPlugin.js +213 -0
  264. package/src/plugins/{plugin.url.js → url/plugin.url.js} +54 -18
  265. package/src/util/TextSelectionManager.js +1464 -0
  266. package/src/util/browserSniffing.js +42 -1
  267. package/src/util/cache.js +20 -0
  268. package/src/util/docCookies.js +21 -2
  269. package/src/util/dom.js +88 -0
  270. package/src/util/generators.js +89 -0
  271. package/src/util/lit.js +15 -0
  272. package/src/util/strings.js +11 -0
  273. package/.babelrc +0 -12
  274. package/.dependabot/config.yml +0 -6
  275. package/.eslintrc.js +0 -50
  276. package/.gitattributes +0 -2
  277. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  278. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  279. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  280. package/.github/workflows/node.js.yml +0 -37
  281. package/.github/workflows/npm-publish.yml +0 -47
  282. package/.testcaferc.json +0 -5
  283. package/BookReader/BookReader.js +0 -21613
  284. package/BookReader/BookReader.js.map +0 -1
  285. package/BookReader/bookreader-component-bundle.js +0 -14497
  286. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  287. package/BookReader/bookreader-component-bundle.js.map +0 -1
  288. package/BookReader/jquery-1.10.1.js +0 -108
  289. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  290. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  291. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  292. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  293. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  294. package/BookReaderDemo/BookReaderDemo.css +0 -41
  295. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  296. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  297. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  298. package/BookReaderDemo/IIIFBookReader.js +0 -207
  299. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  300. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  301. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  302. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  303. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  304. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  305. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  306. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  307. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  308. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  309. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  310. package/BookReaderDemo/demo-advanced.html +0 -33
  311. package/BookReaderDemo/demo-autoplay.html +0 -38
  312. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  313. package/BookReaderDemo/demo-embed.html +0 -26
  314. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  315. package/BookReaderDemo/demo-fullscreen.html +0 -33
  316. package/BookReaderDemo/demo-iiif.html +0 -34
  317. package/BookReaderDemo/demo-iiif.js +0 -26
  318. package/BookReaderDemo/demo-internetarchive.html +0 -74
  319. package/BookReaderDemo/demo-multiple.html +0 -43
  320. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  321. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  322. package/BookReaderDemo/demo-simple.html +0 -34
  323. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  324. package/BookReaderDemo/immersion-1up.html +0 -64
  325. package/BookReaderDemo/immersion-mode.html +0 -35
  326. package/BookReaderDemo/toggle_controls.html +0 -53
  327. package/BookReaderDemo/view_mode.html +0 -39
  328. package/BookReaderDemo/viewmode-cycle.html +0 -41
  329. package/CHANGELOG.md +0 -499
  330. package/CONTRIBUTING.md +0 -7
  331. package/codecov.yml +0 -17
  332. package/index.html +0 -31
  333. package/karma.conf.js +0 -23
  334. package/screenshot.png +0 -0
  335. package/scripts/postversion.js +0 -10
  336. package/scripts/preversion.js +0 -14
  337. package/scripts/version.js +0 -26
  338. package/src/BookNavigator/BookModel.js +0 -14
  339. package/src/BookNavigator/BookNavigator.js +0 -459
  340. package/src/BookNavigator/assets/book-loader.js +0 -27
  341. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  342. package/src/BookNavigator/assets/icon_close.js +0 -3
  343. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  344. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  345. package/src/BookNavigator/assets/icon_sort_neutral.js +0 -5
  346. package/src/BookNavigator/assets/icon_volumes.js +0 -11
  347. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  348. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  349. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  350. package/src/BookNavigator/search/a-search-result.js +0 -55
  351. package/src/BookNavigator/volumes/volumes-provider.js +0 -83
  352. package/src/BookNavigator/volumes/volumes.js +0 -178
  353. package/src/BookReader/DebugConsole.js +0 -54
  354. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  355. package/src/ItemNavigator/ItemNavigator.js +0 -376
  356. package/src/ItemNavigator/providers/sharing.js +0 -33
  357. package/src/css/_MobileNav.scss +0 -194
  358. package/src/dragscrollable-br.js +0 -261
  359. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  360. package/src/plugins/plugin.mobile_nav.js +0 -287
  361. package/tests/BookReader/BookModel.test.js +0 -312
  362. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  363. package/tests/BookReader/DebugConsole.test.js +0 -25
  364. package/tests/BookReader/ImageCache.test.js +0 -150
  365. package/tests/BookReader/Mode1Up.test.js +0 -164
  366. package/tests/BookReader/Mode2Up.test.js +0 -247
  367. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  368. package/tests/BookReader/PageContainer.test.js +0 -115
  369. package/tests/BookReader/ReduceSet.test.js +0 -38
  370. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  371. package/tests/BookReader/utils/classes.test.js +0 -88
  372. package/tests/BookReader/utils.test.js +0 -109
  373. package/tests/BookReader.options.test.js +0 -39
  374. package/tests/BookReader.test.js +0 -301
  375. package/tests/e2e/README.md +0 -75
  376. package/tests/e2e/autoplay.test.js +0 -13
  377. package/tests/e2e/base.test.js +0 -35
  378. package/tests/e2e/helpers/base.js +0 -263
  379. package/tests/e2e/helpers/debug.js +0 -13
  380. package/tests/e2e/helpers/desktopSearch.js +0 -72
  381. package/tests/e2e/helpers/mobileSearch.js +0 -85
  382. package/tests/e2e/helpers/mockSearch.js +0 -93
  383. package/tests/e2e/helpers/rightToLeft.js +0 -29
  384. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  385. package/tests/e2e/models/BookReader.js +0 -11
  386. package/tests/e2e/models/Navigation.js +0 -56
  387. package/tests/e2e/rightToLeft.test.js +0 -20
  388. package/tests/e2e/viewmode.test.js +0 -37
  389. package/tests/karma/BookNavigator/book-navigator.test.js +0 -139
  390. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  391. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  392. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  393. package/tests/karma/BookNavigator/search/search-results.test.js +0 -240
  394. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +0 -40
  395. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  396. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +0 -141
  397. package/tests/karma/BookNavigator/volumes/volumes.test.js +0 -98
  398. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  399. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  400. package/tests/plugins/plugin.autoplay.test.js +0 -52
  401. package/tests/plugins/plugin.chapters.test.js +0 -130
  402. package/tests/plugins/plugin.iframe.test.js +0 -42
  403. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  404. package/tests/plugins/plugin.resume.test.js +0 -98
  405. package/tests/plugins/plugin.text_selection.test.js +0 -203
  406. package/tests/plugins/plugin.url.test.js +0 -129
  407. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  408. package/tests/plugins/search/plugin.search.test.js +0 -173
  409. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  410. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  411. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  412. package/tests/plugins/tts/PageChunk.test.js +0 -57
  413. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  414. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  415. package/tests/plugins/tts/utils.test.js +0 -133
  416. package/tests/util/browserSniffing.test.js +0 -56
  417. package/tests/util/docCookies.test.js +0 -15
  418. package/tests/util/strings.test.js +0 -63
  419. package/tests/utils.js +0 -42
  420. package/webpack.config.js +0 -86
@@ -1,9 +1,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
 
@@ -135,44 +202,44 @@ export class Navbar {
135
202
  * Switch navbar controls on mobile and desktop
136
203
  */
137
204
  switchNavbarControls() {
205
+ // `$root` is null when `showNavbar` is off
206
+ if (!this.$root) return;
138
207
  // we don't want navbar controls switching with liner-notes
139
208
  if (this.br.options.bookType !== 'linerNotes') {
140
209
  if (this.br.refs.$brContainer.prop('clientWidth') < 640) {
141
- this.showMinimumNavbarControls();
210
+ this.showMobileControls();
142
211
  } else {
143
- this.showMaximumNavbarControls();
212
+ this.showDesktopControls();
144
213
  }
145
214
  }
146
215
  }
147
216
 
148
217
  /**
149
- * Switch Book Navbar controls to minimised
150
- * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
218
+ * Switch Book controls to mobile mode
219
+ * NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
151
220
  */
152
- showMinimumNavbarControls() {
221
+ showMobileControls() {
153
222
  this.minimumControls.forEach((control) => {
154
- const element = document.querySelector(`.controls .${control}`);
155
- if (element) element.classList.remove('hide');
223
+ this.$root.find(`.BRnavMain .controls .${control}`).removeClass('hide');
156
224
  });
157
225
  this.maximumControls.forEach((control) => {
158
- const element = document.querySelector(`.controls .${control}`);
159
- if (element) element.classList.add('hide');
226
+ this.$root.find(`.BRnavMain .controls .${control}`).addClass('hide');
160
227
  });
228
+ this.$root.find('.BRnavMobile').removeClass('hide');
161
229
  }
162
230
 
163
231
  /**
164
- * Switch Book Navbar controls to maximized
165
- * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
232
+ * Switch Book controls to desktop mode
233
+ * NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
166
234
  */
167
- showMaximumNavbarControls() {
235
+ showDesktopControls() {
168
236
  this.maximumControls.forEach((control) => {
169
- const element = document.querySelector(`.controls .${control}`);
170
- if (element) element.classList.remove('hide');
237
+ this.$root.find(`.BRnavMain .controls .${control}`).removeClass('hide');
171
238
  });
172
239
  this.minimumControls.forEach((control) => {
173
- const element = document.querySelector(`.controls .${control}`);
174
- if (element) element.classList.add('hide');
240
+ this.$root.find(`.BRnavMain .controls .${control}`).addClass('hide');
175
241
  });
242
+ this.$root.find('.BRnavMobile').addClass('hide');
176
243
  }
177
244
 
178
245
  /**
@@ -191,7 +258,7 @@ export class Navbar {
191
258
 
192
259
  br.refs.$BRfooter = this.$root = $(`<div class="BRfooter"></div>`);
193
260
  br.refs.$BRnav = this.$nav = $(
194
- `<div class="BRnav BRnavDesktop">
261
+ `<div class="BRnav BRnavMobile docked">
195
262
  ${title ? `<div class="BRnavTitle">${title}</div>` : ''}
196
263
  <nav class="BRcontrols">
197
264
  <ul class="controls">
@@ -200,7 +267,24 @@ export class Navbar {
200
267
  <div class="BRpager"></div>
201
268
  <div class="BRnavline"></div>
202
269
  </div>
203
- <p><span class='BRcurrentpage'></span></p>
270
+ </li>
271
+ ${this.controlFor('bookLeft', {visible: true})}
272
+ ${this.controlFor('bookRight', {visible: true})}
273
+ </ul>
274
+ </nav>
275
+ </div>
276
+ <div class="BRnav BRnavMain">
277
+ ${title ? `<div class="BRnavTitle">${title}</div>` : ''}
278
+ <nav class="BRcontrols">
279
+ <ul class="controls">
280
+ <li class="scrubber">
281
+ <p>
282
+ <span class="BRcurrentpage"></span>
283
+ </p>
284
+ <div class="BRnavpos hide">
285
+ <div class="BRpager"></div>
286
+ <div class="BRnavline"></div>
287
+ </div>
204
288
  </li>
205
289
  ${this._renderControls()}
206
290
  </ul>
@@ -210,63 +294,95 @@ export class Navbar {
210
294
  this.$root.append(this.$nav);
211
295
  br.refs.$br.append(this.$root);
212
296
 
213
- const $slider = this.$root.find('.BRpager').slider({
297
+ this.br.on(EVENTS.beforePageChanged, (ev, { ariaLive }) => {
298
+ if (ariaLive) {
299
+ // So screen readers read out change
300
+ this.$root.find('.BRcurrentpage').attr('role', 'status');
301
+ } else {
302
+ this.$root.find('.BRcurrentpage').removeAttr('role');
303
+ }
304
+ });
305
+ this.br.on(EVENTS.pageChanged, (ev, { index }) => this.updateNavIndexThrottled(index));
306
+ br.options.controls.viewmode.visible && this._bindViewModeButton();
307
+ this.updateNavPageNum(br.currentIndex());
308
+
309
+ /** @type {JQuery} sliders */
310
+ const $sliders = this.$root.find('.BRpager').slider({
214
311
  animate: true,
215
312
  min: 0,
216
- max: br.getNumLeafs() - 1,
313
+ max: Math.max(0, br.book.getNumLeafs() - 1),
217
314
  value: br.currentIndex(),
218
- range: "min"
315
+ range: "min",
219
316
  });
220
317
 
221
- $slider.on('slide', (event, ui) => {
222
- this.updateNavPageNum(ui.value);
223
- return true;
318
+ // The jQuery UI slider handles the keyboard shortcuts on the slider's
319
+ // handle, so need the aria labels there.
320
+ $sliders.find('.ui-slider-handle').attr({
321
+ 'role': 'slider',
322
+ 'aria-label': 'Page navigation slider',
323
+ 'aria-valuemin': 0,
324
+ 'aria-valuemax': Math.max(0, br.book.getNumLeafs() - 1),
224
325
  });
225
326
 
226
- $slider.on('slidechange', (event, ui) => {
327
+ // Ignore up/down arrow keys and page up/down keys, since they're confusingly different
328
+ // between slider movement and page movement. Down decreases slider value, which would move
329
+ // the scroll _up_ in 1up.
330
+ $sliders.find('.ui-slider-handle').off('keydown').on('keydown', (event) => {
331
+ switch (event.keyCode || event.which) {
332
+ case $.ui.keyCode.LEFT:
333
+ case $.ui.keyCode.RIGHT:
334
+ // Forward along to the default handler
335
+ if (isRTL) {
336
+ // Swap left/right for RTL
337
+ if (event.keyCode === $.ui.keyCode.LEFT) {
338
+ event.keyCode = $.ui.keyCode.RIGHT;
339
+ } else {
340
+ event.keyCode = $.ui.keyCode.LEFT;
341
+ }
342
+ }
343
+ $.ui.slider.prototype._handleEvents.keydown.call($(event.target).parent().data('ui-slider'), event);
344
+ event.stopPropagation();
345
+ break;
346
+ default:
347
+ return;
348
+ }
349
+ });
350
+
351
+ $sliders.on('slide', (event, ui) => {
352
+ if (this.br.mode === this.br.constMode2up) {
353
+ // in 2up, need to go to nearest page that is left page
354
+ const movingForward = ui.value > br.currentIndex();
355
+ const newPage = this.br.book.getPage(ui.value);
356
+ if (isRTL ? newPage.pageSide === 'L' : newPage.pageSide === 'R') {
357
+ ui.value += movingForward ? 1 : -1;
358
+ ui.value = Math.max(0, Math.min(ui.value, br.book.getNumLeafs() - 1));
359
+ }
360
+ }
227
361
  this.updateNavPageNum(ui.value);
362
+ });
363
+
364
+ $sliders.on('slidechange', (event, ui) => {
228
365
  // recursion prevention for jumpToIndex
229
- if ($slider.data('swallowchange')) {
230
- $slider.data('swallowchange', false);
231
- } else {
232
- br.jumpToIndex(ui.value);
366
+ if ($(event.target).data('swallowchange')) {
367
+ $(event.target).data('swallowchange', false);
368
+ return;
233
369
  }
234
- return true;
235
- });
236
370
 
237
- br.options.controls.viewmode.visible && this._bindViewModeButton();
238
- this.updateNavPageNum(br.currentIndex());
371
+ if (this.br.mode === this.br.constMode2up) {
372
+ // in 2up, need to go to nearest page that is left page
373
+ const movingForward = ui.value > br.currentIndex();
374
+ const newPage = this.br.book.getPage(ui.value);
375
+ if (isRTL ? newPage.pageSide === 'L' : newPage.pageSide === 'R') {
376
+ ui.value += movingForward ? 1 : -1;
377
+ ui.value = Math.max(0, Math.min(ui.value, br.book.getNumLeafs() - 1));
378
+ }
379
+ }
239
380
 
240
- return this.$nav;
241
- }
381
+ // Don't want this to be aria-live since the slider already announces the value
382
+ this.br.jumpToIndex(ui.value, {ariaLive: false});
383
+ });
242
384
 
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);
385
+ return this.$nav;
270
386
  }
271
387
 
272
388
  /**
@@ -276,17 +392,16 @@ export class Navbar {
276
392
  */
277
393
  getNavPageNumString(index) {
278
394
  const { br } = this;
279
- // 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();
395
+ const pageNum = br.book.getPageNum(index);
396
+ const pageType = br.book.getPageProp(index, 'pageType');
397
+ const numLeafs = br.book.getNumLeafs();
283
398
 
284
399
  if (!this.maxPageNum) {
285
400
  // Calculate Max page num (used for pagination display)
286
401
  let maxPageNum = 0;
287
402
  let pageNumVal;
288
403
  for (let i = 0; i < numLeafs; i++) {
289
- pageNumVal = br.getPageNum(i);
404
+ pageNumVal = parseFloat(br.book.getPageNum(i));
290
405
  if (!isNaN(pageNumVal) && pageNumVal > maxPageNum) {
291
406
  maxPageNum = pageNumVal;
292
407
  }
@@ -295,6 +410,7 @@ export class Navbar {
295
410
  }
296
411
 
297
412
  return getNavPageNumHtml(index, numLeafs, pageNum, pageType, this.maxPageNum);
413
+
298
414
  }
299
415
 
300
416
  /**
@@ -303,6 +419,10 @@ export class Navbar {
303
419
  */
304
420
  updateNavPageNum(index) {
305
421
  this.$root.find('.BRcurrentpage').html(this.getNavPageNumString(index));
422
+ this.$root.find('.ui-slider-handle').attr({
423
+ 'aria-valuenow': index,
424
+ 'aria-valuetext': this.getNavPageNumString(index),
425
+ });
306
426
  }
307
427
 
308
428
  /**
@@ -313,27 +433,27 @@ export class Navbar {
313
433
  // We want to update the value, but normally moving the slider
314
434
  // triggers jumpToIndex which triggers this method
315
435
  index = index !== undefined ? index : this.br.currentIndex();
316
- this.$root.find('.BRpager').data('swallowchange', true).slider('value', index);
436
+ this.$root.find('.BRpager').data('swallowchange', true);
437
+ this.$root.find('.BRpager').slider('value', index);
438
+ this.updateNavPageNum(index);
317
439
  }
318
440
  }
319
441
 
320
442
  /**
321
443
  * Renders the html for the page string
322
- * @param {number} index
323
- * @param {number} numLeafs
444
+ * @param {PageIndex} index 0-indexed page index (0..numLeafs-1)
445
+ * @param {number} numLeafs total number of leaves
324
446
  * @param {number|string} pageNum
325
- * @param {*} pageType @deprecated
447
+ * @param {*} pageType - Deprecated
326
448
  * @param {number} maxPageNum
327
- * @return {string}
449
+ * @return {string} e.g. "Page 14 (3/39)"
328
450
  */
329
451
  export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum) {
330
452
  const pageIsAsserted = pageNum[0] != 'n';
331
453
 
332
454
  if (!pageIsAsserted) {
333
- const pageIndex = index + 1;
334
- return `(${pageIndex} of ${numLeafs})`; // Page (8 of 10)
455
+ pageNum = '—';
335
456
  }
336
-
337
- const bookLengthLabel = maxPageNum ? ` of ${maxPageNum}` : '';
338
- return `${pageNum}${bookLengthLabel}`;
457
+ const lastIndex = Math.max(0, numLeafs - 1);
458
+ return `Page ${pageNum} (${index}/${lastIndex})`;
339
459
  }
@@ -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 = {