@internetarchive/bookreader 5.0.0-11-multiple-files → 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 (389) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +616 -1467
  4. package/BookReader/BookReader.js +2 -21564
  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 -12
  56. package/BookReader/icons/2up.svg +1 -15
  57. package/BookReader/icons/advance.svg +3 -26
  58. package/BookReader/icons/chevron-right.svg +1 -1
  59. package/BookReader/icons/close-circle-dark.svg +1 -0
  60. package/BookReader/icons/close-circle.svg +1 -1
  61. package/BookReader/icons/fullscreen.svg +1 -17
  62. package/BookReader/icons/fullscreen_exit.svg +1 -17
  63. package/BookReader/icons/hamburger.svg +1 -15
  64. package/BookReader/icons/left-arrow.svg +1 -12
  65. package/BookReader/icons/magnify-minus.svg +1 -16
  66. package/BookReader/icons/magnify-plus.svg +1 -17
  67. package/BookReader/icons/magnify.svg +1 -15
  68. package/BookReader/icons/pause.svg +1 -23
  69. package/BookReader/icons/play.svg +1 -22
  70. package/BookReader/icons/playback-speed.svg +1 -34
  71. package/BookReader/icons/read-aloud.svg +1 -22
  72. package/BookReader/icons/review.svg +3 -22
  73. package/BookReader/icons/slider-toggle.svg +1 -0
  74. package/BookReader/icons/thumbnails.svg +1 -17
  75. package/BookReader/icons/voice.svg +1 -0
  76. package/BookReader/icons/volume-full.svg +1 -22
  77. package/BookReader/images/BRicons.svg +5 -94
  78. package/BookReader/images/books_graphic.svg +1 -177
  79. package/BookReader/images/hypothesis.ico +0 -0
  80. package/BookReader/images/icon_book.svg +1 -12
  81. package/BookReader/images/icon_bookmark.svg +1 -12
  82. package/BookReader/images/icon_experiment.svg +1 -0
  83. package/BookReader/images/icon_gear.svg +1 -14
  84. package/BookReader/images/icon_hamburger.svg +1 -20
  85. package/BookReader/images/icon_home.svg +1 -21
  86. package/BookReader/images/icon_info.svg +1 -11
  87. package/BookReader/images/icon_one_page.svg +1 -8
  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 -15
  91. package/BookReader/images/icon_search_button.svg +1 -8
  92. package/BookReader/images/icon_share.svg +1 -9
  93. package/BookReader/images/icon_skip-ahead.svg +1 -6
  94. package/BookReader/images/icon_skip-back.svg +2 -13
  95. package/BookReader/images/icon_speaker.svg +1 -18
  96. package/BookReader/images/icon_speaker_open.svg +1 -10
  97. package/BookReader/images/icon_thumbnails.svg +1 -12
  98. package/BookReader/images/icon_toc.svg +1 -5
  99. package/BookReader/images/icon_two_pages.svg +1 -9
  100. package/BookReader/images/marker_chap-off.svg +1 -11
  101. package/BookReader/images/marker_chap-on.svg +1 -11
  102. package/BookReader/images/marker_srch-on.svg +1 -11
  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 -172
  108. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js +1 -165
  110. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  111. package/BookReader/plugins/plugin.chapters.js +19 -301
  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 -74
  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 -368
  122. package/BookReader/plugins/plugin.resume.js.map +1 -1
  123. package/BookReader/plugins/plugin.search.js +2 -1420
  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 -1080
  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 +2 -9193
  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 -269
  136. package/BookReader/plugins/plugin.url.js.map +1 -1
  137. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  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 -356
  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 +30 -16
  160. package/src/BookReader/Navbar/Navbar.js +201 -76
  161. package/src/BookReader/PageContainer.js +120 -23
  162. package/src/BookReader/ReduceSet.js +3 -3
  163. package/src/BookReader/Toolbar/Toolbar.js +19 -41
  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 +141 -13
  171. package/src/BookReader.js +711 -1241
  172. package/src/BookReaderPlugin.js +52 -0
  173. package/src/assets/icons/close-circle-dark.svg +1 -0
  174. package/src/assets/icons/magnify-minus.svg +3 -7
  175. package/src/assets/icons/magnify-plus.svg +3 -7
  176. package/src/assets/icons/slider-toggle.svg +1 -0
  177. package/src/assets/icons/voice.svg +1 -0
  178. package/src/assets/images/hypothesis.ico +0 -0
  179. package/src/assets/images/icon_experiment.svg +1 -0
  180. package/src/assets/images/translate.svg +1 -0
  181. package/src/assets/images/unviewable_page.png +0 -0
  182. package/src/assets/silence.mp3 +0 -0
  183. package/src/css/BookReader.scss +1 -17
  184. package/src/css/_BRBookmarks.scss +1 -1
  185. package/src/css/_BRComponent.scss +1 -1
  186. package/src/css/_BRicon.scss +8 -2
  187. package/src/css/_BRmain.scss +33 -27
  188. package/src/css/_BRnav.scss +74 -70
  189. package/src/css/_BRpages.scss +171 -42
  190. package/src/css/_BRsearch.scss +69 -235
  191. package/src/css/_BRtoolbar.scss +5 -5
  192. package/src/css/_TextSelection.scss +129 -24
  193. package/src/css/_colorbox.scss +2 -2
  194. package/src/css/_controls.scss +24 -7
  195. package/src/css/_icons.scss +14 -1
  196. package/src/{BookNavigator/assets → css}/button-base.js +10 -3
  197. package/src/css/icon_checkmark.js +9 -0
  198. package/src/css/sharedStyles.js +15 -0
  199. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  200. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +29 -25
  201. package/src/ia-bookreader/ia-bookreader.js +666 -0
  202. package/src/ia-bookreader/sharing.js +27 -0
  203. package/src/ia-bookreader/viewable-files.js +98 -0
  204. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  205. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  206. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  207. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  208. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +44 -32
  209. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  210. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +5 -10
  211. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  212. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  213. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  214. package/src/plugins/plugin.archive_analytics.js +84 -78
  215. package/src/plugins/plugin.autoplay.js +99 -104
  216. package/src/plugins/plugin.chapters.js +310 -201
  217. package/src/plugins/plugin.experiments.js +321 -0
  218. package/src/plugins/plugin.iframe.js +1 -1
  219. package/src/plugins/plugin.iiif.js +141 -0
  220. package/src/plugins/plugin.resume.js +53 -50
  221. package/src/plugins/plugin.text_selection.js +522 -219
  222. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  223. package/src/plugins/search/plugin.search.js +380 -360
  224. package/src/{BookNavigator → plugins}/search/search-provider.js +94 -32
  225. package/src/{BookNavigator → plugins}/search/search-results.js +108 -90
  226. package/src/plugins/search/utils.js +50 -0
  227. package/src/plugins/search/view.js +79 -210
  228. package/src/plugins/translate/TranslationManager.js +164 -0
  229. package/src/plugins/translate/plugin.translate.js +512 -0
  230. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  231. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  232. package/src/plugins/tts/PageChunk.js +33 -21
  233. package/src/plugins/tts/PageChunkIterator.js +11 -17
  234. package/src/plugins/tts/WebTTSEngine.js +131 -91
  235. package/src/plugins/tts/plugin.tts.js +345 -350
  236. package/src/plugins/tts/utils.js +77 -49
  237. package/src/plugins/url/UrlPlugin.js +191 -0
  238. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  239. package/src/util/TextSelectionManager.js +282 -0
  240. package/src/util/browserSniffing.js +33 -1
  241. package/src/util/cache.js +20 -0
  242. package/src/util/docCookies.js +21 -2
  243. package/src/util/lit.js +15 -0
  244. package/src/util/strings.js +1 -0
  245. package/.babelrc +0 -12
  246. package/.dependabot/config.yml +0 -6
  247. package/.eslintrc.js +0 -49
  248. package/.gitattributes +0 -2
  249. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  250. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  251. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  252. package/.github/workflows/node.js.yml +0 -28
  253. package/.github/workflows/npm-publish.yml +0 -47
  254. package/.testcaferc.json +0 -5
  255. package/BookReader/bookreader-component-bundle.js +0 -14330
  256. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  257. package/BookReader/bookreader-component-bundle.js.map +0 -1
  258. package/BookReader/icons/sort-ascending.svg +0 -1
  259. package/BookReader/icons/sort-descending.svg +0 -1
  260. package/BookReader/jquery-1.10.1.js +0 -108
  261. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  262. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  263. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  264. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  265. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  266. package/BookReaderDemo/BookReaderDemo.css +0 -41
  267. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  268. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  269. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  270. package/BookReaderDemo/IIIFBookReader.js +0 -207
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  273. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  274. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  275. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  276. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  277. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  278. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  279. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  280. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  281. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  282. package/BookReaderDemo/demo-advanced.html +0 -33
  283. package/BookReaderDemo/demo-autoplay.html +0 -38
  284. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  285. package/BookReaderDemo/demo-embed.html +0 -26
  286. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  287. package/BookReaderDemo/demo-fullscreen.html +0 -33
  288. package/BookReaderDemo/demo-iiif.html +0 -34
  289. package/BookReaderDemo/demo-iiif.js +0 -26
  290. package/BookReaderDemo/demo-internetarchive.html +0 -74
  291. package/BookReaderDemo/demo-multiple.html +0 -43
  292. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  293. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  294. package/BookReaderDemo/demo-simple.html +0 -34
  295. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  296. package/BookReaderDemo/immersion-1up.html +0 -64
  297. package/BookReaderDemo/immersion-mode.html +0 -35
  298. package/BookReaderDemo/toggle_controls.html +0 -53
  299. package/BookReaderDemo/view_mode.html +0 -39
  300. package/BookReaderDemo/viewmode-cycle.html +0 -41
  301. package/CHANGELOG.md +0 -476
  302. package/CONTRIBUTING.md +0 -7
  303. package/codecov.yml +0 -17
  304. package/index.html +0 -31
  305. package/karma.conf.js +0 -23
  306. package/screenshot.png +0 -0
  307. package/scripts/postversion.js +0 -10
  308. package/scripts/preversion.js +0 -14
  309. package/scripts/version.js +0 -26
  310. package/src/BookNavigator/BookModel.js +0 -14
  311. package/src/BookNavigator/BookNavigator.js +0 -451
  312. package/src/BookNavigator/assets/book-loader.js +0 -27
  313. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  314. package/src/BookNavigator/assets/icon_close.js +0 -3
  315. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  316. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  317. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  318. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  319. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  320. package/src/BookNavigator/search/a-search-result.js +0 -55
  321. package/src/BookNavigator/volumes/volumes-provider.js +0 -75
  322. package/src/BookNavigator/volumes/volumes.js +0 -161
  323. package/src/BookReader/DebugConsole.js +0 -54
  324. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  325. package/src/ItemNavigator/ItemNavigator.js +0 -372
  326. package/src/ItemNavigator/providers/sharing.js +0 -29
  327. package/src/assets/icons/sort-ascending.svg +0 -1
  328. package/src/assets/icons/sort-descending.svg +0 -1
  329. package/src/css/_MobileNav.scss +0 -194
  330. package/src/dragscrollable-br.js +0 -261
  331. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  332. package/src/plugins/plugin.mobile_nav.js +0 -287
  333. package/tests/BookReader/BookModel.test.js +0 -312
  334. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  335. package/tests/BookReader/DebugConsole.test.js +0 -25
  336. package/tests/BookReader/ImageCache.test.js +0 -150
  337. package/tests/BookReader/Mode1Up.test.js +0 -164
  338. package/tests/BookReader/Mode2Up.test.js +0 -247
  339. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  340. package/tests/BookReader/PageContainer.test.js +0 -115
  341. package/tests/BookReader/ReduceSet.test.js +0 -38
  342. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  343. package/tests/BookReader/utils/classes.test.js +0 -88
  344. package/tests/BookReader/utils.test.js +0 -109
  345. package/tests/BookReader.options.test.js +0 -39
  346. package/tests/BookReader.test.js +0 -301
  347. package/tests/e2e/README.md +0 -75
  348. package/tests/e2e/autoplay.test.js +0 -13
  349. package/tests/e2e/base.test.js +0 -35
  350. package/tests/e2e/helpers/base.js +0 -258
  351. package/tests/e2e/helpers/debug.js +0 -13
  352. package/tests/e2e/helpers/desktopSearch.js +0 -72
  353. package/tests/e2e/helpers/mobileSearch.js +0 -85
  354. package/tests/e2e/helpers/mockSearch.js +0 -93
  355. package/tests/e2e/helpers/rightToLeft.js +0 -29
  356. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  357. package/tests/e2e/models/BookReader.js +0 -11
  358. package/tests/e2e/models/Navigation.js +0 -56
  359. package/tests/e2e/rightToLeft.test.js +0 -20
  360. package/tests/e2e/viewmode.test.js +0 -37
  361. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  362. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  363. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  364. package/tests/karma/BookNavigator/search-results.test.js +0 -240
  365. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  366. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  367. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  368. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  369. package/tests/plugins/plugin.autoplay.test.js +0 -52
  370. package/tests/plugins/plugin.chapters.test.js +0 -130
  371. package/tests/plugins/plugin.iframe.test.js +0 -42
  372. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  373. package/tests/plugins/plugin.resume.test.js +0 -98
  374. package/tests/plugins/plugin.text_selection.test.js +0 -203
  375. package/tests/plugins/plugin.url.test.js +0 -129
  376. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  377. package/tests/plugins/search/plugin.search.test.js +0 -166
  378. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  379. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  380. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  381. package/tests/plugins/tts/PageChunk.test.js +0 -57
  382. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  383. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  384. package/tests/plugins/tts/utils.test.js +0 -133
  385. package/tests/util/browserSniffing.test.js +0 -56
  386. package/tests/util/docCookies.test.js +0 -15
  387. package/tests/util/strings.test.js +0 -63
  388. package/tests/utils.js +0 -42
  389. package/webpack.config.js +0 -86
@@ -1,392 +1,387 @@
1
- /* global BookReader */
2
- /**
3
- * Plugin for Text to Speech in BookReader
4
- */
1
+ // @ts-check
2
+
5
3
  import FestivalTTSEngine from './FestivalTTSEngine.js';
6
4
  import WebTTSEngine from './WebTTSEngine.js';
7
5
  import { toISO6391, approximateWordCount } from './utils.js';
8
6
  import { en as tooltips } from './tooltip_dict.js';
9
- /** @typedef {import('./PageChunk.js')} PageChunk */
10
- /** @typedef {import("./AbstractTTSEngine.js")} AbstractTTSEngine */
11
-
12
- // Default options for TTS
13
- jQuery.extend(BookReader.defaultOptions, {
14
- server: 'ia600609.us.archive.org',
15
- bookPath: '',
16
- enableTtsPlugin: true,
17
- });
18
-
19
- // Extend the constructor to add TTS properties
20
- BookReader.prototype.setup = (function (super_) {
21
- return function (options) {
22
- super_.call(this, options);
23
-
24
- if (this.options.enableTtsPlugin) {
25
- this.ttsHilites = [];
26
- let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :
27
- FestivalTTSEngine.isSupported() ? FestivalTTSEngine :
28
- null;
29
-
30
- if (/_forceTTSEngine=(festival|web)/.test(location.toString())) {
31
- const engineName = location.toString().match(/_forceTTSEngine=(festival|web)/)[1];
32
- TTSEngine = { festival: FestivalTTSEngine, web: WebTTSEngine }[engineName];
33
- }
7
+ import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
8
+ import { BookReaderPlugin } from '../../BookReaderPlugin.js';
9
+ import { applyVariables } from '../../util/strings.js';
10
+ /** @typedef {import('./PageChunk.js').default} PageChunk */
11
+ /** @typedef {import("./AbstractTTSEngine.js").default} AbstractTTSEngine */
34
12
 
35
- if (TTSEngine) {
36
- /** @type {AbstractTTSEngine} */
37
- this.ttsEngine = new TTSEngine({
38
- server: options.server,
39
- bookPath: options.bookPath,
40
- bookLanguage: toISO6391(options.bookLanguage),
41
- onLoadingStart: this.showProgressPopup.bind(this, 'Loading audio...'),
42
- onLoadingComplete: this.removeProgressPopup.bind(this),
43
- onDone: this.ttsStop.bind(this),
44
- beforeChunkPlay: this.ttsBeforeChunkPlay.bind(this),
45
- afterChunkPlay: this.ttsSendChunkFinishedAnalyticsEvent.bind(this),
46
- });
47
- }
13
+ const BookReader = /** @type {typeof import('../../BookReader').default} */(window.BookReader);
14
+
15
+ /**
16
+ * Plugin for Text to Speech in BookReader
17
+ */
18
+ export class TtsPlugin extends BookReaderPlugin {
19
+ options = {
20
+ enabled: true,
21
+ /**
22
+ * @type {import('@/src/util/strings.js').StringWithVars}
23
+ * The URL where to get PageChunk objects for a given page. Expects a var `pageIndex`
24
+ **/
25
+ pageChunkUrl: 'https://{{server}}/BookReader/BookReaderGetTextWrapper.php?path={{bookPath|urlencode}}_djvu.xml&page={{pageIndex}}&callback=false',
26
+ /**
27
+ * @type {import('@/src/util/strings.js').StringWithVars}
28
+ * The URL for converting text to audio if the web SpeechSynthesis API is not supported.
29
+ * Provided variables:
30
+ * - `text` -- the text to convert to audio
31
+ * - `format` -- the format of the audio, 'mp3' or 'ogg';
32
+ */
33
+ remoteTtsUrl: 'https://{{server}}/BookReader/BookReaderGetTTS.php?string={{text|urlencode}}&format={{format}}',
34
+ }
35
+
36
+ /**
37
+ * @override
38
+ * @param {Partial<TtsPlugin['options']>} options
39
+ **/
40
+ setup(options) {
41
+ super.setup(Object.assign({
42
+ // @deprecated support options specified in global options
43
+ server: this.br.options.server,
44
+ bookPath: this.br.options.bookPath,
45
+ }, options));
46
+
47
+ if (!this.options.enabled) return;
48
+
49
+ /** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */
50
+ this._ttsBoxesByIndex = {};
51
+
52
+ let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :
53
+ FestivalTTSEngine.isSupported() ? FestivalTTSEngine :
54
+ null;
55
+
56
+ if (/_forceTTSEngine=(festival|web)/.test(location.toString())) {
57
+ const engineName = location.toString().match(/_forceTTSEngine=(festival|web)/)[1];
58
+ TTSEngine = { festival: FestivalTTSEngine, web: WebTTSEngine }[engineName];
48
59
  }
49
- };
50
- })(BookReader.prototype.setup);
51
-
52
- BookReader.prototype.init = (function(super_) {
53
- return function() {
54
- if (this.options.enableTtsPlugin) {
55
- // Bind to events
56
-
57
- // TODO move this to BookReader.js or something
58
- this.bind(BookReader.eventNames.fragmentChange, () => {
59
- if (this.mode == this.constMode2up) {
60
- // clear highlights if they're no longer valid for this page
61
- const visibleIndices = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
62
- const visibleSelector = visibleIndices.map(i => `.BRReadAloudHilite.Leaf-${i}`).join(', ');
63
- $(this.ttsHilites).filter(visibleSelector).show();
64
- $(this.ttsHilites).not(visibleSelector).hide();
65
- }
60
+
61
+ if (TTSEngine) {
62
+ /** @type {AbstractTTSEngine} */
63
+ this.ttsEngine = new TTSEngine({
64
+ pageChunkUrl: applyVariables(this.options.pageChunkUrl, this.br.options.vars),
65
+ bookLanguage: toISO6391(this.br.options.bookLanguage),
66
+ onLoadingStart: this.br.showProgressPopup.bind(this.br, 'Loading audio...'),
67
+ onLoadingComplete: this.br.removeProgressPopup.bind(this.br),
68
+ onDone: this.stop.bind(this),
69
+ beforeChunkPlay: this.beforeChunkPlay.bind(this),
70
+ afterChunkPlay: this.sendChunkFinishedAnalyticsEvent.bind(this),
71
+ ...(TTSEngine === FestivalTTSEngine ? {
72
+ festivalUrl: applyVariables(this.options.remoteTtsUrl, this.br.options.vars),
73
+ } : {}),
66
74
  });
75
+ }
76
+ }
67
77
 
68
- this.bind(BookReader.eventNames.PostInit, () => {
69
- this.$('.BRicon.read').click(() => {
70
- this.ttsToggle();
71
- return false;
72
- });
73
- if (this.ttsEngine) {
74
- this.ttsEngine.init();
75
- if (/[?&]_autoReadAloud=show/.test(location.toString())) {
76
- this.ttsStart(false); // false flag is to initiate read aloud controls
77
- }
78
- }
78
+ /** @override */
79
+ init() {
80
+ if (!this.options.enabled) return;
81
+
82
+ this.br.bind(BookReader.eventNames.PostInit, () => {
83
+ this.br.$('.BRicon.read').click(() => {
84
+ this.toggle();
85
+ return false;
79
86
  });
87
+ if (this.ttsEngine) {
88
+ this.ttsEngine.init();
89
+ if (/[?&]_autoReadAloud=show/.test(location.toString())) {
90
+ this.start(false); // false flag is to initiate read aloud controls
91
+ }
92
+ }
93
+ });
94
+
95
+ // This is fired when the hash changes by one of the other plugins!
96
+ // i.e. it will fire every time the page changes -_-
97
+ // this.br.bind(BookReader.eventNames.stop, function(e, br) {
98
+ // this.ttsStop();
99
+ // }.bind(this));
100
+ }
80
101
 
81
- // This is fired when the hash changes by one of the other plugins!
82
- // i.e. it will fire every time the page changes -_-
83
- // this.bind(BookReader.eventNames.stop, function(e, br) {
84
- // this.ttsStop();
85
- // }.bind(this));
102
+ /**
103
+ * @override
104
+ * @param {import ("@/src/BookReader/PageContainer.js").PageContainer} pageContainer
105
+ */
106
+ _configurePageContainer(pageContainer) {
107
+ if (this.options.enabled && pageContainer.page && pageContainer.page.index in this._ttsBoxesByIndex) {
108
+ const pageIndex = pageContainer.page.index;
109
+ renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);
86
110
  }
87
- super_.call(this);
88
- };
89
- })(BookReader.prototype.init);
111
+ }
90
112
 
113
+ /**
114
+ * @override
115
+ * @param {JQuery<HTMLElement>} $navBar
116
+ */
117
+ extendNavBar($navBar) {
118
+ if (!this.options.enabled || !this.ttsEngine) return;
91
119
 
92
- // Extend buildMobileDrawerElement
93
- BookReader.prototype.buildMobileDrawerElement = (function (super_) {
94
- return function () {
95
- const $el = super_.call(this);
96
- if (this.options.enableTtsPlugin && this.ttsEngine) {
97
- $el.find('.BRmobileMenu__moreInfoRow').after($(`
120
+ this.br.refs.$BRReadAloudToolbar = $(`
121
+ <ul class="read-aloud">
98
122
  <li>
99
- <span>
100
- <span class="DrawerIconWrapper"><img class="DrawerIcon" src="${this.imagesBaseURL}icon_speaker_open.svg" alt="info-speaker"/></span>
101
- Read Aloud
102
- </span>
103
- <div>
104
- <span class="larger">Press to toggle read aloud</span>
105
- <br/>
106
- <button class="BRicon read"></button>
107
- </div>
108
- </li>`));
109
- }
110
- return $el;
111
- };
112
- })(BookReader.prototype.buildMobileDrawerElement);
113
-
114
- // Extend initNavbar
115
- BookReader.prototype.initNavbar = (function (super_) {
116
- return function () {
117
- const $el = super_.call(this);
118
- if (this.options.enableTtsPlugin && this.ttsEngine) {
119
- this.refs.$BRReadAloudToolbar = $(`
120
- <ul class="read-aloud">
121
- <li>
122
- <select class="playback-speed" name="playback-speed" title="${tooltips.playbackSpeed}">
123
- <option value="0.25">0.25x</option>
124
- <option value="0.5">0.5x</option>
125
- <option value="0.75">0.75x</option>
126
- <option value="1.0" selected>1.0x</option>
127
- <option value="1.25">1.25x</option>
128
- <option value="1.5">1.5x</option>
129
- <option value="1.75">1.75x</option>
130
- <option value="2">2x</option>
131
- </select>
132
- </li>
133
- <li>
134
- <button type="button" name="review" title="${tooltips.review}">
135
- <div class="icon icon-review"></div>
136
- </button>
137
- </li>
138
- <li>
139
- <button type="button" name="play" title="${tooltips.play}">
140
- <div class="icon icon-play"></div>
141
- <div class="icon icon-pause"></div>
142
- </button>
143
- </li>
144
- <li>
145
- <button type="button" name="advance" title="${tooltips.advance}">
146
- <div class="icon icon-advance"></div>
147
- </button>
148
- </li>
149
- </ul>
150
- `);
151
- $el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);
152
- this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());
153
- this.refs.$BRReadAloudToolbar.find('[name=play]').click(this.ttsPlayPause.bind(this));
154
- this.refs.$BRReadAloudToolbar.find('[name=advance]').click(this.ttsJumpForward.bind(this));
155
- this.refs.$BRReadAloudToolbar.find('[name=review]').click(this.ttsJumpBackward.bind(this));
156
- const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name="playback-speed"]');
157
- $rateSelector.change(ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));
158
- $(`<li>
159
- <button class="BRicon read js-tooltip" title="${tooltips.readAloud}">
160
- <div class="icon icon-read-aloud"></div>
161
- <span class="tooltip">${tooltips.readAloud}</span>
123
+ <select class="playback-speed" name="playback-speed" title="${tooltips.playbackSpeed}">
124
+ <option value="0.25">0.25x</option>
125
+ <option value="0.5">0.5x</option>
126
+ <option value="0.75">0.75x</option>
127
+ <option value="1.0" selected>1.0x</option>
128
+ <option value="1.25">1.25x</option>
129
+ <option value="1.5">1.5x</option>
130
+ <option value="1.75">1.75x</option>
131
+ <option value="2">2x</option>
132
+ </select>
133
+ </li>
134
+ <li>
135
+ <button type="button" name="review" title="${tooltips.review}">
136
+ <div class="icon icon-review"></div>
162
137
  </button>
163
- </li>`).insertBefore($el.find('.BRcontrols .BRicon.zoom_out').closest('li'));
164
- }
165
- return $el;
166
- };
167
- })(BookReader.prototype.initNavbar);
168
-
169
- // ttsToggle()
170
- //______________________________________________________________________________
171
- BookReader.prototype.ttsToggle = function () {
172
- if (this.autoStop) this.autoStop();
173
- if (this.ttsEngine.playing) {
174
- this.ttsStop();
175
- } else {
176
- this.ttsStart();
138
+ </li>
139
+ <li>
140
+ <button type="button" name="play" title="${tooltips.play}">
141
+ <div class="icon icon-play"></div>
142
+ <div class="icon icon-pause"></div>
143
+ </button>
144
+ </li>
145
+ <li>
146
+ <button type="button" name="advance" title="${tooltips.advance}">
147
+ <div class="icon icon-advance"></div>
148
+ </button>
149
+ </li>
150
+ <li>
151
+ <select class="playback-voices" name="playback-voice" style="display: none" title="Change read aloud voices">
152
+ </select>
153
+ </li>
154
+ </ul>
155
+ `);
156
+
157
+ $navBar.find('.BRcontrols').prepend(this.br.refs.$BRReadAloudToolbar);
158
+
159
+ const renderVoiceOption = (voices) => {
160
+ return voices.map(voice =>
161
+ `<option value="${voice.voiceURI}">${voice.lang} - ${voice.name}</option>`).join('');
162
+ };
163
+
164
+ const voiceSortOrder = (a,b) => `${a.lang} - ${a.name}`.localeCompare(`${b.lang} - ${b.name}`);
165
+
166
+ const renderVoicesMenu = (voicesMenu) => {
167
+ voicesMenu.empty();
168
+ let bookLanguage = this.ttsEngine.opts.bookLanguage;
169
+ if (this.br.plugins.translate?.translationManager?.active) {
170
+ bookLanguage = this.br.plugins.translate.langFromCode;
171
+ }
172
+
173
+ const bookLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
174
+ const otherLanguages = this.ttsEngine.getVoices().filter(v => !v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
175
+
176
+ if (this.ttsEngine.getVoices().length > 1) {
177
+ if (this.br.plugins.translate?.translationManager?.active) {
178
+ // Separate out Other Languages when translation active, not sure if too much / unwieldy
179
+ const toLang = this.br.plugins.translate.langToCode;
180
+ const translatedLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(toLang)).sort(voiceSortOrder);
181
+ voicesMenu.append($(`<optgroup label="Book Language, Translated From (${bookLanguage})"> ${renderVoiceOption(bookLanguages)} </optgroup>`));
182
+ voicesMenu.append($(`<optgroup label="Book Language, Translated To (${toLang})"> ${renderVoiceOption(translatedLanguages)} </optgroup>`));
183
+ voicesMenu.append($(`<optgroup label="Other Languages"> ${renderVoiceOption(otherLanguages.filter(v => !v.lang.startsWith(toLang)).sort(voiceSortOrder))}`));
184
+ } else {
185
+ voicesMenu.append($(`<optgroup label="Book Language (${bookLanguage})"> ${renderVoiceOption(bookLanguages)} </optgroup>`));
186
+ voicesMenu.append($(`<optgroup label="Other Languages"> ${renderVoiceOption(otherLanguages)} </optgroup>`));
187
+ }
188
+
189
+ voicesMenu.val(this.ttsEngine.voice.voiceURI);
190
+ voicesMenu.show();
191
+ } else {
192
+ voicesMenu.hide();
193
+ }
194
+ };
195
+
196
+ const voicesMenu = this.br.refs.$BRReadAloudToolbar.find('[name=playback-voice]');
197
+ renderVoicesMenu(voicesMenu);
198
+ voicesMenu.on("change", ev => this.ttsEngine.setVoice(voicesMenu.val()));
199
+ this.ttsEngine.events.on('pause resume start', () => this.updateState());
200
+ this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));
201
+ this.br.on('translationEnabled', () => renderVoicesMenu(voicesMenu));
202
+ this.br.on('translationDisabled', () => renderVoicesMenu(voicesMenu));
203
+ this.br.refs.$BRReadAloudToolbar.find('[name=play]').on("click", this.playPause.bind(this));
204
+ this.br.refs.$BRReadAloudToolbar.find('[name=advance]').on("click", this.jumpForward.bind(this));
205
+ this.br.refs.$BRReadAloudToolbar.find('[name=review]').on("click", this.jumpBackward.bind(this));
206
+ const $rateSelector = this.br.refs.$BRReadAloudToolbar.find('select[name="playback-speed"]');
207
+ $rateSelector.on("change", ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));
208
+ $(`<li>
209
+ <button class="BRicon read js-tooltip" title="${tooltips.readAloud}">
210
+ <div class="icon icon-read-aloud"></div>
211
+ <span class="BRtooltip">${tooltips.readAloud}</span>
212
+ </button>
213
+ </li>`).insertBefore($navBar.find('.BRcontrols .BRicon.zoom_out').closest('li'));
177
214
  }
178
- };
179
-
180
- // ttsStart(
181
- //______________________________________________________________________________
182
- BookReader.prototype.ttsStart = function (startTTSEngine = true) {
183
- if (this.constModeThumb == this.mode)
184
- this.switchMode(this.constMode1up);
185
-
186
- this.refs.$BRReadAloudToolbar.addClass('visible');
187
- this.$('.BRicon.read').addClass('unread active');
188
- this.ttsSendAnalyticsEvent('Start');
189
- if (startTTSEngine)
190
- this.ttsEngine.start(this.currentIndex(), this.getNumLeafs());
191
- };
192
-
193
- BookReader.prototype.ttsJumpForward = function () {
194
- if (this.ttsEngine.paused) {
195
- this.ttsEngine.resume();
215
+
216
+ toggle() {
217
+ this.br.plugins.autoplay?.stop();
218
+ if (this.ttsEngine.playing) {
219
+ this.stop();
220
+ } else {
221
+ this.start();
222
+ }
196
223
  }
197
- this.ttsEngine.jumpForward();
198
- };
199
224
 
200
- BookReader.prototype.ttsJumpBackward = function () {
201
- if (this.ttsEngine.paused) {
202
- this.ttsEngine.resume();
225
+ start(startTTSEngine = true) {
226
+ const checkVoice = this.br.plugins.translate?.translationManager?.active ? toISO6391(this.br.plugins.translate.langToCode) : "";
227
+ const bookVoice = this.ttsEngine.getBestVoice(checkVoice);
228
+
229
+ const voicesMenu = this.br.refs.$BRReadAloudToolbar.find('[name=playback-voice');
230
+ this.ttsEngine.setVoice(bookVoice.voiceURI);
231
+ voicesMenu.val(bookVoice.voiceURI);
232
+ if (this.br.constModeThumb == this.br.mode)
233
+ this.br.switchMode(this.br.constMode1up);
234
+
235
+ this.br.refs.$BRReadAloudToolbar.addClass('visible');
236
+ this.br.$('.BRicon.read').addClass('unread active');
237
+ this.sendAnalyticsEvent('Start');
238
+ if (startTTSEngine)
239
+ this.ttsEngine.start(this.br.currentIndex(), this.br.book.getNumLeafs());
203
240
  }
204
- this.ttsEngine.jumpBackward();
205
- };
206
-
207
- BookReader.prototype.ttsUpdateState = function() {
208
- const isPlaying = !(this.ttsEngine.paused || !this.ttsEngine.playing);
209
- this.$('.read-aloud [name=play]').toggleClass('playing', isPlaying);
210
- };
211
-
212
- BookReader.prototype.ttsPlayPause = function() {
213
- if (!this.ttsEngine.playing) {
214
- this.ttsToggle();
215
- } else {
216
- this.ttsEngine.togglePlayPause();
217
- this.ttsUpdateState(this.ttsEngine.paused);
241
+
242
+ jumpForward() {
243
+ if (this.ttsEngine.paused) {
244
+ this.ttsEngine.resume();
245
+ }
246
+ this.ttsEngine.jumpForward();
218
247
  }
219
- };
220
-
221
- // ttsStop()
222
- //______________________________________________________________________________
223
- BookReader.prototype.ttsStop = function () {
224
- this.refs.$BRReadAloudToolbar.removeClass('visible');
225
- this.$('.BRicon.read').removeClass('unread active');
226
- this.ttsSendAnalyticsEvent('Stop');
227
- this.ttsEngine.stop();
228
- this.ttsRemoveHilites();
229
- this.removeProgressPopup();
230
- };
231
248
 
232
- /**
233
- * @param {PageChunk} chunk
234
- * @return {PromiseLike<void>} returns once the flip is done
235
- */
236
- BookReader.prototype.ttsBeforeChunkPlay = function(chunk) {
237
- return this.ttsMaybeFlipToIndex(chunk.leafIndex)
238
- .then(() => {
239
- this.ttsHighlightChunk(chunk);
240
- this.ttsScrollToChunk(chunk);
241
- });
242
- };
249
+ jumpBackward() {
250
+ if (this.ttsEngine.paused) {
251
+ this.ttsEngine.resume();
252
+ }
253
+ this.ttsEngine.jumpBackward();
254
+ }
243
255
 
244
- /**
245
- * @param {PageChunk} chunk
246
- */
247
- BookReader.prototype.ttsSendChunkFinishedAnalyticsEvent = function(chunk) {
248
- this.ttsSendAnalyticsEvent('ChunkFinished-Words', approximateWordCount(chunk.text));
249
- };
256
+ updateState() {
257
+ const isPlaying = !(this.ttsEngine.paused || !this.ttsEngine.playing);
258
+ this.br.$('.read-aloud [name=play]').toggleClass('playing', isPlaying);
259
+ }
250
260
 
251
- /**
252
- * Flip the page if the provided leaf index is not visible
253
- * @param {Number} leafIndex
254
- * @return {PromiseLike<void>} resolves once the flip animation has completed
255
- */
256
- BookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {
257
- const in2PageMode = this.constMode2up == this.mode;
258
- let resolve = null;
259
- const promise = new Promise(res => resolve = res);
260
-
261
- if (!in2PageMode) {
262
- this.jumpToIndex(leafIndex);
263
- resolve();
264
- } else {
265
- const leafVisible = leafIndex == this.twoPage.currentIndexR || leafIndex == this.twoPage.currentIndexL;
266
- if (leafVisible) {
267
- resolve();
261
+ playPause() {
262
+ if (!this.ttsEngine.playing) {
263
+ this.toggle();
268
264
  } else {
269
- this.animationFinishedCallback = resolve;
270
- const mustGoNext = leafIndex > Math.max(this.twoPage.currentIndexR, this.twoPage.currentIndexL);
271
- if (mustGoNext) this.next();
272
- else this.prev();
273
- promise.then(this.ttsMaybeFlipToIndex.bind(this, leafIndex));
265
+ this.ttsEngine.togglePlayPause();
266
+ this.updateState();
274
267
  }
275
268
  }
276
269
 
277
- return promise;
278
- }
279
270
 
280
- /**
281
- * @param {PageChunk} chunk
282
- */
283
- BookReader.prototype.ttsHighlightChunk = function(chunk) {
284
- this.ttsRemoveHilites();
285
-
286
- if (this.constMode2up == this.mode) {
287
- this.ttsHilite2UP(chunk);
288
- } else {
289
- this.ttsHilite1UP(chunk);
271
+ stop() {
272
+ this.br.refs.$BRReadAloudToolbar.removeClass('visible');
273
+ this.br.$('.BRicon.read').removeClass('unread active');
274
+ this.sendAnalyticsEvent('Stop');
275
+ this.ttsEngine.stop();
276
+ this.removeHilites();
277
+ this.br.removeProgressPopup();
290
278
  }
291
- };
292
279
 
293
- /**
294
- * @param {PageChunk} chunk
295
- */
296
- BookReader.prototype.ttsScrollToChunk = function(chunk) {
297
- if (this.constMode1up != this.mode) return;
298
-
299
- let leafTop = 0;
300
- let h;
301
- let i;
302
- for (i = 0; i < chunk.leafIndex; i++) {
303
- h = parseInt(this._getPageHeight(i) / this.reduce);
304
- leafTop += h + this.padding;
280
+ /**
281
+ * @param {PageChunk} chunk
282
+ * Returns once the flip is done
283
+ */
284
+ async beforeChunkPlay(chunk) {
285
+ await this.maybeFlipToIndex(chunk.leafIndex);
286
+ this.highlightChunk(chunk);
287
+ this.scrollToChunk(chunk);
305
288
  }
306
289
 
307
- const chunkTop = chunk.lineRects[0][3]; //coords are in l,b,r,t order
308
- const chunkBot = chunk.lineRects[chunk.lineRects.length - 1][1];
309
-
310
- const topOfFirstChunk = leafTop + chunkTop / this.reduce;
311
- const botOfLastChunk = leafTop + chunkBot / this.reduce;
312
-
313
- if (window?.soundManager?.debugMode) console.log('leafTop = ' + leafTop + ' topOfFirstChunk = ' + topOfFirstChunk + ' botOfLastChunk = ' + botOfLastChunk);
290
+ /**
291
+ * @param {PageChunk} chunk
292
+ */
293
+ sendChunkFinishedAnalyticsEvent(chunk) {
294
+ this.sendAnalyticsEvent('ChunkFinished-Words', approximateWordCount(chunk.text));
295
+ }
314
296
 
315
- const containerTop = this.refs.$brContainer.prop('scrollTop');
316
- const containerBot = containerTop + this.refs.$brContainer.height();
317
- if (window?.soundManager?.debugMode) console.log('containerTop = ' + containerTop + ' containerBot = ' + containerBot);
297
+ /**
298
+ * Flip the page if the provided leaf index is not visible
299
+ * @param {Number} leafIndex
300
+ */
301
+ async maybeFlipToIndex(leafIndex) {
302
+ if (!this.br._isIndexDisplayed(leafIndex)) {
303
+ // Don't interrupt the read aloud with the page flip update?
304
+ this.br.jumpToIndex(leafIndex, { ariaLive: false });
305
+ }
306
+ }
318
307
 
319
- if ((topOfFirstChunk < containerTop) || (botOfLastChunk > containerBot)) {
320
- this.refs.$brContainer.stop(true).animate({scrollTop: topOfFirstChunk},'fast');
308
+ /**
309
+ * @param {PageChunk} chunk
310
+ */
311
+ highlightChunk(chunk) {
312
+ // The poorly-named variable leafIndex
313
+ const pageIndex = chunk.leafIndex;
314
+
315
+ this.removeHilites();
316
+ if (this.br.plugins.translate?.translationManager.active) {
317
+ const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
318
+ const paragraphIndex = chunk.chunkIndex;
319
+ pageContainers.forEach(container => {
320
+ const translateElement = container.querySelector('.BRtranslateLayer');
321
+ const containerChildren = Array.from(translateElement.childNodes);
322
+ const paragraphEle = containerChildren[paragraphIndex];
323
+ if (!paragraphEle) { return; }
324
+ const [pOffHeight, pOffTop, pOffWidth, pOffLeft] = [paragraphEle.offsetHeight, paragraphEle.offsetTop, paragraphEle.offsetWidth, paragraphEle.offsetLeft];
325
+ const boxes = {pageIndex: [
326
+ {l: pOffLeft, r: pOffLeft + pOffWidth, b: pOffTop + pOffHeight, t: pOffTop},
327
+ ]};
328
+ renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes.pageIndex, this.br.book.getPage(pageIndex), translateElement);
329
+ });
330
+ return;
331
+ }
332
+ // group by index; currently only possible to have chunks on one page :/
333
+ this._ttsBoxesByIndex = {
334
+ [pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t})),
335
+ };
336
+
337
+ // update any already created pages
338
+ for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {
339
+ const pageIndex = parseFloat(pageIndexString);
340
+ const page = this.br.book.getPage(pageIndex);
341
+ const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
342
+ pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));
343
+ }
321
344
  }
322
- };
323
345
 
324
- /**
325
- * @param {PageChunk} chunk
326
- */
327
- BookReader.prototype.ttsHilite1UP = function(chunk) {
328
- for (let i = 0; i < chunk.lineRects.length; i++) {
329
- //each rect is an array of l,b,r,t coords (djvu.xml ordering...)
330
- const l = chunk.lineRects[i][0];
331
- const b = chunk.lineRects[i][1];
332
- const r = chunk.lineRects[i][2];
333
- const t = chunk.lineRects[i][3];
334
-
335
- const div = document.createElement('div');
336
- this.ttsHilites.push(div);
337
- $(div).prop('className', 'BookReaderSearchHilite').appendTo(
338
- this.$('.pagediv' + chunk.leafIndex)
339
- );
340
-
341
- $(div).css({
342
- width: (r - l) / this.reduce + 'px',
343
- height: (b - t) / this.reduce + 'px',
344
- left: l / this.reduce + 'px',
345
- top: t / this.reduce + 'px'
346
+ /**
347
+ * @param {PageChunk} chunk
348
+ */
349
+ scrollToChunk(chunk) {
350
+ // It behaves weird if used in thumb mode
351
+ if (this.br.constModeThumb == this.br.mode) return;
352
+
353
+ $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({
354
+ // Only vertically center the highlight if we're in 1up or in full screen. In
355
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
356
+ // center the highlight 🙄 See:
357
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
358
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
359
+ // full-width, and covers up the last line of the highlight.
360
+ block: this.br.constMode1up == this.br.mode || this.br.isFullscreenActive ? 'center' : 'nearest',
361
+ inline: 'center',
362
+ behavior: 'smooth',
346
363
  });
347
364
  }
348
365
 
349
- };
350
-
351
- /**
352
- * @param {PageChunk} chunk
353
- */
354
- BookReader.prototype.ttsHilite2UP = function (chunk) {
355
- for (let i = 0; i < chunk.lineRects.length; i++) {
356
- //each rect is an array of l,b,r,t coords (djvu.xml ordering...)
357
- const l = chunk.lineRects[i][0];
358
- const b = chunk.lineRects[i][1];
359
- const r = chunk.lineRects[i][2];
360
- const t = chunk.lineRects[i][3];
361
-
362
- const div = document.createElement('div');
363
- this.ttsHilites.push(div);
364
- $(div)
365
- .prop('className', 'BookReaderSearchHilite BRReadAloudHilite Leaf-' + chunk.leafIndex)
366
- .css('zIndex', 3)
367
- .appendTo(this.refs.$brTwoPageView);
368
- this.setHilightCss2UP(div, chunk.leafIndex, l, r, t, b);
366
+ removeHilites() {
367
+ $(this.br.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();
368
+ this._ttsBoxesByIndex = {};
369
369
  }
370
- };
371
370
 
372
- // ttsRemoveHilites()
373
- //______________________________________________________________________________
374
- BookReader.prototype.ttsRemoveHilites = function () {
375
- $(this.ttsHilites).remove();
376
- this.ttsHilites = [];
377
- };
378
-
379
- /**
380
- * @private
381
- * Send an analytics event with an optional value. Also attaches the book's language.
382
- * @param {string} action
383
- * @param {number} [value]
384
- */
385
- BookReader.prototype.ttsSendAnalyticsEvent = function(action, value) {
386
- if (this.archiveAnalyticsSendEvent) {
387
- const extraValues = {};
388
- const mediaLanguage = this.ttsEngine.opts.bookLanguage;
389
- if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;
390
- this.archiveAnalyticsSendEvent('BRReadAloud', action, value, extraValues);
371
+ /**
372
+ * @private
373
+ * Send an analytics event with an optional value. Also attaches the book's language.
374
+ * @param {string} action
375
+ * @param {number} [value]
376
+ */
377
+ sendAnalyticsEvent(action, value) {
378
+ if (this.br.plugins.archiveAnalytics) {
379
+ const extraValues = {};
380
+ const mediaLanguage = this.ttsEngine.opts.bookLanguage;
381
+ if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;
382
+ this.br.plugins.archiveAnalytics.sendEvent('BRReadAloud', action, value, extraValues);
383
+ }
391
384
  }
392
- };
385
+ }
386
+
387
+ BookReader?.registerPlugin('tts', TtsPlugin);