@internetarchive/bookreader 5.0.0-10-alpha-3 → 5.0.0-101

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 (374) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +431 -1134
  4. package/BookReader/BookReader.js +1 -1
  5. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  6. package/BookReader/BookReader.js.map +1 -1
  7. package/BookReader/bergamot-translator-worker.js +2966 -0
  8. package/BookReader/bergamot-translator-worker.wasm +0 -0
  9. package/BookReader/hypothesis/LICENSE +50 -0
  10. package/BookReader/hypothesis/README.md +55 -0
  11. package/BookReader/hypothesis/build/boot.js +1 -0
  12. package/BookReader/hypothesis/build/manifest.json +20 -0
  13. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +184 -0
  14. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +798 -0
  16. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  17. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +711 -0
  18. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  19. package/BookReader/hypothesis/build/styles/annotator.css +2235 -0
  20. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  38. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  39. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  40. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  41. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  42. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/katex.min.css +2 -0
  44. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +2 -0
  46. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  47. package/BookReader/hypothesis/build/styles/sidebar.css +2731 -0
  48. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  49. package/BookReader/hypothesis/build/styles/ui-playground.css +2659 -0
  50. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  51. package/BookReader/hypothesis/package.json +126 -0
  52. package/BookReader/ia-bookreader-bundle.js +1782 -0
  53. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  54. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  55. package/BookReader/icons/1up.svg +1 -1
  56. package/BookReader/icons/2up.svg +1 -1
  57. package/BookReader/icons/advance.svg +1 -1
  58. package/BookReader/icons/chevron-right.svg +1 -1
  59. package/BookReader/icons/close-circle-dark.svg +1 -1
  60. package/BookReader/icons/close-circle.svg +1 -1
  61. package/BookReader/icons/fullscreen.svg +1 -1
  62. package/BookReader/icons/fullscreen_exit.svg +1 -1
  63. package/BookReader/icons/hamburger.svg +1 -1
  64. package/BookReader/icons/left-arrow.svg +1 -1
  65. package/BookReader/icons/magnify-minus.svg +1 -1
  66. package/BookReader/icons/magnify-plus.svg +1 -1
  67. package/BookReader/icons/magnify.svg +1 -1
  68. package/BookReader/icons/pause.svg +1 -1
  69. package/BookReader/icons/play.svg +1 -1
  70. package/BookReader/icons/playback-speed.svg +1 -1
  71. package/BookReader/icons/read-aloud.svg +1 -1
  72. package/BookReader/icons/review.svg +1 -1
  73. package/BookReader/icons/thumbnails.svg +1 -1
  74. package/BookReader/icons/voice.svg +1 -0
  75. package/BookReader/icons/volume-full.svg +1 -1
  76. package/BookReader/images/BRicons.svg +3 -3
  77. package/BookReader/images/books_graphic.svg +1 -1
  78. package/BookReader/images/hypothesis.ico +0 -0
  79. package/BookReader/images/icon_book.svg +1 -1
  80. package/BookReader/images/icon_bookmark.svg +1 -1
  81. package/BookReader/images/icon_experiment.svg +1 -0
  82. package/BookReader/images/icon_gear.svg +1 -1
  83. package/BookReader/images/icon_hamburger.svg +1 -1
  84. package/BookReader/images/icon_home.svg +1 -1
  85. package/BookReader/images/icon_info.svg +1 -1
  86. package/BookReader/images/icon_one_page.svg +1 -1
  87. package/BookReader/images/icon_pause.svg +1 -1
  88. package/BookReader/images/icon_play.svg +1 -1
  89. package/BookReader/images/icon_playback-rate.svg +1 -1
  90. package/BookReader/images/icon_search_button.svg +1 -1
  91. package/BookReader/images/icon_share.svg +1 -1
  92. package/BookReader/images/icon_skip-ahead.svg +1 -1
  93. package/BookReader/images/icon_skip-back.svg +1 -1
  94. package/BookReader/images/icon_speaker.svg +1 -1
  95. package/BookReader/images/icon_speaker_open.svg +1 -1
  96. package/BookReader/images/icon_thumbnails.svg +1 -1
  97. package/BookReader/images/icon_toc.svg +1 -1
  98. package/BookReader/images/icon_two_pages.svg +1 -1
  99. package/BookReader/images/marker_chap-off.svg +1 -1
  100. package/BookReader/images/marker_chap-on.svg +1 -1
  101. package/BookReader/images/marker_srch-on.svg +1 -1
  102. package/BookReader/images/translate.svg +1 -0
  103. package/BookReader/images/unviewable_page.png +0 -0
  104. package/BookReader/jquery-3.js +2 -0
  105. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  106. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  107. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  108. package/BookReader/plugins/plugin.autoplay.js +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  110. package/BookReader/plugins/plugin.chapters.js +25 -1
  111. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  112. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  113. package/BookReader/plugins/plugin.experiments.js +3 -0
  114. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  115. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  116. package/BookReader/plugins/plugin.iframe.js +1 -1
  117. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  118. package/BookReader/plugins/plugin.iiif.js +2 -0
  119. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  120. package/BookReader/plugins/plugin.resume.js +1 -1
  121. package/BookReader/plugins/plugin.resume.js.map +1 -1
  122. package/BookReader/plugins/plugin.search.js +2 -1
  123. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  124. package/BookReader/plugins/plugin.search.js.map +1 -1
  125. package/BookReader/plugins/plugin.text_selection.js +2 -1
  126. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  127. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  128. package/BookReader/plugins/plugin.translate.js +137 -0
  129. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  130. package/BookReader/plugins/plugin.translate.js.map +1 -0
  131. package/BookReader/plugins/plugin.tts.js +1 -1
  132. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  133. package/BookReader/plugins/plugin.tts.js.map +1 -1
  134. package/BookReader/plugins/plugin.url.js +1 -1
  135. package/BookReader/plugins/plugin.url.js.map +1 -1
  136. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  137. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  138. package/BookReader/plugins/translator-worker.js +2 -0
  139. package/BookReader/plugins/translator-worker.js.map +1 -0
  140. package/BookReader/silence.mp3 +0 -0
  141. package/BookReader/translator-worker.js +475 -0
  142. package/BookReader/webcomponents-bundle.js +3 -0
  143. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  144. package/BookReader/webcomponents-bundle.js.map +1 -0
  145. package/README.md +14 -3
  146. package/jsconfig.json +19 -0
  147. package/package.json +84 -64
  148. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  149. package/src/BookNavigator/assets/button-base.js +2 -1
  150. package/src/BookNavigator/assets/ia-logo.js +17 -0
  151. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  152. package/src/BookNavigator/assets/icon_close.js +1 -1
  153. package/src/BookNavigator/book-navigator.js +620 -0
  154. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  155. package/src/BookNavigator/bookmarks/bookmark-edit.js +2 -3
  156. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  157. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +2 -2
  158. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  159. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  160. package/src/BookNavigator/delete-modal-actions.js +1 -1
  161. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  162. package/src/BookNavigator/downloads/downloads.js +24 -4
  163. package/src/BookNavigator/search/search-provider.js +55 -27
  164. package/src/BookNavigator/search/search-results.js +25 -11
  165. package/src/BookNavigator/sharing.js +27 -0
  166. package/src/BookNavigator/viewable-files.js +95 -0
  167. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  168. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +9 -9
  169. package/src/BookReader/BookModel.js +92 -46
  170. package/src/BookReader/DragScrollable.js +233 -0
  171. package/src/BookReader/ImageCache.js +49 -16
  172. package/src/BookReader/Mode1Up.js +58 -360
  173. package/src/BookReader/Mode1UpLit.js +393 -0
  174. package/src/BookReader/Mode2Up.js +75 -1318
  175. package/src/BookReader/Mode2UpLit.js +787 -0
  176. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  177. package/src/BookReader/ModeSmoothZoom.js +312 -0
  178. package/src/BookReader/ModeThumb.js +20 -12
  179. package/src/BookReader/Navbar/Navbar.js +130 -53
  180. package/src/BookReader/PageContainer.js +120 -23
  181. package/src/BookReader/ReduceSet.js +2 -2
  182. package/src/BookReader/Toolbar/Toolbar.js +18 -40
  183. package/src/BookReader/events.js +2 -3
  184. package/src/BookReader/options.js +87 -16
  185. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  186. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  187. package/src/BookReader/utils/SelectionObserver.js +45 -0
  188. package/src/BookReader/utils/classes.js +1 -1
  189. package/src/BookReader/utils.js +136 -12
  190. package/src/BookReader.js +641 -1192
  191. package/src/BookReaderPlugin.js +52 -0
  192. package/src/assets/icons/magnify-minus.svg +3 -7
  193. package/src/assets/icons/magnify-plus.svg +3 -7
  194. package/src/assets/icons/voice.svg +1 -0
  195. package/src/assets/images/hypothesis.ico +0 -0
  196. package/src/assets/images/icon_experiment.svg +1 -0
  197. package/src/assets/images/translate.svg +1 -0
  198. package/src/assets/images/unviewable_page.png +0 -0
  199. package/src/assets/silence.mp3 +0 -0
  200. package/src/css/BookReader.scss +1 -5
  201. package/src/css/_BRBookmarks.scss +1 -1
  202. package/src/css/_BRComponent.scss +1 -1
  203. package/src/css/_BRicon.scss +8 -2
  204. package/src/css/_BRmain.scss +16 -3
  205. package/src/css/_BRnav.scss +12 -66
  206. package/src/css/_BRpages.scss +171 -42
  207. package/src/css/_BRsearch.scss +69 -30
  208. package/src/css/_BRtoolbar.scss +5 -5
  209. package/src/css/_TextSelection.scss +129 -24
  210. package/src/css/_colorbox.scss +2 -2
  211. package/src/css/_controls.scss +24 -7
  212. package/src/css/_icons.scss +1 -1
  213. package/src/ia-bookreader/ia-bookreader.js +224 -0
  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 +314 -205
  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 +54 -51
  221. package/src/plugins/plugin.text_selection.js +510 -219
  222. package/src/plugins/plugin.vendor-fullscreen.js +5 -5
  223. package/src/plugins/search/plugin.search.js +370 -392
  224. package/src/plugins/search/utils.js +43 -0
  225. package/src/plugins/search/view.js +49 -67
  226. package/src/plugins/translate/TranslationManager.js +162 -0
  227. package/src/plugins/translate/plugin.translate.js +523 -0
  228. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  229. package/src/plugins/tts/FestivalTTSEngine.js +20 -30
  230. package/src/plugins/tts/PageChunk.js +33 -21
  231. package/src/plugins/tts/PageChunkIterator.js +11 -17
  232. package/src/plugins/tts/WebTTSEngine.js +131 -91
  233. package/src/plugins/tts/plugin.tts.js +344 -350
  234. package/src/plugins/tts/utils.js +49 -47
  235. package/src/plugins/url/UrlPlugin.js +191 -0
  236. package/src/plugins/{plugin.url.js → url/plugin.url.js} +44 -15
  237. package/src/util/TextSelectionManager.js +282 -0
  238. package/src/util/browserSniffing.js +33 -1
  239. package/src/util/cache.js +20 -0
  240. package/src/util/docCookies.js +21 -2
  241. package/src/util/strings.js +1 -0
  242. package/.babelrc +0 -12
  243. package/.dependabot/config.yml +0 -6
  244. package/.eslintrc.js +0 -50
  245. package/.gitattributes +0 -2
  246. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  247. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  248. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  249. package/.github/workflows/node.js.yml +0 -37
  250. package/.github/workflows/npm-publish.yml +0 -47
  251. package/.testcaferc.json +0 -5
  252. package/BookReader/bookreader-component-bundle.js +0 -1450
  253. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  254. package/BookReader/bookreader-component-bundle.js.map +0 -1
  255. package/BookReader/jquery-1.10.1.js +0 -2
  256. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  257. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  258. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  259. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  260. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  261. package/BookReaderDemo/BookReaderDemo.css +0 -41
  262. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  263. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  264. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  265. package/BookReaderDemo/IIIFBookReader.js +0 -207
  266. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  267. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  268. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  269. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  270. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  273. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  274. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  275. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  276. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  277. package/BookReaderDemo/demo-advanced.html +0 -33
  278. package/BookReaderDemo/demo-autoplay.html +0 -38
  279. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  280. package/BookReaderDemo/demo-embed.html +0 -26
  281. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  282. package/BookReaderDemo/demo-fullscreen.html +0 -33
  283. package/BookReaderDemo/demo-iiif.html +0 -34
  284. package/BookReaderDemo/demo-iiif.js +0 -26
  285. package/BookReaderDemo/demo-internetarchive.html +0 -74
  286. package/BookReaderDemo/demo-multiple.html +0 -43
  287. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  288. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  289. package/BookReaderDemo/demo-simple.html +0 -34
  290. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  291. package/BookReaderDemo/immersion-1up.html +0 -64
  292. package/BookReaderDemo/immersion-mode.html +0 -35
  293. package/BookReaderDemo/toggle_controls.html +0 -53
  294. package/BookReaderDemo/view_mode.html +0 -39
  295. package/BookReaderDemo/viewmode-cycle.html +0 -41
  296. package/CHANGELOG.md +0 -493
  297. package/CONTRIBUTING.md +0 -7
  298. package/codecov.yml +0 -17
  299. package/index.html +0 -31
  300. package/karma.conf.js +0 -23
  301. package/screenshot.png +0 -0
  302. package/scripts/postversion.js +0 -10
  303. package/scripts/preversion.js +0 -14
  304. package/scripts/version.js +0 -26
  305. package/src/BookNavigator/BookModel.js +0 -14
  306. package/src/BookNavigator/BookNavigator.js +0 -446
  307. package/src/BookNavigator/assets/book-loader.js +0 -27
  308. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  309. package/src/BookNavigator/search/a-search-result.js +0 -55
  310. package/src/BookReader/DebugConsole.js +0 -54
  311. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  312. package/src/ItemNavigator/ItemNavigator.js +0 -376
  313. package/src/ItemNavigator/providers/sharing.js +0 -29
  314. package/src/css/_MobileNav.scss +0 -194
  315. package/src/dragscrollable-br.js +0 -261
  316. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  317. package/src/plugins/plugin.mobile_nav.js +0 -287
  318. package/tests/BookReader/BookModel.test.js +0 -312
  319. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  320. package/tests/BookReader/DebugConsole.test.js +0 -25
  321. package/tests/BookReader/ImageCache.test.js +0 -150
  322. package/tests/BookReader/Mode1Up.test.js +0 -164
  323. package/tests/BookReader/Mode2Up.test.js +0 -247
  324. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  325. package/tests/BookReader/PageContainer.test.js +0 -115
  326. package/tests/BookReader/ReduceSet.test.js +0 -38
  327. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  328. package/tests/BookReader/utils/classes.test.js +0 -88
  329. package/tests/BookReader/utils.test.js +0 -109
  330. package/tests/BookReader.options.test.js +0 -39
  331. package/tests/BookReader.test.js +0 -301
  332. package/tests/e2e/README.md +0 -75
  333. package/tests/e2e/autoplay.test.js +0 -13
  334. package/tests/e2e/base.test.js +0 -35
  335. package/tests/e2e/helpers/base.js +0 -263
  336. package/tests/e2e/helpers/debug.js +0 -13
  337. package/tests/e2e/helpers/desktopSearch.js +0 -72
  338. package/tests/e2e/helpers/mobileSearch.js +0 -85
  339. package/tests/e2e/helpers/mockSearch.js +0 -93
  340. package/tests/e2e/helpers/rightToLeft.js +0 -29
  341. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  342. package/tests/e2e/models/BookReader.js +0 -11
  343. package/tests/e2e/models/Navigation.js +0 -56
  344. package/tests/e2e/rightToLeft.test.js +0 -20
  345. package/tests/e2e/viewmode.test.js +0 -37
  346. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  347. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  348. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  349. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  350. package/tests/karma/BookNavigator/search/search-results.test.js +0 -240
  351. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  352. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  353. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  354. package/tests/plugins/plugin.autoplay.test.js +0 -52
  355. package/tests/plugins/plugin.chapters.test.js +0 -130
  356. package/tests/plugins/plugin.iframe.test.js +0 -42
  357. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  358. package/tests/plugins/plugin.resume.test.js +0 -98
  359. package/tests/plugins/plugin.text_selection.test.js +0 -203
  360. package/tests/plugins/plugin.url.test.js +0 -129
  361. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  362. package/tests/plugins/search/plugin.search.test.js +0 -173
  363. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  364. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  365. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  366. package/tests/plugins/tts/PageChunk.test.js +0 -57
  367. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  368. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  369. package/tests/plugins/tts/utils.test.js +0 -133
  370. package/tests/util/browserSniffing.test.js +0 -56
  371. package/tests/util/docCookies.test.js +0 -15
  372. package/tests/util/strings.test.js +0 -63
  373. package/tests/utils.js +0 -42
  374. package/webpack.config.js +0 -86
@@ -1,392 +1,386 @@
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
+ });
80
94
 
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));
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
+ }
101
+
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
+ this.br.jumpToIndex(leafIndex);
304
+ }
305
+ }
318
306
 
319
- if ((topOfFirstChunk < containerTop) || (botOfLastChunk > containerBot)) {
320
- this.refs.$brContainer.stop(true).animate({scrollTop: topOfFirstChunk},'fast');
307
+ /**
308
+ * @param {PageChunk} chunk
309
+ */
310
+ highlightChunk(chunk) {
311
+ // The poorly-named variable leafIndex
312
+ const pageIndex = chunk.leafIndex;
313
+
314
+ this.removeHilites();
315
+ if (this.br.plugins.translate?.translationManager.active) {
316
+ const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
317
+ const paragraphIndex = chunk.chunkIndex;
318
+ pageContainers.forEach(container => {
319
+ const translateElement = container.querySelector('.BRtranslateLayer');
320
+ const containerChildren = Array.from(translateElement.childNodes);
321
+ const paragraphEle = containerChildren[paragraphIndex];
322
+ if (!paragraphEle) { return; }
323
+ const [pOffHeight, pOffTop, pOffWidth, pOffLeft] = [paragraphEle.offsetHeight, paragraphEle.offsetTop, paragraphEle.offsetWidth, paragraphEle.offsetLeft];
324
+ const boxes = {pageIndex: [
325
+ {l: pOffLeft, r: pOffLeft + pOffWidth, b: pOffTop + pOffHeight, t: pOffTop},
326
+ ]};
327
+ renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes.pageIndex, this.br.book.getPage(pageIndex), translateElement);
328
+ });
329
+ return;
330
+ }
331
+ // group by index; currently only possible to have chunks on one page :/
332
+ this._ttsBoxesByIndex = {
333
+ [pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t})),
334
+ };
335
+
336
+ // update any already created pages
337
+ for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {
338
+ const pageIndex = parseFloat(pageIndexString);
339
+ const page = this.br.book.getPage(pageIndex);
340
+ const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
341
+ pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));
342
+ }
321
343
  }
322
- };
323
344
 
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'
345
+ /**
346
+ * @param {PageChunk} chunk
347
+ */
348
+ scrollToChunk(chunk) {
349
+ // It behaves weird if used in thumb mode
350
+ if (this.br.constModeThumb == this.br.mode) return;
351
+
352
+ $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({
353
+ // Only vertically center the highlight if we're in 1up or in full screen. In
354
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
355
+ // center the highlight 🙄 See:
356
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
357
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
358
+ // full-width, and covers up the last line of the highlight.
359
+ block: this.br.constMode1up == this.br.mode || this.br.isFullscreenActive ? 'center' : 'nearest',
360
+ inline: 'center',
361
+ behavior: 'smooth',
346
362
  });
347
363
  }
348
364
 
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);
365
+ removeHilites() {
366
+ $(this.br.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();
367
+ this._ttsBoxesByIndex = {};
369
368
  }
370
- };
371
-
372
- // ttsRemoveHilites()
373
- //______________________________________________________________________________
374
- BookReader.prototype.ttsRemoveHilites = function () {
375
- $(this.ttsHilites).remove();
376
- this.ttsHilites = [];
377
- };
378
369
 
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);
370
+ /**
371
+ * @private
372
+ * Send an analytics event with an optional value. Also attaches the book's language.
373
+ * @param {string} action
374
+ * @param {number} [value]
375
+ */
376
+ sendAnalyticsEvent(action, value) {
377
+ if (this.br.plugins.archiveAnalytics) {
378
+ const extraValues = {};
379
+ const mediaLanguage = this.ttsEngine.opts.bookLanguage;
380
+ if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;
381
+ this.br.plugins.archiveAnalytics.sendEvent('BRReadAloud', action, value, extraValues);
382
+ }
391
383
  }
392
- };
384
+ }
385
+
386
+ BookReader?.registerPlugin('tts', TtsPlugin);