@internetarchive/bookreader 5.0.0-95 → 5.0.0-97

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 (330) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +2257 -0
  4. package/BookReader/BookReader.js +3 -0
  5. package/BookReader/BookReader.js.LICENSE.txt +72 -0
  6. package/BookReader/BookReader.js.map +1 -0
  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 -0
  56. package/BookReader/icons/2up.svg +1 -0
  57. package/BookReader/icons/advance.svg +3 -0
  58. package/BookReader/icons/chevron-right.svg +1 -0
  59. package/BookReader/icons/close-circle-dark.svg +1 -0
  60. package/BookReader/icons/close-circle.svg +1 -0
  61. package/BookReader/icons/fullscreen.svg +1 -0
  62. package/BookReader/icons/fullscreen_exit.svg +1 -0
  63. package/BookReader/icons/hamburger.svg +1 -0
  64. package/BookReader/icons/left-arrow.svg +1 -0
  65. package/BookReader/icons/magnify-minus.svg +1 -0
  66. package/BookReader/icons/magnify-plus.svg +1 -0
  67. package/BookReader/icons/magnify.svg +1 -0
  68. package/BookReader/icons/pause.svg +1 -0
  69. package/BookReader/icons/play.svg +1 -0
  70. package/BookReader/icons/playback-speed.svg +1 -0
  71. package/BookReader/icons/read-aloud.svg +1 -0
  72. package/BookReader/icons/review.svg +3 -0
  73. package/BookReader/icons/thumbnails.svg +1 -0
  74. package/BookReader/icons/voice.svg +1 -0
  75. package/BookReader/icons/volume-full.svg +1 -0
  76. package/BookReader/images/BRicons.png +0 -0
  77. package/BookReader/images/BRicons.svg +5 -0
  78. package/BookReader/images/BRicons_ia.png +0 -0
  79. package/BookReader/images/back_pages.png +0 -0
  80. package/BookReader/images/book_bottom_icon.png +0 -0
  81. package/BookReader/images/book_down_icon.png +0 -0
  82. package/BookReader/images/book_left_icon.png +0 -0
  83. package/BookReader/images/book_leftmost_icon.png +0 -0
  84. package/BookReader/images/book_right_icon.png +0 -0
  85. package/BookReader/images/book_rightmost_icon.png +0 -0
  86. package/BookReader/images/book_top_icon.png +0 -0
  87. package/BookReader/images/book_up_icon.png +0 -0
  88. package/BookReader/images/books_graphic.svg +1 -0
  89. package/BookReader/images/booksplit.png +0 -0
  90. package/BookReader/images/control_pause_icon.png +0 -0
  91. package/BookReader/images/control_play_icon.png +0 -0
  92. package/BookReader/images/embed_icon.png +0 -0
  93. package/BookReader/images/hypothesis.ico +0 -0
  94. package/BookReader/images/icon-home-ia.png +0 -0
  95. package/BookReader/images/icon_OL-logo-xs.png +0 -0
  96. package/BookReader/images/icon_alert-xs.png +0 -0
  97. package/BookReader/images/icon_book.svg +1 -0
  98. package/BookReader/images/icon_bookmark.svg +1 -0
  99. package/BookReader/images/icon_close-pop.png +0 -0
  100. package/BookReader/images/icon_download.png +0 -0
  101. package/BookReader/images/icon_experiment.svg +1 -0
  102. package/BookReader/images/icon_gear.svg +1 -0
  103. package/BookReader/images/icon_hamburger.svg +1 -0
  104. package/BookReader/images/icon_home.png +0 -0
  105. package/BookReader/images/icon_home.svg +1 -0
  106. package/BookReader/images/icon_home_ia.png +0 -0
  107. package/BookReader/images/icon_indicator.png +0 -0
  108. package/BookReader/images/icon_info.svg +1 -0
  109. package/BookReader/images/icon_one_page.svg +1 -0
  110. package/BookReader/images/icon_pause.svg +1 -0
  111. package/BookReader/images/icon_play.svg +1 -0
  112. package/BookReader/images/icon_playback-rate.svg +1 -0
  113. package/BookReader/images/icon_return.png +0 -0
  114. package/BookReader/images/icon_search_button.svg +1 -0
  115. package/BookReader/images/icon_share.svg +1 -0
  116. package/BookReader/images/icon_skip-ahead.svg +1 -0
  117. package/BookReader/images/icon_skip-back.svg +2 -0
  118. package/BookReader/images/icon_speaker.svg +1 -0
  119. package/BookReader/images/icon_speaker_open.svg +1 -0
  120. package/BookReader/images/icon_thumbnails.svg +1 -0
  121. package/BookReader/images/icon_toc.svg +1 -0
  122. package/BookReader/images/icon_two_pages.svg +1 -0
  123. package/BookReader/images/icon_zoomer.png +0 -0
  124. package/BookReader/images/loading.gif +0 -0
  125. package/BookReader/images/logo_icon.png +0 -0
  126. package/BookReader/images/marker_chap-off.png +0 -0
  127. package/BookReader/images/marker_chap-off.svg +1 -0
  128. package/BookReader/images/marker_chap-off_ia.png +0 -0
  129. package/BookReader/images/marker_chap-on.png +0 -0
  130. package/BookReader/images/marker_chap-on.svg +1 -0
  131. package/BookReader/images/marker_srch-on.svg +1 -0
  132. package/BookReader/images/marker_srchchap-off.png +0 -0
  133. package/BookReader/images/marker_srchchap-on.png +0 -0
  134. package/BookReader/images/nav_control-dn.png +0 -0
  135. package/BookReader/images/nav_control-dn_ia.png +0 -0
  136. package/BookReader/images/nav_control-up.png +0 -0
  137. package/BookReader/images/nav_control-up_ia.png +0 -0
  138. package/BookReader/images/nav_control.png +0 -0
  139. package/BookReader/images/one_page_mode_icon.png +0 -0
  140. package/BookReader/images/paper-badge.png +0 -0
  141. package/BookReader/images/print_icon.png +0 -0
  142. package/BookReader/images/progressbar.gif +0 -0
  143. package/BookReader/images/right_edges.png +0 -0
  144. package/BookReader/images/slider.png +0 -0
  145. package/BookReader/images/slider_ia.png +0 -0
  146. package/BookReader/images/thumbnail_mode_icon.png +0 -0
  147. package/BookReader/images/translate.svg +1 -0
  148. package/BookReader/images/transparent.png +0 -0
  149. package/BookReader/images/two_page_mode_icon.png +0 -0
  150. package/BookReader/images/unviewable_page.png +0 -0
  151. package/BookReader/images/zoom_in_icon.png +0 -0
  152. package/BookReader/images/zoom_out_icon.png +0 -0
  153. package/BookReader/jquery-3.js +2 -0
  154. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  155. package/BookReader/plugins/plugin.archive_analytics.js +2 -0
  156. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -0
  157. package/BookReader/plugins/plugin.autoplay.js +2 -0
  158. package/BookReader/plugins/plugin.autoplay.js.map +1 -0
  159. package/BookReader/plugins/plugin.chapters.js +26 -0
  160. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  161. package/BookReader/plugins/plugin.chapters.js.map +1 -0
  162. package/BookReader/plugins/plugin.experiments.js +3 -0
  163. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  164. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  165. package/BookReader/plugins/plugin.iframe.js +2 -0
  166. package/BookReader/plugins/plugin.iframe.js.map +1 -0
  167. package/BookReader/plugins/plugin.iiif.js +2 -0
  168. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  169. package/BookReader/plugins/plugin.resume.js +2 -0
  170. package/BookReader/plugins/plugin.resume.js.map +1 -0
  171. package/BookReader/plugins/plugin.search.js +3 -0
  172. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  173. package/BookReader/plugins/plugin.search.js.map +1 -0
  174. package/BookReader/plugins/plugin.text_selection.js +3 -0
  175. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  176. package/BookReader/plugins/plugin.text_selection.js.map +1 -0
  177. package/BookReader/plugins/plugin.translate.js +3 -0
  178. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  179. package/BookReader/plugins/plugin.translate.js.map +1 -0
  180. package/BookReader/plugins/plugin.tts.js +3 -0
  181. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +29 -0
  182. package/BookReader/plugins/plugin.tts.js.map +1 -0
  183. package/BookReader/plugins/plugin.url.js +2 -0
  184. package/BookReader/plugins/plugin.url.js.map +1 -0
  185. package/BookReader/plugins/plugin.vendor-fullscreen.js +2 -0
  186. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -0
  187. package/BookReader/plugins/translator-worker.js +2 -0
  188. package/BookReader/plugins/translator-worker.js.map +1 -0
  189. package/BookReader/translator-worker.js +475 -0
  190. package/BookReader/webcomponents-bundle.js +3 -0
  191. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  192. package/BookReader/webcomponents-bundle.js.map +1 -0
  193. package/package.json +11 -3
  194. package/src/BookNavigator/book-navigator.js +1 -0
  195. package/src/BookReader/BookModel.js +564 -0
  196. package/src/BookReader/DragScrollable.js +233 -0
  197. package/src/BookReader/ImageCache.js +149 -0
  198. package/src/BookReader/Mode1Up.js +110 -0
  199. package/src/BookReader/Mode1UpLit.js +393 -0
  200. package/src/BookReader/Mode2Up.js +107 -0
  201. package/src/BookReader/Mode2UpLit.js +787 -0
  202. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  203. package/src/BookReader/ModeSmoothZoom.js +312 -0
  204. package/src/BookReader/ModeThumb.js +344 -0
  205. package/src/BookReader/Navbar/Navbar.js +416 -0
  206. package/src/BookReader/PageContainer.js +172 -0
  207. package/src/BookReader/ReduceSet.js +26 -0
  208. package/src/BookReader/Toolbar/Toolbar.js +362 -0
  209. package/src/BookReader/events.js +19 -0
  210. package/src/BookReader/options.js +387 -0
  211. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  212. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  213. package/src/BookReader/utils/SelectionObserver.js +45 -0
  214. package/src/BookReader/utils/classes.js +36 -0
  215. package/src/BookReader/utils.js +313 -0
  216. package/src/BookReader.js +22 -139
  217. package/src/assets/images/icon_experiment.svg +1 -0
  218. package/src/assets/images/translate.svg +1 -0
  219. package/src/css/_BRnav.scss +0 -24
  220. package/src/css/_BRsearch.scss +0 -5
  221. package/src/css/_TextSelection.scss +32 -1
  222. package/src/plugins/plugin.experiments.js +34 -9
  223. package/src/plugins/plugin.text_selection.js +8 -20
  224. package/src/plugins/translate/TranslationManager.js +167 -0
  225. package/src/plugins/translate/plugin.translate.js +414 -0
  226. package/src/plugins/tts/utils.js +9 -20
  227. package/src/util/cache.js +20 -0
  228. package/.eslintrc.cjs +0 -51
  229. package/.gitattributes +0 -2
  230. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  231. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  232. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  233. package/.github/workflows/node.js.yml +0 -102
  234. package/.github/workflows/npm-publish.yml +0 -23
  235. package/.testcaferc.cjs +0 -10
  236. package/BookReaderDemo/BookReaderDemo.css +0 -40
  237. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -112
  238. package/BookReaderDemo/BookReaderJSSimple.js +0 -56
  239. package/BookReaderDemo/IADemoBr.js +0 -149
  240. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  241. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  242. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  243. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  244. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  245. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  246. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  247. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  248. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  249. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  250. package/BookReaderDemo/demo-advanced.html +0 -33
  251. package/BookReaderDemo/demo-embed-iframe-src.html +0 -85
  252. package/BookReaderDemo/demo-embed.html +0 -26
  253. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -34
  254. package/BookReaderDemo/demo-fullscreen.html +0 -31
  255. package/BookReaderDemo/demo-iiif.html +0 -121
  256. package/BookReaderDemo/demo-internetarchive.html +0 -271
  257. package/BookReaderDemo/demo-multiple.html +0 -44
  258. package/BookReaderDemo/demo-preview-pages.html +0 -1093
  259. package/BookReaderDemo/demo-simple.html +0 -35
  260. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -34
  261. package/BookReaderDemo/ia-multiple-volumes-manifest.js +0 -169
  262. package/BookReaderDemo/immersion-1up.html +0 -64
  263. package/BookReaderDemo/immersion-mode.html +0 -33
  264. package/BookReaderDemo/toggle_controls.html +0 -54
  265. package/BookReaderDemo/view_mode.html +0 -40
  266. package/BookReaderDemo/viewmode-cycle.html +0 -40
  267. package/CHANGELOG.md +0 -1087
  268. package/CONTRIBUTING.md +0 -7
  269. package/babel.config.cjs +0 -20
  270. package/codecov.yml +0 -23
  271. package/index.html +0 -34
  272. package/netlify.toml +0 -9
  273. package/renovate.json +0 -52
  274. package/screenshot.png +0 -0
  275. package/scripts/postversion.js +0 -11
  276. package/scripts/preversion.js +0 -15
  277. package/scripts/version.js +0 -24
  278. package/tests/e2e/README.md +0 -112
  279. package/tests/e2e/autoplay.test.js +0 -16
  280. package/tests/e2e/base.test.js +0 -27
  281. package/tests/e2e/helpers/base.js +0 -263
  282. package/tests/e2e/helpers/debug.js +0 -13
  283. package/tests/e2e/helpers/mockSearch.js +0 -90
  284. package/tests/e2e/helpers/params.js +0 -17
  285. package/tests/e2e/helpers/rightToLeft.js +0 -23
  286. package/tests/e2e/helpers/search.js +0 -73
  287. package/tests/e2e/models/BookReader.js +0 -11
  288. package/tests/e2e/models/Navigation.js +0 -39
  289. package/tests/e2e/rightToLeft.test.js +0 -19
  290. package/tests/e2e/viewmode.test.js +0 -44
  291. package/tests/jest/BookNavigator/book-navigator.test.js +0 -653
  292. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +0 -43
  293. package/tests/jest/BookNavigator/bookmarks/bookmark-edit.test.js +0 -132
  294. package/tests/jest/BookNavigator/bookmarks/bookmarks-list.test.js +0 -221
  295. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +0 -45
  296. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +0 -67
  297. package/tests/jest/BookNavigator/downloads/downloads.test.js +0 -53
  298. package/tests/jest/BookNavigator/search/search-provider.test.js +0 -179
  299. package/tests/jest/BookNavigator/search/search-results.test.js +0 -289
  300. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +0 -49
  301. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +0 -80
  302. package/tests/jest/BookNavigator/visual-adjustments.test.js +0 -200
  303. package/tests/jest/BookReader.keyboard.test.js +0 -190
  304. package/tests/jest/BookReader.options.test.js +0 -47
  305. package/tests/jest/BookReader.test.js +0 -316
  306. package/tests/jest/plugins/plugin.archive_analytics.test.js +0 -20
  307. package/tests/jest/plugins/plugin.autoplay.test.js +0 -35
  308. package/tests/jest/plugins/plugin.chapters.test.js +0 -193
  309. package/tests/jest/plugins/plugin.iframe.test.js +0 -42
  310. package/tests/jest/plugins/plugin.resume.test.js +0 -85
  311. package/tests/jest/plugins/plugin.text_selection.test.js +0 -447
  312. package/tests/jest/plugins/plugin.vendor-fullscreen.test.js +0 -65
  313. package/tests/jest/plugins/search/plugin.search.test.js +0 -120
  314. package/tests/jest/plugins/search/plugin.search.view.test.js +0 -131
  315. package/tests/jest/plugins/search/utils.js +0 -25
  316. package/tests/jest/plugins/search/utils.test.js +0 -29
  317. package/tests/jest/plugins/tts/AbstractTTSEngine.test.js +0 -173
  318. package/tests/jest/plugins/tts/FestivalTTSEngine.test.js +0 -59
  319. package/tests/jest/plugins/tts/PageChunk.test.js +0 -57
  320. package/tests/jest/plugins/tts/PageChunkIterator.test.js +0 -179
  321. package/tests/jest/plugins/tts/WebTTSEngine.test.js +0 -178
  322. package/tests/jest/plugins/tts/utils.test.js +0 -74
  323. package/tests/jest/plugins/url/UrlPlugin.test.js +0 -198
  324. package/tests/jest/plugins/url/plugin.url.test.js +0 -168
  325. package/tests/jest/setup.js +0 -3
  326. package/tests/jest/util/browserSniffing.test.js +0 -62
  327. package/tests/jest/util/docCookies.test.js +0 -24
  328. package/tests/jest/util/strings.test.js +0 -63
  329. package/tests/jest/utils.js +0 -83
  330. package/webpack.config.js +0 -97
@@ -21,6 +21,9 @@ class ExperimentModel {
21
21
  /** @type {string} */
22
22
  learnMore;
23
23
 
24
+ /** @type {import("@/src/BookReader.js").default} */
25
+ br;
26
+
24
27
  assetRoot = '/BookReader/';
25
28
 
26
29
  enabledLoading = false;
@@ -46,10 +49,32 @@ export class ExperimentsPlugin extends BookReaderPlugin {
46
49
 
47
50
  /** Where the state of this plugin is saved in localStorage */
48
51
  localStorageKey: 'BrExperiments',
52
+
53
+ /** The experiments that should be shown in the experiments panel */
54
+ enabledExperiments: ['translate'],
49
55
  }
50
56
 
51
57
  /** @type {ExperimentModel[]} */
52
- experiments = [
58
+ allExperiments = [
59
+ new class extends ExperimentModel {
60
+ name = 'translate';
61
+ title = 'Translate Plugin';
62
+ description = "Translate books directly in your browser.";
63
+ learnMore = 'https://mozilla.github.io/translations/';
64
+ icon = 'images/translate.svg';
65
+ enabled = false;
66
+ async enable({ manual = false}) {
67
+ await importAsScript(this.buildAssetPath('plugins/plugin.translate.js'));
68
+ this.br.initializePlugin('translate');
69
+ }
70
+ async disable() {
71
+ // need to reload to remove translate plugin script
72
+ // Sleep so that the event loop can finish processing before the reload
73
+ sleep(0).then(() => {
74
+ window.location.reload();
75
+ });
76
+ }
77
+ }(),
53
78
  new class extends ExperimentModel {
54
79
  name = 'hypothesis';
55
80
  title = 'Hypothes.is';
@@ -93,10 +118,11 @@ export class ExperimentsPlugin extends BookReaderPlugin {
93
118
  return;
94
119
  }
95
120
 
96
- for (const experiment of this.experiments) {
121
+ for (const experiment of this.allExperiments) {
97
122
  // TODO: imagesBaseURL should be replaced with assetRoot everywhere
98
123
  experiment.assetRoot = this.br.options.imagesBaseURL.replace(/images\/$/, '');
99
124
  experiment.icon = experiment.buildAssetPath(experiment.icon);
125
+ experiment.br = this.br;
100
126
  }
101
127
 
102
128
  this._loadExperimentStates();
@@ -106,7 +132,7 @@ export class ExperimentsPlugin extends BookReaderPlugin {
106
132
 
107
133
  _loadExperimentStates() {
108
134
  const savedStates = JSON.parse(localStorage.getItem(this.options.localStorageKey) || '{}');
109
- this.experiments.forEach(experiment => {
135
+ this.allExperiments.forEach(experiment => {
110
136
  if (savedStates[experiment.name] !== undefined) {
111
137
  experiment.enabled = savedStates[experiment.name];
112
138
  if (experiment.enabled) {
@@ -118,7 +144,7 @@ export class ExperimentsPlugin extends BookReaderPlugin {
118
144
 
119
145
  _saveExperimentStates() {
120
146
  const states = Object.fromEntries(
121
- this.experiments.map(experiment => [experiment.name, experiment.enabled]),
147
+ this.allExperiments.map(experiment => [experiment.name, experiment.enabled]),
122
148
  );
123
149
  localStorage.setItem(this.options.localStorageKey, JSON.stringify(states));
124
150
  }
@@ -145,13 +171,12 @@ export class ExperimentsPlugin extends BookReaderPlugin {
145
171
  _render() {
146
172
  this.br.shell.menuProviders['experiments'] = {
147
173
  id: 'experiments',
148
- // https://icon-sets.iconify.design/hugeicons/?icon-filter=eco-lab-02&query=lab
149
174
  icon: html`
150
- <svg xmlns="http://www.w3.org/2000/svg" width="34" viewBox="0 0 24 24"><path fill="currentColor" d="M10 5.75h1.25v2.5H9.5c-.41 0-.75.34-.75.75s.34.75.75.75h.25v1.96A5.72 5.72 0 0 0 6.25 17c0 3.17 2.58 5.75 5.75 5.75s5.75-2.58 5.75-5.75c0-2.33-1.39-4.4-3.5-5.29V9.75h.25c.41 0 .75-.34.75-.75s-.34-.75-.75-.75h-1.75v-1.5H14c1.52 0 2.75-1.23 2.75-2.75V3c0-.41-.34-.75-.75-.75h-2c-.579 0-1.115.178-1.558.483A2.75 2.75 0 0 0 10 1.25H8c-.41 0-.75.34-.75.75v1c0 1.52 1.23 2.75 2.75 2.75m2.75-.5V5c0-.69.56-1.25 1.25-1.25h1.25V4c0 .69-.56 1.25-1.25 1.25zm-1.5 6.98V9.75h1.5v2.48c0 .33.22.62.53.72c1.77.56 2.97 2.19 2.97 4.06A4.26 4.26 0 0 1 12 21.26a4.26 4.26 0 0 1-4.25-4.25c0-1.87 1.19-3.5 2.97-4.06c.32-.1.53-.39.53-.72m-2.5-9.48H10c.69 0 1.25.56 1.25 1.25v.25H10c-.69 0-1.25-.56-1.25-1.25z" color="currentColor"/></svg>
175
+ <img src="${this.br.options.imagesBaseURL}/icon_experiment.svg" width="26"/>
151
176
  `,
152
177
  label: 'Experiments',
153
178
  component: html`<br-experiments-panel
154
- .experiments="${this.experiments}"
179
+ .experiments="${this.allExperiments.filter(experiment => this.options.enabledExperiments.includes(experiment.name))}"
155
180
  @connected="${e => this._panel = e.target}"
156
181
  @toggle="${async e => {
157
182
  await this._toggleExperiment(e.detail.experiment, e.detail.enabled);
@@ -240,14 +265,14 @@ export class BrExperimentToggle extends LitElement {
240
265
 
241
266
  render() {
242
267
  return html`
243
- <div class="experiment-card">
268
+ <div class="experiment-card" style="margin-bottom: 10px;">
244
269
  <div style="display: flex; align-items: center; gap: 10px;">
245
270
  <img src="${this.icon}" style="width: 20px; height: 20px;" alt="" />
246
271
  <div style="flex-grow: 1; font-weight: bold;">${this.title}</div>
247
272
  </div>
248
273
  <p style="opacity: 0.9">
249
274
  ${this.description}
250
- <a href="${this.learnMore}" target="_blank">Learn more</a>.
275
+ ${this.learnMore ? html`<a href="${this.learnMore}" target="_blank">Learn more</a>.` : ''}
251
276
  </p>
252
277
  <div style="display: flex">
253
278
  <div style="flex-grow: 1;"></div>
@@ -3,31 +3,12 @@ import { createDIVPageLayer } from '../BookReader/PageContainer.js';
3
3
  import { SelectionObserver } from '../BookReader/utils/SelectionObserver.js';
4
4
  import { BookReaderPlugin } from '../BookReaderPlugin.js';
5
5
  import { applyVariables } from '../util/strings.js';
6
+ import { Cache } from '../util/cache.js';
6
7
  /** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */
7
8
  /** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */
8
9
 
9
10
  const BookReader = /** @type {typeof import('../BookReader').default} */(window.BookReader);
10
11
 
11
- /**
12
- * @template T
13
- */
14
- export class Cache {
15
- constructor(maxSize = 10) {
16
- this.maxSize = maxSize;
17
- /** @type {T[]} */
18
- this.entries = [];
19
- }
20
-
21
- /**
22
- * @param {T} entry
23
- */
24
- add(entry) {
25
- if (this.entries.length >= this.maxSize) {
26
- this.entries.shift();
27
- }
28
- this.entries.push(entry);
29
- }
30
- }
31
12
 
32
13
  export class TextSelectionPlugin extends BookReaderPlugin {
33
14
  options = {
@@ -327,6 +308,9 @@ export class TextSelectionPlugin extends BookReaderPlugin {
327
308
  }
328
309
 
329
310
  const textLayer = createDIVPageLayer(pageContainer.page, 'BRtextLayer');
311
+ // Have to wait to make sure the page container is actually rendered,
312
+ // otherwise width/height are unset after a mode change.
313
+ await Promise.resolve();
330
314
  const ratioW = parseFloat(pageContainer.$container[0].style.width) / pageContainer.page.width;
331
315
  const ratioH = parseFloat(pageContainer.$container[0].style.height) / pageContainer.page.height;
332
316
  textLayer.style.transform = `scale(${ratioW}, ${ratioH})`;
@@ -356,6 +340,10 @@ export class TextSelectionPlugin extends BookReaderPlugin {
356
340
  }
357
341
  $container.append(textLayer);
358
342
  this.stopPageFlip($container);
343
+ this.br.trigger('textLayerRendered', {
344
+ pageIndex,
345
+ pageContainer,
346
+ });
359
347
  }
360
348
 
361
349
  /**
@@ -0,0 +1,167 @@
1
+ // @ts-check
2
+ import { Cache } from '../../util/cache.js';
3
+ import { BatchTranslator } from '@internetarchive/bergamot-translator/translator.js';
4
+
5
+ export const langs = /** @type {{[lang: string]: string}} */ {
6
+ "bg": "Bulgarian",
7
+ "ca": "Catalan",
8
+ "cs": "Czech",
9
+ "nl": "Dutch",
10
+ "en": "English",
11
+ "et": "Estonian",
12
+ "de": "German",
13
+ "fr": "French",
14
+ "is": "Icelandic",
15
+ "it": "Italian",
16
+ "nb": "Norwegian Bokmål",
17
+ "nn": "Norwegian Nynorsk",
18
+ "fa": "Persian",
19
+ "pl": "Polish",
20
+ "pt": "Portuguese",
21
+ "ru": "Russian",
22
+ "es": "Spanish",
23
+ "uk": "Ukrainian",
24
+ };
25
+
26
+ export class TranslationManager {
27
+ /** @type {Cache<{index: string, response: string}>} */
28
+ alreadyTranslated = new Cache(100);
29
+
30
+ /**
31
+ * @typedef {Object} genericModelInfo
32
+ * @property {string} name
33
+ * @property {number} size
34
+ * @property {number} estimatedCompressedSize
35
+ * @property {any} [qualityModel]
36
+ * @property {string} [expectedSha256Hash]
37
+ * @property {string} [modelType]
38
+ */
39
+ /**
40
+ * @type { {[langPair: string] : {model: genericModelInfo, lex: genericModelInfo, vocab: genericModelInfo, quality?: genericModelInfo}} }
41
+ */
42
+ modelRegistry = {};
43
+
44
+ /** @type {Record<key, {promise: Promise<string>, resolve: function, reject: function}>} */
45
+ currentlyTranslating = {}
46
+
47
+ /** @type {Record<string, string>[]} */
48
+ fromLanguages = [];
49
+ /** @type {Record<string, string>[]} */
50
+ toLanguages = [];
51
+
52
+ /** @type {boolean} */
53
+ active = false;
54
+
55
+ publicPath = '';
56
+
57
+ constructor() {
58
+ //TODO Should default to the book language as the first element
59
+ const enModel = {code: "en", name: "English", type: "prod"};
60
+ this.fromLanguages.push(enModel);
61
+ this.toLanguages.push(enModel);
62
+ }
63
+
64
+
65
+ async initWorker() {
66
+ if (this.initPromise) return this.initPromise;
67
+ this.initPromise = new Promise((resolve, reject) => {
68
+ this._initResolve = resolve;
69
+ this._initReject = reject;
70
+ });
71
+ const registryUrl = "https://cors.archive.org/cors/mozilla-translate-models/";
72
+ const registryJson = await fetch(registryUrl + "registry.json").then(r => r.json());
73
+ for (const language of Object.values(registryJson)) {
74
+ for (const file of Object.values(language)) {
75
+ file.name = registryUrl + file.name;
76
+ }
77
+ }
78
+
79
+ /** @type {BatchTranslator} */
80
+ // Arbitrary setting for number of workers, 1 is already quite fast
81
+ // batchSize from 8 -> 4 for improved performance
82
+ this.translator = new BatchTranslator({
83
+ registryUrl: `data:application/json,${encodeURIComponent(JSON.stringify(registryJson))}`,
84
+ workers: 2,
85
+ batchSize: 4,
86
+ workerUrl: this.publicPath + '/translator-worker.js',
87
+ });
88
+
89
+ const modelType = await this.translator.backing.registry;
90
+ const arr = {}; // unsure if we need to keep track of the files
91
+ for (const obj of Object.values(modelType)) {
92
+ const firstLang = obj['from'];
93
+ const secondLang = obj['to'];
94
+ const fromModelType = obj['files'];
95
+ arr[`${firstLang}${secondLang}`] = fromModelType;
96
+ // Assuming that all of the languages loaded from the registryUrl inside @internetarchive/bergamot-translator/translator.js are prod
97
+ // List of dev models found here https://github.com/mozilla/firefox-translations-models/tree/main/models/base
98
+ // There are also differences between the model types in the repo above here: https://github.com/mozilla/firefox-translations-models?tab=readme-ov-file#firefox-translations-models
99
+ if (firstLang !== "en") {
100
+ this.fromLanguages.push({code: firstLang, name:langs[firstLang], type: "prod"});
101
+ }
102
+ if (secondLang !== "en") {
103
+ this.toLanguages.push({code: secondLang, name:langs[secondLang], type: "prod"});
104
+ }
105
+ }
106
+ this._initResolve([this.modelRegistry]);
107
+ return this.initPromise;
108
+ }
109
+
110
+ /**
111
+ * Targets the page and paragraph of a text layer to create a translation from the "fromLang" to the "toLang". Tries to force order in translation by using the pageIndex (+1000 if the current page is not visible) and paragraphIndex
112
+ * @param {string} fromLang
113
+ * @param {string} toLang
114
+ * @param {string} pageIndex
115
+ * @param {number} paragraphIndex
116
+ * @param {string} text
117
+ * @param {number} priority
118
+ * @return {Promise<string>} translated text
119
+ */
120
+
121
+ getTranslation = async (fromLang, toLang, pageIndex, paragraphIndex, text, priority) => {
122
+ this.active = true;
123
+ if (fromLang == toLang || !fromLang || !toLang) {
124
+ return;
125
+ }
126
+ const key = `${fromLang}${toLang}-${pageIndex}:${paragraphIndex}`;
127
+ const cachedEntry = this.alreadyTranslated.entries.find(x => x.index == key);
128
+
129
+ if (cachedEntry) {
130
+ return cachedEntry.response;
131
+ }
132
+
133
+ if (key in this.currentlyTranslating) {
134
+ return this.currentlyTranslating[key].promise;
135
+ }
136
+
137
+ let _resolve = null;
138
+ let _reject = null;
139
+ const promise = new Promise((res, rej) => {
140
+ _resolve = res;
141
+ _reject = rej;
142
+ });
143
+
144
+ this.currentlyTranslating[key] = {
145
+ promise,
146
+ resolve: _resolve,
147
+ reject: _reject,
148
+ };
149
+
150
+ if (!text) {
151
+ this.currentlyTranslating[key].reject("No text was provided");
152
+ return promise;
153
+ }
154
+ this.translator.translate({
155
+ to: toLang,
156
+ from: fromLang,
157
+ text: text,
158
+ html: false,
159
+ priority: priority,
160
+ }).then((resp) => {
161
+ const response = resp;
162
+ this.currentlyTranslating[key].resolve(response.target.text);
163
+ });
164
+
165
+ return promise;
166
+ }
167
+ }