@internetarchive/bookreader 5.0.0-11 → 5.0.0-110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +604 -1239
  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 +1907 -0
  53. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  54. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  55. package/BookReader/icons/1up.svg +1 -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/slider-toggle.svg +1 -0
  74. package/BookReader/icons/thumbnails.svg +1 -1
  75. package/BookReader/icons/voice.svg +1 -0
  76. package/BookReader/icons/volume-full.svg +1 -1
  77. package/BookReader/images/BRicons.svg +3 -3
  78. package/BookReader/images/books_graphic.svg +1 -1
  79. package/BookReader/images/hypothesis.ico +0 -0
  80. package/BookReader/images/icon_book.svg +1 -1
  81. package/BookReader/images/icon_bookmark.svg +1 -1
  82. package/BookReader/images/icon_experiment.svg +1 -0
  83. package/BookReader/images/icon_gear.svg +1 -1
  84. package/BookReader/images/icon_hamburger.svg +1 -1
  85. package/BookReader/images/icon_home.svg +1 -1
  86. package/BookReader/images/icon_info.svg +1 -1
  87. package/BookReader/images/icon_one_page.svg +1 -1
  88. package/BookReader/images/icon_pause.svg +1 -1
  89. package/BookReader/images/icon_play.svg +1 -1
  90. package/BookReader/images/icon_playback-rate.svg +1 -1
  91. package/BookReader/images/icon_search_button.svg +1 -1
  92. package/BookReader/images/icon_share.svg +1 -1
  93. package/BookReader/images/icon_skip-ahead.svg +1 -1
  94. package/BookReader/images/icon_skip-back.svg +1 -1
  95. package/BookReader/images/icon_speaker.svg +1 -1
  96. package/BookReader/images/icon_speaker_open.svg +1 -1
  97. package/BookReader/images/icon_thumbnails.svg +1 -1
  98. package/BookReader/images/icon_toc.svg +1 -1
  99. package/BookReader/images/icon_two_pages.svg +1 -1
  100. package/BookReader/images/marker_chap-off.svg +1 -1
  101. package/BookReader/images/marker_chap-on.svg +1 -1
  102. package/BookReader/images/marker_srch-on.svg +1 -1
  103. package/BookReader/images/translate.svg +1 -0
  104. package/BookReader/images/unviewable_page.png +0 -0
  105. package/BookReader/jquery-3.js +2 -0
  106. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  107. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  108. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js +1 -1
  110. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  111. package/BookReader/plugins/plugin.chapters.js +22 -1
  112. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  113. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  114. package/BookReader/plugins/plugin.experiments.js +3 -0
  115. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  116. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  117. package/BookReader/plugins/plugin.iframe.js +1 -1
  118. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  119. package/BookReader/plugins/plugin.iiif.js +2 -0
  120. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  121. package/BookReader/plugins/plugin.resume.js +1 -1
  122. package/BookReader/plugins/plugin.resume.js.map +1 -1
  123. package/BookReader/plugins/plugin.search.js +2 -1
  124. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  125. package/BookReader/plugins/plugin.search.js.map +1 -1
  126. package/BookReader/plugins/plugin.text_selection.js +2 -1
  127. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  128. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  129. package/BookReader/plugins/plugin.translate.js +137 -0
  130. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  131. package/BookReader/plugins/plugin.translate.js.map +1 -0
  132. package/BookReader/plugins/plugin.tts.js +1 -1
  133. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  134. package/BookReader/plugins/plugin.tts.js.map +1 -1
  135. package/BookReader/plugins/plugin.url.js +1 -1
  136. package/BookReader/plugins/plugin.url.js.map +1 -1
  137. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  138. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  139. package/BookReader/plugins/translator-worker.js +2 -0
  140. package/BookReader/plugins/translator-worker.js.map +1 -0
  141. package/BookReader/silence.mp3 +0 -0
  142. package/BookReader/translator-worker.js +475 -0
  143. package/BookReader/webcomponents-bundle.js +3 -0
  144. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  145. package/BookReader/webcomponents-bundle.js.map +1 -0
  146. package/README.md +14 -3
  147. package/jsconfig.json +19 -0
  148. package/package.json +92 -70
  149. package/src/BookReader/BookModel.js +92 -46
  150. package/src/BookReader/DragScrollable.js +233 -0
  151. package/src/BookReader/ImageCache.js +49 -16
  152. package/src/BookReader/Mode1Up.js +66 -365
  153. package/src/BookReader/Mode1UpLit.js +392 -0
  154. package/src/BookReader/Mode2Up.js +87 -1315
  155. package/src/BookReader/Mode2UpLit.js +788 -0
  156. package/src/BookReader/ModeAbstract.js +43 -0
  157. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  158. package/src/BookReader/ModeSmoothZoom.js +312 -0
  159. package/src/BookReader/ModeThumb.js +29 -15
  160. package/src/BookReader/Navbar/Navbar.js +201 -76
  161. package/src/BookReader/PageContainer.js +120 -23
  162. package/src/BookReader/ReduceSet.js +2 -2
  163. package/src/BookReader/Toolbar/Toolbar.js +18 -40
  164. package/src/BookReader/events.js +3 -3
  165. package/src/BookReader/options.js +94 -17
  166. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  167. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  168. package/src/BookReader/utils/SelectionObserver.js +45 -0
  169. package/src/BookReader/utils/classes.js +1 -1
  170. package/src/BookReader/utils.js +136 -12
  171. package/src/BookReader.js +678 -1226
  172. package/src/BookReaderPlugin.js +52 -0
  173. package/src/assets/icons/magnify-minus.svg +3 -7
  174. package/src/assets/icons/magnify-plus.svg +3 -7
  175. package/src/assets/icons/slider-toggle.svg +1 -0
  176. package/src/assets/icons/voice.svg +1 -0
  177. package/src/assets/images/hypothesis.ico +0 -0
  178. package/src/assets/images/icon_experiment.svg +1 -0
  179. package/src/assets/images/translate.svg +1 -0
  180. package/src/assets/images/unviewable_page.png +0 -0
  181. package/src/assets/silence.mp3 +0 -0
  182. package/src/css/BookReader.scss +1 -5
  183. package/src/css/_BRBookmarks.scss +1 -1
  184. package/src/css/_BRComponent.scss +1 -1
  185. package/src/css/_BRicon.scss +8 -2
  186. package/src/css/_BRmain.scss +16 -3
  187. package/src/css/_BRnav.scss +74 -70
  188. package/src/css/_BRpages.scss +171 -42
  189. package/src/css/_BRsearch.scss +69 -30
  190. package/src/css/_BRtoolbar.scss +5 -5
  191. package/src/css/_TextSelection.scss +129 -24
  192. package/src/css/_colorbox.scss +2 -2
  193. package/src/css/_controls.scss +24 -7
  194. package/src/css/_icons.scss +8 -1
  195. package/src/{BookNavigator/assets → css}/button-base.js +2 -2
  196. package/src/css/icon_checkmark.js +9 -0
  197. package/src/css/sharedStyles.js +15 -0
  198. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  199. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +25 -5
  200. package/src/ia-bookreader/ia-bookreader.js +666 -0
  201. package/src/ia-bookreader/sharing.js +27 -0
  202. package/src/ia-bookreader/viewable-files.js +98 -0
  203. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  204. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  205. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  206. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  207. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +43 -31
  208. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  209. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +3 -3
  210. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  211. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  212. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  213. package/src/plugins/plugin.archive_analytics.js +84 -78
  214. package/src/plugins/plugin.autoplay.js +99 -104
  215. package/src/plugins/plugin.chapters.js +314 -205
  216. package/src/plugins/plugin.experiments.js +321 -0
  217. package/src/plugins/plugin.iframe.js +1 -1
  218. package/src/plugins/plugin.iiif.js +141 -0
  219. package/src/plugins/plugin.resume.js +54 -51
  220. package/src/plugins/plugin.text_selection.js +522 -219
  221. package/src/plugins/plugin.vendor-fullscreen.js +5 -5
  222. package/src/plugins/search/plugin.search.js +374 -392
  223. package/src/{BookNavigator → plugins}/search/search-provider.js +59 -27
  224. package/src/{BookNavigator → plugins}/search/search-results.js +105 -76
  225. package/src/plugins/search/utils.js +50 -0
  226. package/src/plugins/search/view.js +50 -68
  227. package/src/plugins/translate/TranslationManager.js +164 -0
  228. package/src/plugins/translate/plugin.translate.js +512 -0
  229. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  230. package/src/plugins/tts/FestivalTTSEngine.js +20 -30
  231. package/src/plugins/tts/PageChunk.js +33 -21
  232. package/src/plugins/tts/PageChunkIterator.js +11 -17
  233. package/src/plugins/tts/WebTTSEngine.js +131 -91
  234. package/src/plugins/tts/plugin.tts.js +345 -350
  235. package/src/plugins/tts/utils.js +77 -49
  236. package/src/plugins/url/UrlPlugin.js +191 -0
  237. package/src/plugins/{plugin.url.js → url/plugin.url.js} +44 -15
  238. package/src/util/TextSelectionManager.js +282 -0
  239. package/src/util/browserSniffing.js +33 -1
  240. package/src/util/cache.js +20 -0
  241. package/src/util/docCookies.js +21 -2
  242. package/src/util/lit.js +15 -0
  243. package/src/util/strings.js +1 -0
  244. package/.babelrc +0 -12
  245. package/.dependabot/config.yml +0 -6
  246. package/.eslintrc.js +0 -50
  247. package/.gitattributes +0 -2
  248. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  249. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  250. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  251. package/.github/workflows/node.js.yml +0 -37
  252. package/.github/workflows/npm-publish.yml +0 -47
  253. package/.testcaferc.json +0 -5
  254. package/BookReader/bookreader-component-bundle.js +0 -1450
  255. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  256. package/BookReader/bookreader-component-bundle.js.map +0 -1
  257. package/BookReader/jquery-1.10.1.js +0 -2
  258. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  259. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  260. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  261. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  262. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  263. package/BookReaderDemo/BookReaderDemo.css +0 -41
  264. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  265. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  266. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  267. package/BookReaderDemo/IIIFBookReader.js +0 -207
  268. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  269. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  270. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  273. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  274. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  275. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  276. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  277. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  278. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  279. package/BookReaderDemo/demo-advanced.html +0 -33
  280. package/BookReaderDemo/demo-autoplay.html +0 -38
  281. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  282. package/BookReaderDemo/demo-embed.html +0 -26
  283. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  284. package/BookReaderDemo/demo-fullscreen.html +0 -33
  285. package/BookReaderDemo/demo-iiif.html +0 -34
  286. package/BookReaderDemo/demo-iiif.js +0 -26
  287. package/BookReaderDemo/demo-internetarchive.html +0 -74
  288. package/BookReaderDemo/demo-multiple.html +0 -43
  289. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  290. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  291. package/BookReaderDemo/demo-simple.html +0 -34
  292. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  293. package/BookReaderDemo/immersion-1up.html +0 -64
  294. package/BookReaderDemo/immersion-mode.html +0 -35
  295. package/BookReaderDemo/toggle_controls.html +0 -53
  296. package/BookReaderDemo/view_mode.html +0 -39
  297. package/BookReaderDemo/viewmode-cycle.html +0 -41
  298. package/CHANGELOG.md +0 -495
  299. package/CONTRIBUTING.md +0 -7
  300. package/codecov.yml +0 -17
  301. package/index.html +0 -31
  302. package/karma.conf.js +0 -23
  303. package/screenshot.png +0 -0
  304. package/scripts/postversion.js +0 -10
  305. package/scripts/preversion.js +0 -14
  306. package/scripts/version.js +0 -26
  307. package/src/BookNavigator/BookModel.js +0 -14
  308. package/src/BookNavigator/BookNavigator.js +0 -446
  309. package/src/BookNavigator/assets/book-loader.js +0 -27
  310. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  311. package/src/BookNavigator/assets/icon_close.js +0 -3
  312. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  313. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  314. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  315. package/src/BookNavigator/search/a-search-result.js +0 -55
  316. package/src/BookReader/DebugConsole.js +0 -54
  317. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  318. package/src/ItemNavigator/ItemNavigator.js +0 -376
  319. package/src/ItemNavigator/providers/sharing.js +0 -29
  320. package/src/css/_MobileNav.scss +0 -194
  321. package/src/dragscrollable-br.js +0 -261
  322. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  323. package/src/plugins/plugin.mobile_nav.js +0 -287
  324. package/tests/BookReader/BookModel.test.js +0 -312
  325. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  326. package/tests/BookReader/DebugConsole.test.js +0 -25
  327. package/tests/BookReader/ImageCache.test.js +0 -150
  328. package/tests/BookReader/Mode1Up.test.js +0 -164
  329. package/tests/BookReader/Mode2Up.test.js +0 -247
  330. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  331. package/tests/BookReader/PageContainer.test.js +0 -115
  332. package/tests/BookReader/ReduceSet.test.js +0 -38
  333. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  334. package/tests/BookReader/utils/classes.test.js +0 -88
  335. package/tests/BookReader/utils.test.js +0 -109
  336. package/tests/BookReader.options.test.js +0 -39
  337. package/tests/BookReader.test.js +0 -301
  338. package/tests/e2e/README.md +0 -75
  339. package/tests/e2e/autoplay.test.js +0 -13
  340. package/tests/e2e/base.test.js +0 -35
  341. package/tests/e2e/helpers/base.js +0 -263
  342. package/tests/e2e/helpers/debug.js +0 -13
  343. package/tests/e2e/helpers/desktopSearch.js +0 -72
  344. package/tests/e2e/helpers/mobileSearch.js +0 -85
  345. package/tests/e2e/helpers/mockSearch.js +0 -93
  346. package/tests/e2e/helpers/rightToLeft.js +0 -29
  347. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  348. package/tests/e2e/models/BookReader.js +0 -11
  349. package/tests/e2e/models/Navigation.js +0 -56
  350. package/tests/e2e/rightToLeft.test.js +0 -20
  351. package/tests/e2e/viewmode.test.js +0 -37
  352. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  353. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  354. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  355. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  356. package/tests/karma/BookNavigator/search/search-results.test.js +0 -240
  357. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  358. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  359. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  360. package/tests/plugins/plugin.autoplay.test.js +0 -52
  361. package/tests/plugins/plugin.chapters.test.js +0 -130
  362. package/tests/plugins/plugin.iframe.test.js +0 -42
  363. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  364. package/tests/plugins/plugin.resume.test.js +0 -98
  365. package/tests/plugins/plugin.text_selection.test.js +0 -203
  366. package/tests/plugins/plugin.url.test.js +0 -129
  367. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  368. package/tests/plugins/search/plugin.search.test.js +0 -173
  369. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  370. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  371. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  372. package/tests/plugins/tts/PageChunk.test.js +0 -57
  373. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  374. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  375. package/tests/plugins/tts/utils.test.js +0 -133
  376. package/tests/util/browserSniffing.test.js +0 -56
  377. package/tests/util/docCookies.test.js +0 -15
  378. package/tests/util/strings.test.js +0 -63
  379. package/tests/utils.js +0 -42
  380. package/webpack.config.js +0 -86
@@ -0,0 +1,788 @@
1
+ // @ts-check
2
+ import { customElement, property, query } from 'lit/decorators.js';
3
+ import {LitElement, html} from 'lit';
4
+ import { styleMap } from 'lit/directives/style-map.js';
5
+ import { ModeSmoothZoom } from './ModeSmoothZoom.js';
6
+ import { arrChanged, promisifyEvent } from './utils.js';
7
+ import { HTMLDimensionsCacher } from "./utils/HTMLDimensionsCacher.js";
8
+ import { PageModel } from './BookModel.js';
9
+ import { ModeCoordinateSpace } from './ModeCoordinateSpace.js';
10
+ /** @typedef {import('./BookModel').BookModel} BookModel */
11
+ /** @typedef {import('./BookModel').PageIndex} PageIndex */
12
+ /** @typedef {import('./ModeSmoothZoom').SmoothZoomable} SmoothZoomable */
13
+ /** @typedef {import('./PageContainer').PageContainer} PageContainer */
14
+ /** @typedef {import('../BookReader').default} BookReader */
15
+
16
+ // I _have_ to make this globally public, otherwise it won't let me call
17
+ // its constructor :/
18
+ /** @implements {SmoothZoomable} */
19
+ @customElement('br-mode-2up')
20
+ export class Mode2UpLit extends LitElement {
21
+ /****************************************/
22
+ /************** PROPERTIES **************/
23
+ /****************************************/
24
+
25
+ /** @type {BookReader} */
26
+ br;
27
+
28
+ /************** BOOK-RELATED PROPERTIES **************/
29
+
30
+ /** @type {BookModel} */
31
+ @property({ type: Object })
32
+ book;
33
+
34
+ /************** SCALE-RELATED PROPERTIES **************/
35
+
36
+ /** @type {ModeCoordinateSpace} Manage conversion between coordinates */
37
+ coordSpace = new ModeCoordinateSpace(this);
38
+
39
+ @property({ type: Number })
40
+ scale = 1;
41
+
42
+ initialScale = 1;
43
+
44
+ /** @type {import('./options').AutoFitValues} */
45
+ @property({ type: String })
46
+ autoFit = 'auto';
47
+
48
+ /************** VIRTUAL-FLIPPING PROPERTIES **************/
49
+
50
+ /** ms for flip animation */
51
+ flipSpeed = 400;
52
+
53
+ @query('.br-mode-2up__leafs--flipping') $flippingEdges;
54
+
55
+ /** @type {PageModel[]} */
56
+ @property({ type: Array, hasChanged: arrChanged })
57
+ visiblePages = [];
58
+
59
+ /** @type {PageModel | null} */
60
+ get pageLeft() {
61
+ return this.visiblePages.find(p => p.pageSide == 'L');
62
+ }
63
+
64
+ /** @type {PageModel | null} */
65
+ get pageRight() {
66
+ return this.visiblePages.find(p => p.pageSide == 'R');
67
+ }
68
+
69
+ /** @type {PageModel[]} */
70
+ @property({ type: Array })
71
+ renderedPages = [];
72
+
73
+ /** @type {Record<PageIndex, PageContainer>} position in inches */
74
+ pageContainerCache = {};
75
+
76
+ /** @type {{ direction: 'left' | 'right', pagesFlipping: [PageIndex, PageIndex], pagesFlippingCount: number }} */
77
+ activeFlip = null;
78
+
79
+ /** @private cache this value */
80
+ _leftCoverWidth = 0;
81
+
82
+ /************** DOM-RELATED PROPERTIES **************/
83
+
84
+ /** @type {HTMLElement} */
85
+ get $container() { return this; }
86
+
87
+ /** @type {HTMLElement} */
88
+ get $visibleWorld() { return this.$book; }
89
+
90
+ /** @type {HTMLElement} */
91
+ @query('.br-mode-2up__book')
92
+ $book;
93
+
94
+ get positions() {
95
+ return this.computePositions(this.pageLeft, this.pageRight);
96
+ }
97
+
98
+ /** @param {PageModel} page */
99
+ computePageHeight(page) {
100
+ return this.book.getMedianPageSizeInches().height;
101
+ }
102
+
103
+ /** @param {PageModel} page */
104
+ computePageWidth(page) {
105
+ return page.widthInches * this.computePageHeight(page) / page.heightInches;
106
+ }
107
+
108
+ /**
109
+ * @param {PageModel | null} pageLeft
110
+ * @param {PageModel | null} pageRight
111
+ */
112
+ computePositions(pageLeft, pageRight) {
113
+ const computePageWidth = this.computePageWidth.bind(this);
114
+ const numLeafs = this.book.getNumLeafs();
115
+ const movingPagesWidth = this.activeFlip ? Math.ceil(this.activeFlip.pagesFlippingCount / 2) * this.PAGE_THICKNESS_IN : 0;
116
+ const leftPagesCount = this.book.pageProgression == 'lr' ? (pageLeft?.index ?? 0) : (!pageLeft ? 0 : numLeafs - pageLeft.index);
117
+
118
+ // Everything is relative to the gutter
119
+ const gutter = this._leftCoverWidth + leftPagesCount * this.PAGE_THICKNESS_IN;
120
+
121
+ const pageLeftEnd = gutter;
122
+ const pageLeftWidth = !pageLeft ? computePageWidth(pageRight.right) : computePageWidth(pageLeft);
123
+ const pageLeftStart = gutter - pageLeftWidth;
124
+
125
+ const leafEdgesLeftEnd = pageLeftStart; // leafEdgesLeftStart + leafEdgesLeftMainWidth + leafEdgesLeftMovingWidth;
126
+ const leafEdgesLeftMovingWidth = this.activeFlip?.direction != 'left' ? 0 : movingPagesWidth;
127
+ const leafEdgesLeftMainWidth = Math.ceil(leftPagesCount / 2) * this.PAGE_THICKNESS_IN - leafEdgesLeftMovingWidth;
128
+ const leafEdgesLeftFullWidth = leafEdgesLeftMovingWidth + leafEdgesLeftMainWidth;
129
+ const leafEdgesLeftMovingStart = leafEdgesLeftEnd - leafEdgesLeftMovingWidth;
130
+ const leafEdgesLeftStart = leafEdgesLeftMovingStart - leafEdgesLeftMainWidth;
131
+
132
+ const pageRightStart = gutter;
133
+ const pageRightWidth = !pageRight ? 0 : computePageWidth(pageRight);
134
+ const pageRightEnd = pageRightStart + pageRightWidth;
135
+
136
+ const rightPagesCount = this.book.pageProgression == 'lr' ? (!pageRight ? 0 : numLeafs - pageRight.index) : (pageRight?.index ?? 0);
137
+ const leafEdgesRightStart = pageRightEnd;
138
+ const leafEdgesRightMovingWidth = this.activeFlip?.direction != 'right' ? 0 : movingPagesWidth;
139
+ const leafEdgesRightMainStart = leafEdgesRightStart + leafEdgesRightMovingWidth;
140
+ const leafEdgesRightMainWidth = Math.ceil(rightPagesCount / 2) * this.PAGE_THICKNESS_IN - leafEdgesRightMovingWidth;
141
+ const leafEdgesRightEnd = leafEdgesRightStart + leafEdgesRightMainWidth + leafEdgesRightMovingWidth;
142
+ const leafEdgesRightFullWidth = leafEdgesRightMovingWidth + leafEdgesRightMainWidth;
143
+
144
+ const spreadWidth = pageRightEnd - pageLeftStart;
145
+ const bookWidth = leafEdgesRightEnd - leafEdgesLeftStart;
146
+ return {
147
+ leafEdgesLeftStart,
148
+ leafEdgesLeftMainWidth,
149
+ leafEdgesLeftMovingStart,
150
+ leafEdgesLeftMovingWidth,
151
+ leafEdgesLeftEnd,
152
+ leafEdgesLeftFullWidth,
153
+
154
+ pageLeftStart,
155
+ pageLeftWidth,
156
+ pageLeftEnd,
157
+
158
+ gutter,
159
+
160
+ pageRightStart,
161
+ pageRightWidth,
162
+ pageRightEnd,
163
+
164
+ leafEdgesRightStart,
165
+ leafEdgesRightMovingWidth,
166
+ leafEdgesRightMainStart,
167
+ leafEdgesRightMainWidth,
168
+ leafEdgesRightEnd,
169
+ leafEdgesRightFullWidth,
170
+
171
+ spreadWidth,
172
+ bookWidth,
173
+ };
174
+ }
175
+
176
+ /** @type {HTMLDimensionsCacher} Cache things like clientWidth to reduce repaints */
177
+ htmlDimensionsCacher = new HTMLDimensionsCacher(this);
178
+
179
+ smoothZoomer = new ModeSmoothZoom(this);
180
+
181
+ /************** CONSTANT PROPERTIES **************/
182
+
183
+ /** How much to zoom when zoom button pressed */
184
+ ZOOM_FACTOR = 1.1;
185
+
186
+ /** How thick a page is in the real world, as an estimate for the leafs */
187
+ PAGE_THICKNESS_IN = 0.002;
188
+
189
+ /****************************************/
190
+ /************** PUBLIC API **************/
191
+ /****************************************/
192
+
193
+ /************** MAIN PUBLIC METHODS **************/
194
+
195
+ /**
196
+ * @param {PageIndex} index
197
+ * TODO Remove smooth option from everywhere.
198
+ */
199
+ async jumpToIndex(index, { smooth = true } = {}) {
200
+ await this._flipAnimation(index, { animate: smooth });
201
+ }
202
+
203
+ zoomIn() {
204
+ this.scale *= this.ZOOM_FACTOR;
205
+ }
206
+
207
+ zoomOut() {
208
+ this.scale *= 1 / this.ZOOM_FACTOR;
209
+ }
210
+
211
+ /********************************************/
212
+ /************** INTERNAL STUFF **************/
213
+ /********************************************/
214
+
215
+ /************** LIFE CYCLE **************/
216
+
217
+ /**
218
+ * @param {BookModel} book
219
+ * @param {BookReader} br
220
+ */
221
+ constructor(book, br) {
222
+ super();
223
+ this.book = book;
224
+
225
+ /** @type {BookReader} */
226
+ this.br = br;
227
+ }
228
+
229
+ /** @override */
230
+ firstUpdated(changedProps) {
231
+ super.firstUpdated(changedProps);
232
+ this.htmlDimensionsCacher.updateClientSizes();
233
+ this.smoothZoomer.attach();
234
+ }
235
+
236
+ /** @override */
237
+ connectedCallback() {
238
+ super.connectedCallback();
239
+ this.htmlDimensionsCacher.attachResizeListener();
240
+ this.smoothZoomer.attach();
241
+ }
242
+
243
+ /** @override */
244
+ disconnectedCallback() {
245
+ this.htmlDimensionsCacher.detachResizeListener();
246
+ this.smoothZoomer.detach();
247
+ super.disconnectedCallback();
248
+ }
249
+
250
+ /** @override */
251
+ updated(changedProps) {
252
+ // this.X is the new value
253
+ // changedProps.get('X') is the old value
254
+ if (changedProps.has('book')) {
255
+ this._leftCoverWidth = this.computePageWidth(this.book.getPage(this.book.pageProgression == 'lr' ? 0 : -1));
256
+ }
257
+ if (changedProps.has('visiblePages')) {
258
+ this.renderedPages = this.computeRenderedPages();
259
+ this.br.displayedIndices = this.visiblePages.map(p => p.index);
260
+ this.br.updateFirstIndex(this.br.displayedIndices[0]);
261
+ }
262
+ if (changedProps.has('autoFit')) {
263
+ if (this.autoFit != 'none') {
264
+ this.resizeViaAutofit();
265
+ }
266
+ }
267
+ if (changedProps.has('scale')) {
268
+ const oldVal = changedProps.get('scale');
269
+ this.recenter();
270
+ this.smoothZoomer.updateViewportOnZoom(this.scale, oldVal);
271
+ }
272
+ }
273
+
274
+ /************** LIT CONFIGS **************/
275
+
276
+ /** @override */
277
+ createRenderRoot() {
278
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
279
+ return this;
280
+ }
281
+
282
+ /************** RENDERING **************/
283
+
284
+ /** @override */
285
+ render() {
286
+ return html`
287
+ <div class="br-mode-2up__book" @mouseup=${this.handlePageClick}>
288
+ ${this.renderLeafEdges('left')}
289
+ ${this.renderedPages.map(p => this.renderPage(p))}
290
+ ${this.renderLeafEdges('right')}
291
+ </div>`;
292
+ }
293
+
294
+ /** @param {PageModel} page */
295
+ createPageContainer = (page) => {
296
+ return this.pageContainerCache[page.index] || (
297
+ this.pageContainerCache[page.index] = (
298
+ // @ts-ignore I know it's protected, TS! But Mode2Up and BookReader are friends.
299
+ this.br._createPageContainer(page.index)
300
+ )
301
+ );
302
+ }
303
+
304
+ /**
305
+ * @param {PageIndex} startIndex
306
+ */
307
+ initFirstRender(startIndex) {
308
+ const page = this.book.getPage(startIndex);
309
+ const spread = page.spread;
310
+ this.visiblePages = (
311
+ this.book.pageProgression == 'lr' ? [spread.left, spread.right] : [spread.right, spread.left]
312
+ ).filter(p => p);
313
+ this.htmlDimensionsCacher.updateClientSizes();
314
+ this.resizeViaAutofit(page);
315
+ this.initialScale = this.scale;
316
+ }
317
+
318
+ /** @param {PageModel} page */
319
+ renderPage = (page) => {
320
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
321
+ const wToV = this.coordSpace.worldUnitsToVisiblePixels;
322
+
323
+ const width = wToR(this.computePageWidth(page));
324
+ const height = wToR(this.computePageHeight(page));
325
+ const isVisible = this.visiblePages.map(p => p.index).includes(page.index);
326
+ const positions = this.computePositions(page.spread.left, page.spread.right);
327
+
328
+ const pageContainerEl = this.createPageContainer(page)
329
+ .update({
330
+ dimensions: {
331
+ width,
332
+ height,
333
+ top: 0,
334
+ left: wToR(page.pageSide == 'L' ? positions.pageLeftStart : positions.pageLeftEnd),
335
+ },
336
+ reduce: page.width / wToV(this.computePageWidth(page)),
337
+ }).$container[0];
338
+
339
+ // Should keep for initial render of the page
340
+ const wasVisible = pageContainerEl.classList.contains('BRpage-visible');
341
+ const visibleStatus = pageContainerEl.classList.toggle('BRpage-visible', isVisible);
342
+ if (visibleStatus && !wasVisible) {
343
+ this.br.trigger('pageVisible', { pageContainerEl });
344
+ }
345
+ return pageContainerEl;
346
+ }
347
+
348
+ /**
349
+ * @param {'left' | 'right'} side
350
+ * Renders the current leaf edges, as well as any "moving" leaf edges,
351
+ * i.e. leaf edges that are currently being flipped. Uses a custom element
352
+ * to render br-leaf-edges.
353
+ **/
354
+ renderLeafEdges = (side) => {
355
+ if (!this.visiblePages.length) return html``;
356
+ const fullWidthIn = side == 'left' ? this.positions.leafEdgesLeftFullWidth : this.positions.leafEdgesRightFullWidth;
357
+ if (!fullWidthIn) return html``;
358
+
359
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
360
+ const height = wToR(this.computePageHeight(this.visiblePages[0]));
361
+ const hasMovingPages = this.activeFlip?.direction == side;
362
+
363
+ const leftmostPage = this.book.getPage(this.book.pageProgression == 'lr' ? 0 : this.book.getNumLeafs() - 1);
364
+ const rightmostPage = this.book.getPage(this.book.pageProgression == 'lr' ? this.book.getNumLeafs() - 1 : 0);
365
+ const numPagesFlipping = hasMovingPages ? this.activeFlip.pagesFlippingCount : 0;
366
+ const range = side == 'left' ?
367
+ [leftmostPage.index, this.pageLeft.goLeft(numPagesFlipping).index] :
368
+ [this.pageRight.goRight(numPagesFlipping).index, rightmostPage.index];
369
+
370
+ const mainEdgesStyle = {
371
+ width: `${wToR(side == 'left' ? this.positions.leafEdgesLeftMainWidth : this.positions.leafEdgesRightMainWidth)}px`,
372
+ height: `${height}px`,
373
+ left: `${wToR(side == 'left' ? this.positions.leafEdgesLeftStart : this.positions.leafEdgesRightMainStart)}px`,
374
+ };
375
+ const mainEdges = html`
376
+ <br-leaf-edges
377
+ leftIndex=${range[0]}
378
+ rightIndex=${range[1]}
379
+ .book=${this.book}
380
+ .pageClickHandler=${(index) => this.br.jumpToIndex(index, { ariaLive: true })}
381
+ side=${side}
382
+ class="br-mode-2up__leafs br-mode-2up__leafs--${side}"
383
+ style=${styleMap(mainEdgesStyle)}
384
+ ></br-leaf-edges>
385
+ `;
386
+
387
+ if (hasMovingPages) {
388
+ const width = wToR(side == 'left' ? this.positions.leafEdgesLeftMovingWidth : this.positions.leafEdgesRightMovingWidth);
389
+ const style = {
390
+ width: `${width}px`,
391
+ height: `${height}px`,
392
+ left: `${wToR(side == 'left' ? this.positions.leafEdgesLeftMovingStart : this.positions.leafEdgesRightStart)}px`,
393
+ pointerEvents: 'none',
394
+ transformOrigin: `${wToR(side == 'left' ? this.positions.pageLeftWidth : -this.positions.pageRightWidth) + width / 2}px 0`,
395
+ };
396
+
397
+ const movingEdges = html`
398
+ <br-leaf-edges
399
+ leftIndex=${this.activeFlip.pagesFlipping[0]}
400
+ rightIndex=${this.activeFlip.pagesFlipping[1]}
401
+ .book=${this.book}
402
+ side=${side}
403
+ class="br-mode-2up__leafs br-mode-2up__leafs--${side} br-mode-2up__leafs--flipping"
404
+ style=${styleMap(style)}
405
+ ></br-leaf-edges>
406
+ `;
407
+
408
+ return side == 'left' ? html`${mainEdges}${movingEdges}` : html`${movingEdges}${mainEdges}`;
409
+ } else {
410
+ return mainEdges;
411
+ }
412
+ }
413
+
414
+ resizeViaAutofit(page = this.visiblePages[0]) {
415
+ this.scale = this.computeScale(page, this.autoFit);
416
+ }
417
+
418
+ recenter(page = this.visiblePages[0]) {
419
+ const translate = this.computeTranslate(page, this.scale);
420
+ this.$book.style.transform = `translateX(${translate.x}px) translateY(${translate.y}px) scale(${this.scale})`;
421
+ }
422
+
423
+ /**
424
+ * @returns {PageModel[]}
425
+ */
426
+ computeRenderedPages() {
427
+ // Also render 2 pages before/after
428
+ // @ts-ignore TS doesn't understand the filtering out of null values
429
+ return [
430
+ this.visiblePages[0]?.prev?.prev,
431
+ this.visiblePages[0]?.prev,
432
+ ...this.visiblePages,
433
+ this.visiblePages[this.visiblePages.length - 1]?.next,
434
+ this.visiblePages[this.visiblePages.length - 1]?.next?.next,
435
+ ]
436
+ .filter(p => p)
437
+ // Never render more than 10 pages! Usually means something is wrong
438
+ .slice(0, 10);
439
+ }
440
+
441
+ /**
442
+ * @param {PageModel} page
443
+ * @param {import('./options').AutoFitValues} autoFit
444
+ */
445
+ computeScale(page, autoFit) {
446
+ if (!page) return 1;
447
+ const spread = page.spread;
448
+ const bookWidth = this.computePositions(spread.left, spread.right).bookWidth;
449
+ const bookHeight = this.computePageHeight(spread.left || spread.right);
450
+ const BOOK_PADDING_PX = 10;
451
+ const curScale = this.scale;
452
+ this.scale = 1; // Need this temporarily
453
+ const widthScale = this.coordSpace.renderedPixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth - 2 * BOOK_PADDING_PX) / bookWidth;
454
+ const heightScale = this.coordSpace.renderedPixelsToWorldUnits(this.htmlDimensionsCacher.clientHeight - 2 * BOOK_PADDING_PX) / bookHeight;
455
+ this.scale = curScale;
456
+ const realScale = 1;
457
+
458
+ let scale = realScale;
459
+ if (autoFit == 'width') {
460
+ scale = widthScale;
461
+ } else if (autoFit == 'height') {
462
+ scale = heightScale;
463
+ } else if (autoFit == 'auto') {
464
+ scale = Math.min(widthScale, heightScale);
465
+ } else if (autoFit == 'none') {
466
+ scale = this.scale;
467
+ } else {
468
+ // Should be impossible
469
+ throw new Error(`Invalid autoFit value: ${autoFit}`);
470
+ }
471
+
472
+ return scale;
473
+ }
474
+
475
+ /**
476
+ * @param {PageModel} page
477
+ * @param {number} scale
478
+ * @returns {{x: number, y: number}}
479
+ */
480
+ computeTranslate(page, scale = this.scale) {
481
+ if (!page) return { x: 0, y: 0 };
482
+ const spread = page.spread;
483
+ // Default to real size if it fits, otherwise default to full height
484
+ const positions = this.computePositions(spread.left, spread.right);
485
+ const bookWidth = positions.bookWidth;
486
+ const bookHeight = this.computePageHeight(spread.left || spread.right);
487
+ const visibleBookWidth = this.coordSpace.worldUnitsToRenderedPixels(bookWidth) * scale;
488
+ const visibleBookHeight = this.coordSpace.worldUnitsToRenderedPixels(bookHeight) * scale;
489
+ const leftOffset = this.coordSpace.worldUnitsToRenderedPixels(-positions.leafEdgesLeftStart) * scale;
490
+ const translateX = (this.htmlDimensionsCacher.clientWidth - visibleBookWidth) / 2 + leftOffset;
491
+ const translateY = (this.htmlDimensionsCacher.clientHeight - visibleBookHeight) / 2;
492
+ return { x: Math.max(leftOffset, translateX), y: Math.max(0, translateY) };
493
+ }
494
+
495
+ /************** VIRTUAL FLIPPING LOGIC **************/
496
+
497
+ /**
498
+ * @private
499
+ * @param {'left' | 'right' | 'next' | 'prev' | PageIndex | PageModel | {left: PageModel | null, right: PageModel | null}} nextSpread
500
+ */
501
+ async _flipAnimation(nextSpread, { animate = true, flipSpeed = this.flipSpeed } = {}) {
502
+ const curSpread = (this.pageLeft || this.pageRight)?.spread;
503
+ if (!curSpread) {
504
+ // Nothings been actually rendered yet! Will be corrected during initFirstRender
505
+ return;
506
+ }
507
+
508
+ flipSpeed = flipSpeed || this.flipSpeed; // Handle null
509
+ nextSpread = this.parseNextSpread(nextSpread);
510
+ if (this.activeFlip || !nextSpread) return;
511
+
512
+ const progression = this.book.pageProgression;
513
+ const curLeftIndex = curSpread.left?.index ?? (progression == 'lr' ? -1 : this.book.getNumLeafs());
514
+ const nextLeftIndex = nextSpread.left?.index ?? (progression == 'lr' ? -1 : this.book.getNumLeafs());
515
+ if (curLeftIndex == nextLeftIndex) return;
516
+
517
+ const renderedIndices = this.renderedPages.map(p => p.index);
518
+ /** @type {PageContainer[]} */
519
+ const nextPageContainers = [];
520
+ for (const page of [nextSpread.left, nextSpread.right]) {
521
+ if (!page) continue;
522
+ nextPageContainers.push(this.createPageContainer(page));
523
+ if (!renderedIndices.includes(page.index)) {
524
+ this.renderedPages.push(page);
525
+ }
526
+ }
527
+
528
+ const curTranslate = this.computeTranslate(curSpread.left || curSpread.right, this.scale);
529
+ const idealNextTranslate = this.computeTranslate(nextSpread.left || nextSpread.right, this.scale);
530
+ const translateDiff = Math.sqrt((idealNextTranslate.x - curTranslate.x) ** 2 + (idealNextTranslate.y - curTranslate.y) ** 2);
531
+ let nextTranslate = `translate(${idealNextTranslate.x}px, ${idealNextTranslate.y}px)`;
532
+ if (translateDiff < 50) {
533
+ const activeTranslate = this.$book.style.transform.match(/translate\([^)]+\)/)?.[0];
534
+ if (activeTranslate) {
535
+ nextTranslate = activeTranslate;
536
+ }
537
+ }
538
+ const newTransform = `${nextTranslate} scale(${this.scale})`;
539
+
540
+ if (animate && 'animate' in Element.prototype) {
541
+ // This table is used to determine the direction of the flip animation:
542
+ // | < | >
543
+ // lr | L | R
544
+ // rl | R | L
545
+ const direction = progression == 'lr' ? (nextLeftIndex > curLeftIndex ? 'right' : 'left') : (nextLeftIndex > curLeftIndex ? 'left' : 'right');
546
+
547
+ this.activeFlip = {
548
+ direction,
549
+ pagesFlipping: [curLeftIndex, nextLeftIndex],
550
+ pagesFlippingCount: Math.abs(nextLeftIndex - curLeftIndex),
551
+ };
552
+
553
+ this.classList.add(`br-mode-2up--flipping-${direction}`);
554
+ this.classList.add(`BRpageFlipping`);
555
+
556
+ // Wait for lit update cycle to finish so that entering pages are rendered
557
+ this.requestUpdate();
558
+ await this.updateComplete;
559
+
560
+ this.visiblePages
561
+ .map(p => this.pageContainerCache[p.index].$container)
562
+ .forEach($c => $c.addClass('BRpage-exiting'));
563
+
564
+ nextPageContainers.forEach(c => c.$container.addClass('BRpage-entering'));
565
+
566
+ /** @type {KeyframeAnimationOptions} */
567
+ const animationStyle = {
568
+ duration: flipSpeed + this.activeFlip.pagesFlippingCount,
569
+ easing: 'ease-in',
570
+ fill: 'none',
571
+ };
572
+
573
+ const bookCenteringAnimation = this.$book.animate([
574
+ { transform: newTransform },
575
+ ], animationStyle);
576
+
577
+ const edgeTranslationAnimation = this.$flippingEdges.animate([
578
+ { transform: `rotateY(0deg)` },
579
+ {
580
+ transform: direction == 'left' ? `rotateY(-180deg)` : `rotateY(180deg)`,
581
+ },
582
+ ], animationStyle);
583
+
584
+ const exitingPageAnimation = direction == 'left' ?
585
+ this.querySelector('.BRpage-exiting[data-side=L]').animate([
586
+ { transform: `rotateY(0deg)` },
587
+ { transform: `rotateY(180deg)` },
588
+ ], animationStyle) : this.querySelector('.BRpage-exiting[data-side=R]').animate([
589
+ { transform: `rotateY(0deg)` },
590
+ { transform: `rotateY(-180deg)` },
591
+ ], animationStyle);
592
+
593
+ const enteringPageAnimation = direction == 'left' ?
594
+ this.querySelector('.BRpage-entering[data-side=R]').animate([
595
+ { transform: `rotateY(-180deg)` },
596
+ { transform: `rotateY(0deg)` },
597
+ ], animationStyle) : this.querySelector('.BRpage-entering[data-side=L]').animate([
598
+ { transform: `rotateY(180deg)` },
599
+ { transform: `rotateY(0deg)` },
600
+ ], animationStyle);
601
+
602
+ bookCenteringAnimation.play();
603
+ edgeTranslationAnimation.play();
604
+ exitingPageAnimation.play();
605
+ enteringPageAnimation.play();
606
+
607
+ nextPageContainers.forEach(c => c.$container.addClass('BRpage-visible'));
608
+
609
+ await Promise.race([
610
+ promisifyEvent(bookCenteringAnimation, 'finish'),
611
+ promisifyEvent(edgeTranslationAnimation, 'finish'),
612
+ promisifyEvent(exitingPageAnimation, 'finish'),
613
+ promisifyEvent(enteringPageAnimation, 'finish'),
614
+ ]);
615
+
616
+ this.classList.remove(`br-mode-2up--flipping-${direction}`);
617
+ this.classList.remove(`BRpageFlipping`);
618
+
619
+ this.visiblePages
620
+ .map(p => this.pageContainerCache[p.index].$container)
621
+ .forEach($c => $c.removeClass('BRpage-exiting BRpage-visible'));
622
+ nextPageContainers.forEach(c => c.$container.removeClass('BRpage-entering'));
623
+ this.activeFlip = null;
624
+ }
625
+
626
+ this.$book.style.transform = newTransform;
627
+ this.visiblePages = (
628
+ progression == 'lr' ? [nextSpread.left, nextSpread.right] : [nextSpread.right, nextSpread.left]
629
+ ).filter(x => x);
630
+ nextPageContainers.forEach(c => {
631
+ this.br.trigger('pageVisible', {
632
+ pageContainerEl: c.$container[0],
633
+ });
634
+ });
635
+ }
636
+
637
+ /**
638
+ * @param {'left' | 'right' | 'next' | 'prev' | PageIndex | PageModel | {left: PageModel | null, right: PageModel | null}} nextSpread
639
+ * @returns {{left: PageModel | null, right: PageModel | null}}
640
+ */
641
+ parseNextSpread(nextSpread) {
642
+ if (nextSpread == 'next') {
643
+ nextSpread = this.book.pageProgression == 'lr' ? 'right' : 'left';
644
+ } else if (nextSpread == 'prev') {
645
+ nextSpread = this.book.pageProgression == 'lr' ? 'left' : 'right';
646
+ }
647
+
648
+ const curPage = this.book.getPage(this.br.currentIndex());
649
+ const curSpread = curPage.spread;
650
+
651
+ if (nextSpread == 'left') {
652
+ nextSpread = curSpread.left?.findLeft({ combineConsecutiveUnviewables: true })?.spread;
653
+ } else if (nextSpread == 'right') {
654
+ nextSpread = curSpread.right?.findRight({ combineConsecutiveUnviewables: true })?.spread;
655
+ }
656
+
657
+ if (typeof(nextSpread) == 'number') {
658
+ nextSpread = this.book.getPage(nextSpread).spread;
659
+ }
660
+
661
+ if (nextSpread instanceof PageModel) {
662
+ nextSpread = nextSpread.spread;
663
+ }
664
+
665
+ return nextSpread;
666
+ }
667
+
668
+ /************** INPUT HANDLERS **************/
669
+
670
+ /**
671
+ * @param {MouseEvent} ev
672
+ */
673
+ handlePageClick = (ev) => {
674
+ // right click
675
+ if (ev.which == 3 && this.br.protected) {
676
+ return false;
677
+ }
678
+
679
+ if (ev.which != 1) return;
680
+
681
+ const $page = $(ev.target).closest('.BRpagecontainer');
682
+ if (!$page.length) return;
683
+ if ($page.data('side') == 'L') {
684
+ this.br.left();
685
+ } else if ($page.data('side') == 'R') {
686
+ this.br.right();
687
+ }
688
+ }
689
+ }
690
+
691
+ @customElement('br-leaf-edges')
692
+ export class LeafEdges extends LitElement {
693
+ @property({ type: Number }) leftIndex = 0;
694
+ @property({ type: Number }) rightIndex = 0;
695
+ /** @type {'left' | 'right'} */
696
+ @property({ type: String }) side = 'left';
697
+
698
+ /** @type {BookModel} */
699
+ @property({attribute: false})
700
+ book = null;
701
+
702
+ /** @type {(index: PageIndex) => void} */
703
+ @property({attribute: false, type: Function})
704
+ pageClickHandler = null;
705
+
706
+ @query('.br-leaf-edges__bar') $hoverBar;
707
+ @query('.br-leaf-edges__label') $hoverLabel;
708
+
709
+ get pageWidthPercent() {
710
+ return 100 * 1 / (this.rightIndex - this.leftIndex + 1);
711
+ }
712
+
713
+ render() {
714
+ return html`
715
+ <div
716
+ class="br-leaf-edges__bar"
717
+ style="${styleMap({width: `${this.pageWidthPercent}%`})}"
718
+ ></div>
719
+ <div class="br-leaf-edges__label">Page</div>`;
720
+ }
721
+
722
+ connectedCallback() {
723
+ super.connectedCallback();
724
+ this.addEventListener('mouseenter', this.onMouseEnter);
725
+ this.addEventListener('mouseleave', this.onMouseLeave);
726
+ this.addEventListener('click', this.onClick);
727
+ }
728
+ disconnectedCallback() {
729
+ super.disconnectedCallback();
730
+ this.addEventListener('mouseenter', this.onMouseEnter);
731
+ this.removeEventListener('mousemove', this.onMouseMove);
732
+ this.removeEventListener('mouseleave', this.onMouseLeave);
733
+ }
734
+
735
+ /** @override */
736
+ createRenderRoot() {
737
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
738
+ return this;
739
+ }
740
+
741
+ /**
742
+ * @param {MouseEvent} e
743
+ */
744
+ onMouseEnter = (e) => {
745
+ this.addEventListener('mousemove', this.onMouseMove);
746
+ this.$hoverBar.style.display = 'block';
747
+ this.$hoverLabel.style.display = 'block';
748
+ }
749
+
750
+ /**
751
+ * @param {MouseEvent} e
752
+ */
753
+ onMouseMove = (e) => {
754
+ this.$hoverBar.style.left = `${e.offsetX}px`;
755
+ if (this.side == 'right') {
756
+ this.$hoverLabel.style.left = `${e.offsetX}px`;
757
+ } else {
758
+ this.$hoverLabel.style.right = `${this.offsetWidth - e.offsetX}px`;
759
+ }
760
+ this.$hoverLabel.style.top = `${e.offsetY}px`;
761
+ const index = this.mouseEventToPageIndex(e);
762
+ this.$hoverLabel.textContent = this.book.getPageName(index);
763
+ }
764
+
765
+ /**
766
+ * @param {MouseEvent} e
767
+ */
768
+ onMouseLeave = (e) => {
769
+ this.removeEventListener('mousemove', this.onMouseMove);
770
+ this.$hoverBar.style.display = 'none';
771
+ this.$hoverLabel.style.display = 'none';
772
+ }
773
+
774
+ /**
775
+ * @param {MouseEvent} e
776
+ */
777
+ onClick = (e) => {
778
+ this.pageClickHandler(this.mouseEventToPageIndex(e));
779
+ }
780
+
781
+ /**
782
+ * @param {MouseEvent} e
783
+ * @returns {PageIndex}
784
+ */
785
+ mouseEventToPageIndex(e) {
786
+ return Math.floor(this.leftIndex + (e.offsetX / this.offsetWidth) * (this.rightIndex - this.leftIndex + 1));
787
+ }
788
+ }