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

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 +428 -1139
  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 +163 -43
  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
@@ -0,0 +1,523 @@
1
+ // @ts-check
2
+ import { html, LitElement } from 'lit';
3
+ import { BookReaderPlugin } from '../../BookReaderPlugin.js';
4
+ import { customElement, property } from 'lit/decorators.js';
5
+ import { TranslationManager } from "./TranslationManager.js";
6
+ import { toISO6391 } from '../tts/utils.js';
7
+ import { sortBy } from '../../../src/BookReader/utils.js';
8
+ import { TextSelectionManager } from '../../../src/util/TextSelectionManager.js';
9
+ import '@internetarchive/ia-activity-indicator/ia-activity-indicator.js';
10
+
11
+ // @ts-ignore
12
+ const BookReader = /** @type {typeof import('@/src/BookReader.js').default} */(window.BookReader);
13
+
14
+ export class TranslatePlugin extends BookReaderPlugin {
15
+
16
+ options = {
17
+ enabled: true,
18
+
19
+ /** @type {string | import('lit').TemplateResult} */
20
+ panelDisclaimerText: "Translations are in alpha",
21
+ }
22
+
23
+ /** @type {TranslationManager} */
24
+ translationManager = new TranslationManager();
25
+
26
+ /** @type {Worker}*/
27
+ worker;
28
+
29
+ /**
30
+ * Contains the list of languages available to translate to
31
+ * @type {string[]}
32
+ */
33
+ toLanguages = [];
34
+
35
+ /**
36
+ * Current language code that is being translated From. Defaults to EN currently
37
+ * @type {!string}
38
+ */
39
+ langFromCode;
40
+
41
+ /**
42
+ * Current language code that is being translated To
43
+ * @type {!string}
44
+ */
45
+ langToCode;
46
+ /**
47
+ * @type {BrTranslatePanel} _panel - Represents a panel used in the plugin.
48
+ * The specific type and purpose of this panel should be defined based on its usage.
49
+ */
50
+ _panel;
51
+
52
+ /**
53
+ * @type {boolean} userToggleTranslate - Checks if user has initiated translation
54
+ * Should synchronize with the state of TranslationManager's active state
55
+ */
56
+ userToggleTranslate;
57
+
58
+ /**
59
+ * @type {boolean} loadingModel - Shows loading animation while downloading lang model
60
+ */
61
+ loadingModel = true;
62
+
63
+ textSelectionManager = new TextSelectionManager('.BRtranslateLayer', this.br, {selectionElement: [".BRlineElement"]}, 1);
64
+
65
+ async init() {
66
+ const currentLanguage = toISO6391(this.br.options.bookLanguage.replace(/[.,/#!$%^&*;:{}=\-_`~()]/g, ""));
67
+ this.langFromCode = currentLanguage ?? "en";
68
+ this.textSelectionManager.init();
69
+
70
+ if (!this.options.enabled) {
71
+ return;
72
+ }
73
+
74
+ this.translationManager.publicPath = this.br.options.imagesBaseURL.replace(/\/+$/, '') + '/..';
75
+
76
+ /**
77
+ * @param {*} ev
78
+ * @param {object} eventProps
79
+ */
80
+ this.br.on('textLayerRendered', async (_, {pageIndex, pageContainer}) => {
81
+ // Stops invalid models from running, also prevents translation on page load
82
+ // TODO check if model has finished loading or if it exists
83
+ if (!this.translationManager) {
84
+ return;
85
+ }
86
+ if (this.translationManager.active) {
87
+ const pageElement = pageContainer.$container[0];
88
+ this.translateRenderedLayer(pageElement);
89
+ }
90
+ });
91
+
92
+ /**
93
+ * @param {*} ev
94
+ * @param {object} eventProps
95
+ */
96
+ this.br.on('pageVisible', (_, {pageContainerEl}) => {
97
+ if (!this.translationManager.active) {
98
+ return;
99
+ }
100
+ for (const paragraphEl of pageContainerEl.querySelectorAll('.BRtranslateLayer > .BRparagraphElement')) {
101
+ if (paragraphEl.textContent) {
102
+ this.fitVisiblePage(paragraphEl);
103
+ }
104
+ }
105
+ });
106
+
107
+ await this.translationManager.initWorker();
108
+ // Note await above lets _render function properly, since it gives the browser
109
+ // time to render the rest of bookreader, which _render depends on
110
+ this.langToCode = this.translationManager.toLanguages[0].code;
111
+ this._render();
112
+ }
113
+
114
+ /** @param {HTMLElement} page*/
115
+ getParagraphsOnPage = (page) => {
116
+ return page ? Array.from(page.querySelectorAll(".BRtextLayer > .BRparagraphElement")) : [];
117
+ }
118
+
119
+ translateActivePageContainerElements() {
120
+ const currentlyActiveContainers = this.br.getActivePageContainerElements();
121
+ const visiblePageContainers = currentlyActiveContainers.filter((element) => {
122
+ return element.classList.contains('BRpage-visible');
123
+ });
124
+ const hiddenPageContainers = currentlyActiveContainers.filter((element) => {
125
+ return !element.classList.contains('BRpage-visible');
126
+ });
127
+
128
+ for (const page of visiblePageContainers) {
129
+ this.translateRenderedLayer(page, 0);
130
+ }
131
+ for (const loadingPage of hiddenPageContainers) {
132
+ this.translateRenderedLayer(loadingPage, 1000);
133
+ }
134
+ }
135
+
136
+ /** @param {HTMLElement} page */
137
+ async translateRenderedLayer(page, priority) {
138
+ // Do not run translation if in thumbnail mode or if user did not initiate transations
139
+ if (this.br.mode == this.br.constModeThumb || !this.userToggleTranslate || this.langFromCode == this.langToCode) {
140
+ return;
141
+ }
142
+
143
+ const pageIndex = page.dataset.index;
144
+
145
+ let pageTranslationLayer;
146
+ if (!page.querySelector('.BRPageLayer.BRtranslateLayer')) {
147
+ pageTranslationLayer = document.createElement('div');
148
+ pageTranslationLayer.classList.add('BRPageLayer', 'BRtranslateLayer', 'BRtranslateLayerLoading');
149
+ pageTranslationLayer.setAttribute('lang', `${this.langToCode}`);
150
+ page.prepend(pageTranslationLayer);
151
+ } else {
152
+ pageTranslationLayer = page.querySelector('.BRPageLayer.BRtranslateLayer');
153
+ }
154
+
155
+ const textLayerElement = page.querySelector('.BRtextLayer');
156
+ textLayerElement.classList.add('showingTranslation');
157
+ $(pageTranslationLayer).css({
158
+ "width": $(textLayerElement).css("width"),
159
+ "height": $(textLayerElement).css("height"),
160
+ "transform": $(textLayerElement).css("transform"),
161
+ "pointer-events": $(textLayerElement).css("pointer-events"),
162
+ "z-index": 3,
163
+ });
164
+ const paragraphs = this.getParagraphsOnPage(page);
165
+
166
+ const paragraphTranslationPromises = paragraphs.map(async (paragraph, pidx) => {
167
+ let translatedParagraph = page.querySelector(`[data-translate-index='${pageIndex}-${pidx}']`);
168
+ if (!translatedParagraph) {
169
+ translatedParagraph = document.createElement('p');
170
+ // set data-translate-index on the placeholder
171
+ translatedParagraph.setAttribute('data-translate-index', `${pageIndex}-${pidx}`);
172
+ translatedParagraph.className = 'BRparagraphElement';
173
+ const originalParagraphStyle = paragraphs[pidx];
174
+ // check text selection paragraphs for header/footer roles
175
+ if (paragraph.classList.contains('ocr-role-header-footer')) {
176
+ translatedParagraph.ariaHidden = "true";
177
+ translatedParagraph.classList.add('ocr-role-header-footer');
178
+ }
179
+ const fontSize = `${parseInt($(originalParagraphStyle).css("font-size"))}px`;
180
+
181
+ $(translatedParagraph).css({
182
+ "margin-left": $(originalParagraphStyle).css("margin-left"),
183
+ "margin-top": $(originalParagraphStyle).css("margin-top"),
184
+ "top": $(originalParagraphStyle).css("top"),
185
+ "height": $(originalParagraphStyle).css("height"),
186
+ "width": $(originalParagraphStyle).css("width"),
187
+ "font-size": fontSize,
188
+ });
189
+ pageTranslationLayer.append(translatedParagraph);
190
+ }
191
+
192
+ if (paragraph.textContent.length !== 0) {
193
+ const pagePriority = parseFloat(pageIndex) + priority + pidx;
194
+ this.translationManager.getTranslationModel(this.langFromCode, this.langToCode).then(() => {
195
+ this._panel.loadingModel = false;
196
+ this.loadingModel = false;
197
+ });
198
+ const translatedText = await this.translationManager.getTranslation(this.langFromCode, this.langToCode, pageIndex, pidx, paragraph.textContent, pagePriority);
199
+ // prevent duplicate spans from appearing if exists
200
+ translatedParagraph.firstElementChild?.remove();
201
+
202
+ const firstWordSpacing = paragraphs[pidx]?.firstChild?.firstChild;
203
+ const createSpan = document.createElement('span');
204
+ createSpan.className = 'BRlineElement';
205
+ createSpan.textContent = translatedText;
206
+ translatedParagraph.appendChild(createSpan);
207
+
208
+ $(createSpan).css({
209
+ "text-indent": $(firstWordSpacing).css('padding-left'),
210
+ });
211
+ if (page.classList.contains('BRpage-visible')) {
212
+ this.fitVisiblePage(translatedParagraph);
213
+ }
214
+ }
215
+ });
216
+
217
+ this.textSelectionManager?.stopPageFlip(this.br.refs.$brContainer);
218
+ await Promise.all(paragraphTranslationPromises);
219
+ this.br.trigger('translateLayerRendered', {
220
+ leafIndex: pageIndex,
221
+ translateLayer: pageTranslationLayer,
222
+ });
223
+ }
224
+
225
+ /**
226
+ * Get the translation layers for a specific leaf index.
227
+ * @param {number} leafIndex
228
+ * @returns {Promise<HTMLElement[]>}
229
+ */
230
+ async getTranslateLayers(leafIndex) {
231
+ const pageContainerElements = this.br.getActivePageContainerElementsForIndex(leafIndex);
232
+ const translateLayer = $(pageContainerElements).filter(`[data-index='${leafIndex}']`).find('.BRtranslateLayer');
233
+ if (translateLayer.length) return translateLayer.toArray();
234
+
235
+ return new Promise((res, rej) => {
236
+ const handler = async (_, extraParams) => {
237
+ if (extraParams.leafIndex == leafIndex) {
238
+ this.br.off('translateLayerRendered', handler); // remember to detach translateLayer
239
+ res([extraParams.translateLayer]);
240
+ }
241
+ };
242
+ this.br.on('translateLayerRendered', handler);
243
+ });
244
+ }
245
+
246
+ clearAllTranslations() {
247
+ document.querySelectorAll('.BRtranslateLayer').forEach(el => el.remove());
248
+ document.querySelectorAll('.showingTranslation').forEach(el => el.classList.remove('showingTranslation'));
249
+ }
250
+
251
+ /**
252
+ * @param {Element} paragEl
253
+ */
254
+ fitVisiblePage(paragEl) {
255
+ // For some reason, Chrome does not detect the transform property for the translation + text layers
256
+ // Could not get it to fetch the transform value using $().css method
257
+ // Oddly enough the value is retrieved if using .style.transform instead?
258
+ const translateLayerEl = paragEl.parentElement;
259
+ if ($(translateLayerEl).css('transform') == 'none') {
260
+ const pageNumber = paragEl.getAttribute('data-translate-index').split('-')[0];
261
+ /** @type {HTMLElement} selectionTransform */
262
+ const textLayerEl = document.querySelector(`[data-index='${pageNumber}'] .BRtextLayer`);
263
+ $(translateLayerEl).css({'transform': textLayerEl.style.transform});
264
+ }
265
+
266
+ const originalFontSize = parseInt($(paragEl).css("font-size"));
267
+ let adjustedFontSize = originalFontSize;
268
+ while (paragEl.clientHeight < paragEl.scrollHeight && adjustedFontSize > 0) {
269
+ adjustedFontSize--;
270
+ $(paragEl).css({ "font-size": `${adjustedFontSize}px` });
271
+ }
272
+
273
+ const textHeight = paragEl.firstElementChild.clientHeight;
274
+ const scrollHeight = paragEl.scrollHeight;
275
+ const fits = textHeight < scrollHeight;
276
+ if (fits) {
277
+ const lines = textHeight / adjustedFontSize;
278
+ // Line heights for smaller paragraphs occasionally need a minor adjustment
279
+ const newLineHeight = scrollHeight / lines;
280
+ $(paragEl).css({
281
+ "line-height" : `${newLineHeight}px`,
282
+ "overflow": "visible",
283
+ });
284
+ }
285
+ }
286
+
287
+ handleFromLangChange = async (e) => {
288
+ this.clearAllTranslations();
289
+ const selectedLangFrom = e.detail.value;
290
+
291
+ // Update the from language
292
+ this.langFromCode = selectedLangFrom;
293
+ this._panel.requestUpdate();
294
+
295
+ // Add 'From' language to 'To' list if not already present
296
+ if (!this.translationManager.toLanguages.some(lang => lang.code === selectedLangFrom)) {
297
+ this.translationManager.toLanguages.push({
298
+ code: selectedLangFrom,
299
+ name: this.translationManager.fromLanguages.find((entry) => entry.code == selectedLangFrom).name,
300
+ });
301
+ }
302
+
303
+ // Update the 'To' languages list and set the correct 'To' language
304
+ this._panel.toLanguages = this.translationManager.toLanguages;
305
+
306
+ console.log(this.langFromCode, this.langToCode);
307
+ this._render();
308
+ if (this.langFromCode !== this.langToCode) {
309
+ this.translateActivePageContainerElements();
310
+ }
311
+ }
312
+
313
+ handleToLangChange = async (e) => {
314
+ this.clearAllTranslations();
315
+ this.langToCode = e.detail.value;
316
+ this._render();
317
+ this.translateActivePageContainerElements();
318
+ }
319
+
320
+ handleToggleTranslation = async () => {
321
+ this.userToggleTranslate = !this.userToggleTranslate;
322
+ this.translationManager.active = this.userToggleTranslate;
323
+
324
+ this._render();
325
+ if (!this.userToggleTranslate) {
326
+ this.clearAllTranslations();
327
+ this.br.trigger('translationDisabled', { });
328
+ this.textSelectionManager.detach();
329
+ } else {
330
+ this.br.trigger('translationEnabled', { });
331
+ this.translateActivePageContainerElements();
332
+ this.textSelectionManager.attach();
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Update translation side menu
338
+ */
339
+ _render() {
340
+ this.br.shell.menuProviders['translate'] = {
341
+ id: 'translate',
342
+ icon: html`<img src='${this.br.options.imagesBaseURL}/translate.svg' width="26"/>`,
343
+ label: 'Translate',
344
+ component: html`<br-translate-panel
345
+ @connected="${e => {
346
+ this._panel = e.target;
347
+ this._panel.fromLanguages = this.translationManager.fromLanguages;
348
+ this._panel.toLanguages = this.translationManager.toLanguages;
349
+ this._panel.userTranslationActive = this.userToggleTranslate;
350
+ this._panel.detectedToLang = this.langToCode;
351
+ this._panel.detectedFromLang = this.langFromCode;
352
+ this._panel.loadingModel = this.loadingModel;
353
+ }
354
+ }"
355
+ @langFromChanged="${this.handleFromLangChange}"
356
+ @langToChanged="${this.handleToLangChange}"
357
+ @toggleTranslation="${this.handleToggleTranslation}"
358
+ .fromLanguages="${this.translationManager.fromLanguages}"
359
+ .toLanguages="${this.translationManager.toLanguages}"
360
+ .disclaimerMessage="${this.options.panelDisclaimerText}"
361
+ .userTranslationActive=${this.userToggleTranslate}
362
+ .detectedFromLang=${this.langFromCode}
363
+ .detectedToLang=${this.langToCode}
364
+ .loadingModel=${this.loadingModel}
365
+ class="translate-panel"
366
+ />`,
367
+ };
368
+ this.br.shell.updateMenuContents();
369
+ }
370
+ }
371
+ BookReader?.registerPlugin('translate', TranslatePlugin);
372
+
373
+ @customElement('br-translate-panel')
374
+ export class BrTranslatePanel extends LitElement {
375
+ @property({ type: Array }) fromLanguages = []; // List of obj {code, name}
376
+ @property({ type: Array }) toLanguages = []; // List of obj {code, name}
377
+ @property({ type: String }) prevSelectedLang = ''; // Tracks the previous selected language for the "To" dropdown
378
+ @property({ type: String }) disclaimerMessage = '';
379
+ @property({ type: Boolean }) userTranslationActive = false;
380
+ @property({ type: String }) detectedFromLang = '';
381
+ @property({ type: String }) detectedToLang = '';
382
+ @property({ type: Boolean }) loadingModel;
383
+
384
+ /** @override */
385
+ createRenderRoot() {
386
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
387
+ return this;
388
+ }
389
+
390
+ connectedCallback() {
391
+ super.connectedCallback();
392
+ this.dispatchEvent(new CustomEvent('connected'));
393
+ }
394
+
395
+ render() {
396
+ return html`<div class="app" style="margin-top: 5%;padding-right: 5px;">
397
+ <div
398
+ class="disclaimer"
399
+ id="disclaimerMessage"
400
+ style="background-color: rgba(255,255,255,0.1);padding: 10px;border-radius: 8px;font-size: 12px;margin-bottom: 10px;color: rgba(255,255,255, 0.9);"
401
+ >${this.disclaimerMessage}</div>
402
+
403
+ <div class="panel panel--to" style="padding: 0 10px;">
404
+ <label>
405
+ <span style="font-size: 12px;color: #ccc;">Translate To</span>
406
+ <select id="lang-to" name="to" class="lang-select" style="display:block; width:100%;" @change="${this._onLangToChange}">
407
+ ${sortBy(this.toLanguages, ((lang) => lang.name.toLowerCase()
408
+ )).map((lang) => {
409
+ return html`<option value="${lang.code}"
410
+ ?selected=${lang.code == this.detectedToLang}
411
+ > ${lang.name ? lang.name : lang.code} </option>`;
412
+ })
413
+ }
414
+ </select>
415
+ </label>
416
+ </div>
417
+
418
+ <div class="panel panel--start" style="text-align: right;padding: 0 10px;/*! font-size: 18px; */margin-top: 10px;">
419
+ <button class="start-translation-brn" @click="${this._toggleTranslation}">
420
+ ${this.userTranslationActive ? "Stop Translating" : "Translate"}
421
+ </button>
422
+ </div>
423
+
424
+ <div class="panel panel--from" style="font-size: 12px;color: #ccc;text-align: center;padding: 8px 10px;">
425
+ <details style="display: contents">
426
+ <summary style="text-decoration: underline white; cursor:pointer; display:inline-block">
427
+ <i>
428
+ Source: ${this._getLangName(this.detectedFromLang)} ${this.prevSelectedLang ? "" : "(detected)"}
429
+ </i> Change
430
+ </summary>
431
+ <select id="lang-from" name="from" class="lang-select" value=${this.detectedFromLang} @change="${this._onLangFromChange}" style="width:65%; margin-top: 3%; margin-bottom: 3%">
432
+ ${sortBy(this.fromLanguages, ((lang) => lang.name.toLowerCase()
433
+ )).map((lang) => {
434
+ return html`<option value="${lang.code}"
435
+ ?selected=${lang.code == this.detectedFromLang}
436
+ >${lang.name ? lang.name : lang.code} </option>`;
437
+ })
438
+ }
439
+ </select>
440
+ </details>
441
+ <div class="footer" id="status" style="margin-top:5%">
442
+ ${this._statusWarning()}
443
+ </div>
444
+
445
+ <div class="lang-models-loading">
446
+ ${this._languageModelStatus()}
447
+ </div>
448
+ </div>`;
449
+ }
450
+ _onLangFromChange(event) {
451
+ const langFromChangedEvent = new CustomEvent('langFromChanged', {
452
+ detail: { value: event.target.value },
453
+ bubbles: true,
454
+ composed: true,
455
+ });
456
+ this.dispatchEvent(langFromChangedEvent);
457
+
458
+ // Update the prevSelectedLang if "To" is different from "From"
459
+ if (this._getSelectedLang('to') !== this._getSelectedLang('from')) {
460
+ this.prevSelectedLang = this._getSelectedLang('from');
461
+ }
462
+ this.loadingModel = true;
463
+ this.detectedFromLang = event.target.value;
464
+ }
465
+
466
+ _onLangToChange(event) {
467
+ const langToChangedEvent = new CustomEvent('langToChanged', {
468
+ detail: { value: event.target.value },
469
+ bubbles: true,
470
+ composed: true,
471
+ });
472
+ this.dispatchEvent(langToChangedEvent);
473
+
474
+ // Update the prevSelectedLang if "To" is different from "From"
475
+ if (this._getSelectedLang('from') !== event.target.value) {
476
+ this.prevSelectedLang = this._getSelectedLang('from');
477
+ }
478
+ this.loadingModel = true;
479
+ this.detectedToLang = event.target.value;
480
+ }
481
+
482
+ _getSelectedLang(type) {
483
+ /** @type {HTMLSelectElement} */
484
+ const dropdown = this.querySelector(`#lang-${type}`);
485
+ return dropdown ? dropdown.value : '';
486
+ }
487
+
488
+ _getLangName(code) {
489
+ const lang = [...this.fromLanguages, ...this.toLanguages].find(lang => lang.code === code);
490
+ return lang ? lang.name : '';
491
+ }
492
+
493
+ _toggleTranslation(event) {
494
+ const toggleTranslateEvent = new CustomEvent('toggleTranslation', {
495
+ detail: {value: event.target.value},
496
+ bubbles: true,
497
+ composed:true,
498
+ });
499
+ this.userTranslationActive = !this.userTranslationActive;
500
+ this.dispatchEvent(toggleTranslateEvent);
501
+ }
502
+
503
+ // TODO: Hardcoded warning message for now but should add more statuses
504
+ _statusWarning() {
505
+ if (this.detectedFromLang == this.detectedToLang) {
506
+ return "Translate To language is the same as the Source language";
507
+ }
508
+ return "";
509
+ }
510
+
511
+ _languageModelStatus() {
512
+ if (this.userTranslationActive) {
513
+ if (this.loadingModel) {
514
+ return html`
515
+ <ia-activity-indicator mode="processing" style="display:block; width: 40px; height: 40px; margin: 0 auto;"></ia-activity-indicator>
516
+ <p>Downloading language model</p>
517
+ `;
518
+ }
519
+ return html`<p>Language model loaded</p>`;
520
+ }
521
+ return "";
522
+ }
523
+ }