@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
@@ -0,0 +1,787 @@
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
+ this.br._components.navbar.updateNavIndexThrottled();
262
+ }
263
+ if (changedProps.has('autoFit')) {
264
+ if (this.autoFit != 'none') {
265
+ this.resizeViaAutofit();
266
+ }
267
+ }
268
+ if (changedProps.has('scale')) {
269
+ const oldVal = changedProps.get('scale');
270
+ this.recenter();
271
+ this.smoothZoomer.updateViewportOnZoom(this.scale, oldVal);
272
+ }
273
+ }
274
+
275
+ /************** LIT CONFIGS **************/
276
+
277
+ /** @override */
278
+ createRenderRoot() {
279
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
280
+ return this;
281
+ }
282
+
283
+ /************** RENDERING **************/
284
+
285
+ /** @override */
286
+ render() {
287
+ return html`
288
+ <div class="br-mode-2up__book" @mouseup=${this.handlePageClick}>
289
+ ${this.renderLeafEdges('left')}
290
+ ${this.renderedPages.map(p => this.renderPage(p))}
291
+ ${this.renderLeafEdges('right')}
292
+ </div>`;
293
+ }
294
+
295
+ /** @param {PageModel} page */
296
+ createPageContainer = (page) => {
297
+ return this.pageContainerCache[page.index] || (
298
+ this.pageContainerCache[page.index] = (
299
+ // @ts-ignore I know it's protected, TS! But Mode2Up and BookReader are friends.
300
+ this.br._createPageContainer(page.index)
301
+ )
302
+ );
303
+ }
304
+
305
+ /**
306
+ * @param {PageIndex} startIndex
307
+ */
308
+ initFirstRender(startIndex) {
309
+ const page = this.book.getPage(startIndex);
310
+ const spread = page.spread;
311
+ this.visiblePages = (
312
+ this.book.pageProgression == 'lr' ? [spread.left, spread.right] : [spread.right, spread.left]
313
+ ).filter(p => p);
314
+ this.htmlDimensionsCacher.updateClientSizes();
315
+ this.resizeViaAutofit(page);
316
+ this.initialScale = this.scale;
317
+ }
318
+
319
+ /** @param {PageModel} page */
320
+ renderPage = (page) => {
321
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
322
+ const wToV = this.coordSpace.worldUnitsToVisiblePixels;
323
+
324
+ const width = wToR(this.computePageWidth(page));
325
+ const height = wToR(this.computePageHeight(page));
326
+ const isVisible = this.visiblePages.map(p => p.index).includes(page.index);
327
+ const positions = this.computePositions(page.spread.left, page.spread.right);
328
+
329
+ const pageContainerEl = this.createPageContainer(page)
330
+ .update({
331
+ dimensions: {
332
+ width,
333
+ height,
334
+ top: 0,
335
+ left: wToR(page.pageSide == 'L' ? positions.pageLeftStart : positions.pageLeftEnd),
336
+ },
337
+ reduce: page.width / wToV(this.computePageWidth(page)),
338
+ }).$container[0];
339
+
340
+ // Should keep for initial render of the page
341
+ const wasVisible = pageContainerEl.classList.contains('BRpage-visible');
342
+ const visibleStatus = pageContainerEl.classList.toggle('BRpage-visible', isVisible);
343
+ if (visibleStatus && !wasVisible) {
344
+ this.br.trigger('pageVisible', { pageContainerEl });
345
+ }
346
+ return pageContainerEl;
347
+ }
348
+
349
+ /**
350
+ * @param {'left' | 'right'} side
351
+ * Renders the current leaf edges, as well as any "moving" leaf edges,
352
+ * i.e. leaf edges that are currently being flipped. Uses a custom element
353
+ * to render br-leaf-edges.
354
+ **/
355
+ renderLeafEdges = (side) => {
356
+ if (!this.visiblePages.length) return html``;
357
+ const fullWidthIn = side == 'left' ? this.positions.leafEdgesLeftFullWidth : this.positions.leafEdgesRightFullWidth;
358
+ if (!fullWidthIn) return html``;
359
+
360
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
361
+ const height = wToR(this.computePageHeight(this.visiblePages[0]));
362
+ const hasMovingPages = this.activeFlip?.direction == side;
363
+
364
+ const leftmostPage = this.book.getPage(this.book.pageProgression == 'lr' ? 0 : this.book.getNumLeafs() - 1);
365
+ const rightmostPage = this.book.getPage(this.book.pageProgression == 'lr' ? this.book.getNumLeafs() - 1 : 0);
366
+ const numPagesFlipping = hasMovingPages ? this.activeFlip.pagesFlippingCount : 0;
367
+ const range = side == 'left' ?
368
+ [leftmostPage.index, this.pageLeft.goLeft(numPagesFlipping).index] :
369
+ [this.pageRight.goRight(numPagesFlipping).index, rightmostPage.index];
370
+
371
+ const mainEdgesStyle = {
372
+ width: `${wToR(side == 'left' ? this.positions.leafEdgesLeftMainWidth : this.positions.leafEdgesRightMainWidth)}px`,
373
+ height: `${height}px`,
374
+ left: `${wToR(side == 'left' ? this.positions.leafEdgesLeftStart : this.positions.leafEdgesRightMainStart)}px`,
375
+ };
376
+ const mainEdges = html`
377
+ <br-leaf-edges
378
+ leftIndex=${range[0]}
379
+ rightIndex=${range[1]}
380
+ .book=${this.book}
381
+ .pageClickHandler=${(index) => this.br.jumpToIndex(index)}
382
+ side=${side}
383
+ class="br-mode-2up__leafs br-mode-2up__leafs--${side}"
384
+ style=${styleMap(mainEdgesStyle)}
385
+ ></br-leaf-edges>
386
+ `;
387
+
388
+ if (hasMovingPages) {
389
+ const width = wToR(side == 'left' ? this.positions.leafEdgesLeftMovingWidth : this.positions.leafEdgesRightMovingWidth);
390
+ const style = {
391
+ width: `${width}px`,
392
+ height: `${height}px`,
393
+ left: `${wToR(side == 'left' ? this.positions.leafEdgesLeftMovingStart : this.positions.leafEdgesRightStart)}px`,
394
+ pointerEvents: 'none',
395
+ transformOrigin: `${wToR(side == 'left' ? this.positions.pageLeftWidth : -this.positions.pageRightWidth) + width / 2}px 0`,
396
+ };
397
+
398
+ const movingEdges = html`
399
+ <br-leaf-edges
400
+ leftIndex=${this.activeFlip.pagesFlipping[0]}
401
+ rightIndex=${this.activeFlip.pagesFlipping[1]}
402
+ .book=${this.book}
403
+ side=${side}
404
+ class="br-mode-2up__leafs br-mode-2up__leafs--${side} br-mode-2up__leafs--flipping"
405
+ style=${styleMap(style)}
406
+ ></br-leaf-edges>
407
+ `;
408
+
409
+ return side == 'left' ? html`${mainEdges}${movingEdges}` : html`${movingEdges}${mainEdges}`;
410
+ } else {
411
+ return mainEdges;
412
+ }
413
+ }
414
+
415
+ resizeViaAutofit(page = this.visiblePages[0]) {
416
+ this.scale = this.computeScale(page, this.autoFit);
417
+ }
418
+
419
+ recenter(page = this.visiblePages[0]) {
420
+ const translate = this.computeTranslate(page, this.scale);
421
+ this.$book.style.transform = `translateX(${translate.x}px) translateY(${translate.y}px) scale(${this.scale})`;
422
+ }
423
+
424
+ /**
425
+ * @returns {PageModel[]}
426
+ */
427
+ computeRenderedPages() {
428
+ // Also render 2 pages before/after
429
+ // @ts-ignore TS doesn't understand the filtering out of null values
430
+ return [
431
+ this.visiblePages[0]?.prev?.prev,
432
+ this.visiblePages[0]?.prev,
433
+ ...this.visiblePages,
434
+ this.visiblePages[this.visiblePages.length - 1]?.next,
435
+ this.visiblePages[this.visiblePages.length - 1]?.next?.next,
436
+ ]
437
+ .filter(p => p)
438
+ // Never render more than 10 pages! Usually means something is wrong
439
+ .slice(0, 10);
440
+ }
441
+
442
+ /**
443
+ * @param {PageModel} page
444
+ * @param {import('./options').AutoFitValues} autoFit
445
+ */
446
+ computeScale(page, autoFit) {
447
+ if (!page) return 1;
448
+ const spread = page.spread;
449
+ const bookWidth = this.computePositions(spread.left, spread.right).bookWidth;
450
+ const bookHeight = this.computePageHeight(spread.left || spread.right);
451
+ const BOOK_PADDING_PX = 10;
452
+ const curScale = this.scale;
453
+ this.scale = 1; // Need this temporarily
454
+ const widthScale = this.coordSpace.renderedPixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth - 2 * BOOK_PADDING_PX) / bookWidth;
455
+ const heightScale = this.coordSpace.renderedPixelsToWorldUnits(this.htmlDimensionsCacher.clientHeight - 2 * BOOK_PADDING_PX) / bookHeight;
456
+ this.scale = curScale;
457
+ const realScale = 1;
458
+
459
+ let scale = realScale;
460
+ if (autoFit == 'width') {
461
+ scale = widthScale;
462
+ } else if (autoFit == 'height') {
463
+ scale = heightScale;
464
+ } else if (autoFit == 'auto') {
465
+ scale = Math.min(widthScale, heightScale);
466
+ } else if (autoFit == 'none') {
467
+ scale = this.scale;
468
+ } else {
469
+ // Should be impossible
470
+ throw new Error(`Invalid autoFit value: ${autoFit}`);
471
+ }
472
+
473
+ return scale;
474
+ }
475
+
476
+ /**
477
+ * @param {PageModel} page
478
+ * @param {number} scale
479
+ * @returns {{x: number, y: number}}
480
+ */
481
+ computeTranslate(page, scale = this.scale) {
482
+ if (!page) return { x: 0, y: 0 };
483
+ const spread = page.spread;
484
+ // Default to real size if it fits, otherwise default to full height
485
+ const positions = this.computePositions(spread.left, spread.right);
486
+ const bookWidth = positions.bookWidth;
487
+ const bookHeight = this.computePageHeight(spread.left || spread.right);
488
+ const visibleBookWidth = this.coordSpace.worldUnitsToRenderedPixels(bookWidth) * scale;
489
+ const visibleBookHeight = this.coordSpace.worldUnitsToRenderedPixels(bookHeight) * scale;
490
+ const leftOffset = this.coordSpace.worldUnitsToRenderedPixels(-positions.leafEdgesLeftStart) * scale;
491
+ const translateX = (this.htmlDimensionsCacher.clientWidth - visibleBookWidth) / 2 + leftOffset;
492
+ const translateY = (this.htmlDimensionsCacher.clientHeight - visibleBookHeight) / 2;
493
+ return { x: Math.max(leftOffset, translateX), y: Math.max(0, translateY) };
494
+ }
495
+
496
+ /************** VIRTUAL FLIPPING LOGIC **************/
497
+
498
+ /**
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 curSpread = (this.pageLeft || this.pageRight).spread;
649
+
650
+ if (nextSpread == 'left') {
651
+ nextSpread = curSpread.left?.findLeft({ combineConsecutiveUnviewables: true })?.spread;
652
+ } else if (nextSpread == 'right') {
653
+ nextSpread = curSpread.right?.findRight({ combineConsecutiveUnviewables: true })?.spread;
654
+ }
655
+
656
+ if (typeof(nextSpread) == 'number') {
657
+ nextSpread = this.book.getPage(nextSpread).spread;
658
+ }
659
+
660
+ if (nextSpread instanceof PageModel) {
661
+ nextSpread = nextSpread.spread;
662
+ }
663
+
664
+ return nextSpread;
665
+ }
666
+
667
+ /************** INPUT HANDLERS **************/
668
+
669
+ /**
670
+ * @param {MouseEvent} ev
671
+ */
672
+ handlePageClick = (ev) => {
673
+ // right click
674
+ if (ev.which == 3 && this.br.protected) {
675
+ return false;
676
+ }
677
+
678
+ if (ev.which != 1) return;
679
+
680
+ const $page = $(ev.target).closest('.BRpagecontainer');
681
+ if (!$page.length) return;
682
+ if ($page.data('side') == 'L') {
683
+ this.flipAnimation('left');
684
+ } else if ($page.data('side') == 'R') {
685
+ this.flipAnimation('right');
686
+ }
687
+ }
688
+ }
689
+
690
+ @customElement('br-leaf-edges')
691
+ export class LeafEdges extends LitElement {
692
+ @property({ type: Number }) leftIndex = 0;
693
+ @property({ type: Number }) rightIndex = 0;
694
+ /** @type {'left' | 'right'} */
695
+ @property({ type: String }) side = 'left';
696
+
697
+ /** @type {BookModel} */
698
+ @property({attribute: false})
699
+ book = null;
700
+
701
+ /** @type {(index: PageIndex) => void} */
702
+ @property({attribute: false, type: Function})
703
+ pageClickHandler = null;
704
+
705
+ @query('.br-leaf-edges__bar') $hoverBar;
706
+ @query('.br-leaf-edges__label') $hoverLabel;
707
+
708
+ get pageWidthPercent() {
709
+ return 100 * 1 / (this.rightIndex - this.leftIndex + 1);
710
+ }
711
+
712
+ render() {
713
+ return html`
714
+ <div
715
+ class="br-leaf-edges__bar"
716
+ style="${styleMap({width: `${this.pageWidthPercent}%`})}"
717
+ ></div>
718
+ <div class="br-leaf-edges__label">Page</div>`;
719
+ }
720
+
721
+ connectedCallback() {
722
+ super.connectedCallback();
723
+ this.addEventListener('mouseenter', this.onMouseEnter);
724
+ this.addEventListener('mouseleave', this.onMouseLeave);
725
+ this.addEventListener('click', this.onClick);
726
+ }
727
+ disconnectedCallback() {
728
+ super.disconnectedCallback();
729
+ this.addEventListener('mouseenter', this.onMouseEnter);
730
+ this.removeEventListener('mousemove', this.onMouseMove);
731
+ this.removeEventListener('mouseleave', this.onMouseLeave);
732
+ }
733
+
734
+ /** @override */
735
+ createRenderRoot() {
736
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
737
+ return this;
738
+ }
739
+
740
+ /**
741
+ * @param {MouseEvent} e
742
+ */
743
+ onMouseEnter = (e) => {
744
+ this.addEventListener('mousemove', this.onMouseMove);
745
+ this.$hoverBar.style.display = 'block';
746
+ this.$hoverLabel.style.display = 'block';
747
+ }
748
+
749
+ /**
750
+ * @param {MouseEvent} e
751
+ */
752
+ onMouseMove = (e) => {
753
+ this.$hoverBar.style.left = `${e.offsetX}px`;
754
+ if (this.side == 'right') {
755
+ this.$hoverLabel.style.left = `${e.offsetX}px`;
756
+ } else {
757
+ this.$hoverLabel.style.right = `${this.offsetWidth - e.offsetX}px`;
758
+ }
759
+ this.$hoverLabel.style.top = `${e.offsetY}px`;
760
+ const index = this.mouseEventToPageIndex(e);
761
+ this.$hoverLabel.textContent = this.book.getPageName(index);
762
+ }
763
+
764
+ /**
765
+ * @param {MouseEvent} e
766
+ */
767
+ onMouseLeave = (e) => {
768
+ this.removeEventListener('mousemove', this.onMouseMove);
769
+ this.$hoverBar.style.display = 'none';
770
+ this.$hoverLabel.style.display = 'none';
771
+ }
772
+
773
+ /**
774
+ * @param {MouseEvent} e
775
+ */
776
+ onClick = (e) => {
777
+ this.pageClickHandler(this.mouseEventToPageIndex(e));
778
+ }
779
+
780
+ /**
781
+ * @param {MouseEvent} e
782
+ * @returns {PageIndex}
783
+ */
784
+ mouseEventToPageIndex(e) {
785
+ return Math.floor(this.leftIndex + (e.offsetX / this.offsetWidth) * (this.rightIndex - this.leftIndex + 1));
786
+ }
787
+ }