@internetarchive/bookreader 5.0.0-5-multiple-files → 5.0.0-50-a1

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 (289) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +77 -6
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +131 -339
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -0
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1493 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  57. package/BookReader/jquery-3.js +2 -0
  58. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  59. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -165
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +1 -304
  64. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  65. package/BookReader/plugins/plugin.iframe.js +1 -74
  66. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  67. package/BookReader/plugins/plugin.mobile_nav.js +1 -334
  68. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  69. package/BookReader/plugins/plugin.resume.js +1 -368
  70. package/BookReader/plugins/plugin.resume.js.map +1 -1
  71. package/BookReader/plugins/plugin.search.js +1 -1420
  72. package/BookReader/plugins/plugin.search.js.map +1 -1
  73. package/BookReader/plugins/plugin.text_selection.js +1 -1080
  74. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  75. package/BookReader/plugins/plugin.tts.js +2 -9193
  76. package/BookReader/plugins/plugin.tts.js.map +1 -1
  77. package/BookReader/plugins/plugin.url.js +1 -269
  78. package/BookReader/plugins/plugin.url.js.map +1 -1
  79. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  80. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  81. package/BookReader/webcomponents-bundle.js +3 -0
  82. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  83. package/BookReader/webcomponents-bundle.js.map +1 -0
  84. package/BookReaderDemo/BookReaderDemo.css +14 -1
  85. package/BookReaderDemo/IADemoBr.js +148 -0
  86. package/BookReaderDemo/demo-advanced.html +2 -2
  87. package/BookReaderDemo/demo-autoplay.html +2 -1
  88. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  89. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  90. package/BookReaderDemo/demo-fullscreen.html +2 -1
  91. package/BookReaderDemo/demo-iiif.html +2 -1
  92. package/BookReaderDemo/demo-internetarchive.html +84 -17
  93. package/BookReaderDemo/demo-multiple.html +2 -1
  94. package/BookReaderDemo/demo-preview-pages.html +2 -1
  95. package/BookReaderDemo/demo-simple.html +2 -1
  96. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  97. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  98. package/BookReaderDemo/immersion-1up.html +2 -1
  99. package/BookReaderDemo/immersion-mode.html +2 -1
  100. package/BookReaderDemo/toggle_controls.html +2 -1
  101. package/BookReaderDemo/view_mode.html +2 -1
  102. package/BookReaderDemo/viewmode-cycle.html +2 -3
  103. package/CHANGELOG.md +202 -0
  104. package/README.md +14 -1
  105. package/babel.config.js +18 -0
  106. package/codecov.yml +6 -0
  107. package/index.html +3 -0
  108. package/jsconfig.json +19 -0
  109. package/package.json +66 -56
  110. package/renovate.json +52 -0
  111. package/scripts/preversion.js +4 -1
  112. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  113. package/src/BookNavigator/assets/button-base.js +9 -2
  114. package/src/BookNavigator/assets/ia-logo.js +17 -0
  115. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  116. package/src/BookNavigator/assets/icon_close.js +1 -1
  117. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  118. package/src/BookNavigator/assets/{icon_sort_ascending.js → icon_sort_desc.js} +2 -2
  119. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  120. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  121. package/src/BookNavigator/book-navigator.js +583 -0
  122. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  123. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  124. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  125. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  126. package/src/BookNavigator/bookmarks/bookmarks-provider.js +21 -8
  127. package/src/BookNavigator/bookmarks/ia-bookmarks.js +102 -66
  128. package/src/BookNavigator/delete-modal-actions.js +1 -1
  129. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  130. package/src/BookNavigator/downloads/downloads.js +41 -25
  131. package/src/BookNavigator/search/a-search-result.js +18 -13
  132. package/src/BookNavigator/search/search-provider.js +80 -28
  133. package/src/BookNavigator/search/search-results.js +10 -18
  134. package/src/BookNavigator/sharing.js +27 -0
  135. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  136. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  137. package/src/BookNavigator/volumes/volumes-provider.js +93 -63
  138. package/src/BookNavigator/volumes/volumes.js +40 -46
  139. package/src/BookReader/BookModel.js +0 -29
  140. package/src/BookReader/DebugConsole.js +3 -3
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/Mode1Up.js +51 -351
  143. package/src/BookReader/Mode1UpLit.js +441 -0
  144. package/src/BookReader/Mode2Up.js +120 -105
  145. package/src/BookReader/ModeSmoothZoom.js +179 -0
  146. package/src/BookReader/ModeThumb.js +17 -11
  147. package/src/BookReader/Navbar/Navbar.js +10 -36
  148. package/src/BookReader/PageContainer.js +69 -6
  149. package/src/BookReader/ReduceSet.js +1 -1
  150. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  151. package/src/BookReader/options.js +10 -0
  152. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  153. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  154. package/src/BookReader/utils.js +92 -13
  155. package/src/BookReader.js +431 -620
  156. package/src/assets/icons/close-circle-dark.svg +1 -0
  157. package/src/assets/icons/magnify-minus.svg +3 -7
  158. package/src/assets/icons/magnify-plus.svg +3 -7
  159. package/src/assets/icons/voice.svg +1 -0
  160. package/src/css/BookReader.scss +0 -12
  161. package/src/css/_BRComponent.scss +1 -1
  162. package/src/css/_BRmain.scss +19 -24
  163. package/src/css/_BRnav.scss +4 -26
  164. package/src/css/_BRpages.scss +35 -0
  165. package/src/css/_BRsearch.scss +25 -216
  166. package/src/css/_TextSelection.scss +14 -17
  167. package/src/css/_colorbox.scss +2 -2
  168. package/src/css/_controls.scss +17 -5
  169. package/src/css/_icons.scss +6 -0
  170. package/src/ia-bookreader/ia-bookreader.js +224 -0
  171. package/src/plugins/plugin.autoplay.js +4 -4
  172. package/src/plugins/plugin.chapters.js +28 -35
  173. package/src/plugins/plugin.mobile_nav.js +11 -10
  174. package/src/plugins/plugin.resume.js +3 -3
  175. package/src/plugins/plugin.text_selection.js +26 -39
  176. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  177. package/src/plugins/search/plugin.search.js +174 -116
  178. package/src/plugins/search/view.js +63 -179
  179. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  180. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  181. package/src/plugins/tts/PageChunk.js +15 -21
  182. package/src/plugins/tts/PageChunkIterator.js +8 -12
  183. package/src/plugins/tts/WebTTSEngine.js +66 -69
  184. package/src/plugins/tts/plugin.tts.js +92 -109
  185. package/src/plugins/tts/utils.js +0 -9
  186. package/src/plugins/url/UrlPlugin.js +184 -0
  187. package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
  188. package/src/util/manifestGenerator.js +0 -0
  189. package/tests/e2e/README.md +37 -0
  190. package/tests/e2e/autoplay.test.js +2 -2
  191. package/tests/e2e/base.test.js +7 -7
  192. package/tests/e2e/helpers/base.js +9 -3
  193. package/tests/e2e/helpers/debug.js +1 -1
  194. package/tests/e2e/helpers/desktopSearch.js +14 -13
  195. package/tests/e2e/helpers/mobileSearch.js +3 -3
  196. package/tests/e2e/helpers/params.js +17 -0
  197. package/tests/e2e/models/Navigation.js +13 -4
  198. package/tests/e2e/rightToLeft.test.js +4 -5
  199. package/tests/e2e/viewmode.test.js +38 -33
  200. package/tests/jest/BookNavigator/book-navigator.test.js +634 -0
  201. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  202. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  203. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  204. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  205. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  206. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  207. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  208. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +102 -58
  209. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  210. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  211. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  212. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  213. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +34 -14
  214. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  215. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  216. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  217. package/tests/jest/BookReader/Mode1UpLit.test.js +92 -0
  218. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +36 -15
  219. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  220. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  221. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  222. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  223. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  224. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  225. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  226. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  227. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  228. package/tests/jest/BookReader/utils.test.js +186 -0
  229. package/tests/jest/BookReader.keyboard.test.js +190 -0
  230. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  231. package/tests/{BookReader.test.js → jest/BookReader.test.js} +18 -37
  232. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  233. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  234. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  235. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  236. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  237. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  238. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  239. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  240. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +63 -47
  241. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  242. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  243. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  244. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  245. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  246. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  247. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -28
  248. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  249. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  250. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  251. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  252. package/tests/{util → jest/util}/strings.test.js +1 -1
  253. package/tests/{utils.js → jest/utils.js} +38 -0
  254. package/webpack.config.js +11 -5
  255. package/.babelrc +0 -12
  256. package/.dependabot/config.yml +0 -6
  257. package/.testcaferc.json +0 -5
  258. package/BookReader/bookreader-component-bundle.js +0 -14275
  259. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  260. package/BookReader/bookreader-component-bundle.js.map +0 -1
  261. package/BookReader/icons/sort-ascending.svg +0 -1
  262. package/BookReader/icons/sort-descending.svg +0 -1
  263. package/BookReader/jquery-1.10.1.js +0 -108
  264. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  265. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  266. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  267. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  268. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  269. package/karma.conf.js +0 -23
  270. package/src/BookNavigator/BookModel.js +0 -14
  271. package/src/BookNavigator/BookNavigator.js +0 -448
  272. package/src/BookNavigator/assets/book-loader.js +0 -27
  273. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  274. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  275. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  276. package/src/ItemNavigator/ItemNavigator.js +0 -373
  277. package/src/ItemNavigator/providers/sharing.js +0 -29
  278. package/src/assets/icons/sort-ascending.svg +0 -1
  279. package/src/assets/icons/sort-descending.svg +0 -1
  280. package/src/dragscrollable-br.js +0 -261
  281. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  282. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  283. package/tests/BookReader/Mode1Up.test.js +0 -164
  284. package/tests/BookReader/utils.test.js +0 -109
  285. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  286. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  287. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  288. package/tests/karma/BookNavigator/volumes.test.js +0 -101
  289. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,441 @@
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';
6
+ import { arrChanged, calcScreenDPI, genToArray, sum, throttle } from './utils';
7
+ import { HTMLDimensionsCacher } from "./utils/HTMLDimensionsCacher";
8
+ import { ScrollClassAdder } from './utils/ScrollClassAdder';
9
+ /** @typedef {import('./BookModel').BookModel} BookModel */
10
+ /** @typedef {import('./BookModel').PageIndex} PageIndex */
11
+ /** @typedef {import('./BookModel').PageModel} PageModel */
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
+ // it's constructor :/
18
+ /** @implements {SmoothZoomable} */
19
+ @customElement('br-mode-1up')
20
+ export class Mode1UpLit 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
+ /** @type {PageModel[]} */
35
+ @property({ type: Array })
36
+ pages = [];
37
+
38
+ /** @type {Record<PageIndex, number>} in world coordinates (inches) */
39
+ @property({ type: Object })
40
+ pageTops = {};
41
+
42
+ /************** SCALE-RELATED PROPERTIES **************/
43
+
44
+ /** @private */
45
+ screenDPI = calcScreenDPI();
46
+
47
+ /**
48
+ * How much smaller the rendered pages are than the real-world item
49
+ *
50
+ * Mode1Up doesn't use the br.reduce because it is DPI aware. The reduction factor
51
+ * of a given leaf can change (since leaves can have different DPIs), but the real-world
52
+ * reduction is constant throughout.
53
+ */
54
+ realWorldReduce = 1;
55
+
56
+ @property({ type: Number })
57
+ scale = 1;
58
+ /** Position (in unit-less, [0, 1] coordinates) in client to scale around */
59
+ @property({ type: Object })
60
+ scaleCenter = { x: 0.5, y: 0.5 };
61
+
62
+ /************** VIRTUAL-SCROLLING PROPERTIES **************/
63
+
64
+ /** in world coordinates (inches) */
65
+ @property({ type: Object })
66
+ visibleRegion = {
67
+ top: 0,
68
+ left: 0,
69
+ width: 100,
70
+ height: 100,
71
+ };
72
+
73
+ /** @type {PageModel[]} */
74
+ @property({ type: Array, hasChanged: arrChanged })
75
+ visiblePages = [];
76
+
77
+ /** @type {PageModel[]} */
78
+ @property({ type: Array })
79
+ renderedPages = [];
80
+
81
+ /** @type {Record<PageIndex, PageContainer>} position in inches */
82
+ pageContainerCache = {};
83
+
84
+ /************** WORLD-RELATED PROPERTIES **************/
85
+ /**
86
+ * The world is an imaginary giant document that contains all the pages.
87
+ * The "world"'s size is used to determine how long the scroll bar should
88
+ * be, for example.
89
+ */
90
+
91
+ /** @type {HTMLElement} */
92
+ @query('.br-mode-1up__world')
93
+ $world;
94
+
95
+ worldDimensions = { width: 100, height: 100 };
96
+
97
+ get worldStyle() {
98
+ const wToR = this.worldUnitsToRenderedPixels;
99
+ return {
100
+ width: wToR(this.worldDimensions.width) + "px",
101
+ height: wToR(this.worldDimensions.height) + "px",
102
+ };
103
+ }
104
+
105
+ /** @type {HTMLElement} */
106
+ get $container() { return this; }
107
+
108
+ /** @type {HTMLElement} */
109
+ @query('.br-mode-1up__visible-world')
110
+ $visibleWorld;
111
+
112
+ /************** DOM-RELATED PROPERTIES **************/
113
+
114
+ /** @type {HTMLDimensionsCacher} Cache things like clientWidth to reduce repaints */
115
+ htmlDimensionsCacher = new HTMLDimensionsCacher(this);
116
+
117
+ smoothZoomer = new ModeSmoothZoom(this);
118
+
119
+ scrollClassAdder = new ScrollClassAdder(this, 'BRscrolling-active');
120
+
121
+ /************** CONSTANT PROPERTIES **************/
122
+
123
+ /** Vertical space between/around the pages in inches */
124
+ SPACING_IN = 0.2;
125
+
126
+ /** How much to zoom when zoom button pressed */
127
+ ZOOM_FACTOR = 1.1;
128
+
129
+ /****************************************/
130
+ /************** PUBLIC API **************/
131
+ /****************************************/
132
+
133
+ /************** MAIN PUBLIC METHODS **************/
134
+
135
+ /**
136
+ * @param {PageIndex} index
137
+ */
138
+ jumpToIndex(index, { smooth = false } = {}) {
139
+ if (smooth) {
140
+ this.style.scrollBehavior = 'smooth';
141
+ }
142
+ this.scrollTop = this.worldUnitsToVisiblePixels(this.pageTops[index] - this.SPACING_IN / 2);
143
+ // TODO: Also h center?
144
+ if (smooth) {
145
+ setTimeout(() => this.style.scrollBehavior = '', 100);
146
+ }
147
+ }
148
+
149
+ zoomIn() {
150
+ this.scale *= this.ZOOM_FACTOR;
151
+ }
152
+
153
+ zoomOut() {
154
+ this.scale *= 1 / this.ZOOM_FACTOR;
155
+ }
156
+
157
+ /********************************************/
158
+ /************** INTERNAL STUFF **************/
159
+ /********************************************/
160
+
161
+ /************** LIFE CYCLE **************/
162
+
163
+ /**
164
+ * @param {BookModel} book
165
+ * @param {BookReader} br
166
+ */
167
+ constructor(book, br) {
168
+ super();
169
+ this.book = book;
170
+
171
+ /** @type {BookReader} */
172
+ this.br = br;
173
+ }
174
+
175
+ /** @override */
176
+ firstUpdated(changedProps) {
177
+ super.firstUpdated(changedProps);
178
+ this.htmlDimensionsCacher.updateClientSizes();
179
+ this.smoothZoomer.attach();
180
+ }
181
+
182
+ /**
183
+ * @param {PageIndex} startIndex
184
+ */
185
+ initFirstRender(startIndex) {
186
+ const page = this.book.getPage(startIndex);
187
+ this.scale = this.computeDefaultScale(page);
188
+ }
189
+
190
+ /** @override */
191
+ updated(changedProps) {
192
+ // this.X is the new value
193
+ // changedProps.get('X') is the old value
194
+ if (changedProps.has('book')) {
195
+ this.pages = genToArray(this.book.pagesIterator({ combineConsecutiveUnviewables: true }));
196
+ }
197
+ if (changedProps.has('pages')) {
198
+ this.worldDimensions = this.computeWorldDimensions();
199
+ this.pageTops = this.computePageTops(this.pages, this.SPACING_IN);
200
+ }
201
+ if (changedProps.has('visibleRegion')) {
202
+ this.visiblePages = this.computeVisiblePages();
203
+ }
204
+ if (changedProps.has('visiblePages')) {
205
+ this.throttledUpdateRenderedPages();
206
+ this.br.displayedIndices = this.visiblePages.map(p => p.index);
207
+ this.br.updateFirstIndex(this.br.displayedIndices[0]);
208
+ this.br._components.navbar.updateNavIndexThrottled();
209
+ }
210
+ if (changedProps.has('scale')) {
211
+ const oldVal = changedProps.get('scale');
212
+ // Need to set this scale to actually scale the pages
213
+ this.$visibleWorld.style.transform = `scale(${this.scale})`;
214
+ this.updateViewportOnZoom(this.scale, oldVal);
215
+ // Need to set this scale to update the world size, so the scrollbar gets the correct size
216
+ this.$world.style.transform = `scale(${this.scale})`;
217
+ }
218
+ }
219
+
220
+ /** @override */
221
+ connectedCallback() {
222
+ super.connectedCallback();
223
+ this.htmlDimensionsCacher.attachResizeListener();
224
+ this.attachScrollListeners();
225
+ this.smoothZoomer.attach();
226
+ }
227
+
228
+ /** @override */
229
+ disconnectedCallback() {
230
+ this.htmlDimensionsCacher.detachResizeListener();
231
+ this.detachScrollListeners();
232
+ this.smoothZoomer.detach();
233
+ super.disconnectedCallback();
234
+ }
235
+
236
+ /************** LIT CONFIGS **************/
237
+
238
+ /** @override */
239
+ createRenderRoot() {
240
+ // Disable shadow DOM; that would require a huge rejiggering of CSS
241
+ return this;
242
+ }
243
+
244
+ /************** COORDINATE SPACE CONVERTERS **************/
245
+ /**
246
+ * There are a few different "coordinate spaces" at play in BR:
247
+ * (1) World units: i.e. inches. Unless otherwise stated, all computations
248
+ * are done in world units.
249
+ * (2) Rendered Pixels: i.e. img.width = '300'. Note this does _not_ take
250
+ * into account zoom scaling.
251
+ * (3) Visible Pixels: Just rendered pixels, but taking into account scaling.
252
+ */
253
+
254
+ worldUnitsToRenderedPixels = (/** @type {number} */inches) => inches * this.screenDPI / this.realWorldReduce;
255
+ renderedPixelsToWorldUnits = (/** @type {number} */px) => px * this.realWorldReduce / this.screenDPI;
256
+
257
+ renderedPixelsToVisiblePixels = (/** @type {number} */px) => px * this.scale;
258
+ visiblePixelsToRenderedPixels = (/** @type {number} */px) => px / this.scale;
259
+
260
+ worldUnitsToVisiblePixels = (/** @type {number} */px) => this.renderedPixelsToVisiblePixels(this.worldUnitsToRenderedPixels(px));
261
+ visiblePixelsToWorldUnits = (/** @type {number} */px) => this.renderedPixelsToWorldUnits(this.visiblePixelsToRenderedPixels(px));
262
+
263
+ /************** RENDERING **************/
264
+
265
+ /** @override */
266
+ render() {
267
+ return html`
268
+ <div class="br-mode-1up__world" style=${styleMap(this.worldStyle)}></div>
269
+ <div class="br-mode-1up__visible-world">
270
+ ${this.renderedPages.map(p => this.renderPage(p))}
271
+ </div>`;
272
+ }
273
+
274
+ /** @param {PageModel} page */
275
+ createPageContainer = (page) => {
276
+ return this.pageContainerCache[page.index] || (
277
+ this.pageContainerCache[page.index] = (
278
+ // @ts-ignore I know it's protected, TS! But Mode1Up and BookReader are friends.
279
+ this.br._createPageContainer(page.index)
280
+ )
281
+ );
282
+ }
283
+
284
+ /** @param {PageModel} page */
285
+ renderPage = (page) => {
286
+ const wToR = this.worldUnitsToRenderedPixels;
287
+ const wToV = this.worldUnitsToVisiblePixels;
288
+ const containerWidth = this.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
289
+
290
+ const width = wToR(page.widthInches);
291
+ const height = wToR(page.heightInches);
292
+ const left = Math.max(this.SPACING_IN, (containerWidth - page.widthInches) / 2);
293
+ const top = this.pageTops[page.index];
294
+
295
+ const transform = `translate(${wToR(left)}px, ${wToR(top)}px)`;
296
+ const pageContainerEl = this.createPageContainer(page)
297
+ .update({
298
+ dimensions: {
299
+ width,
300
+ height,
301
+ top: 0,
302
+ left: 0,
303
+ },
304
+ reduce: page.width / wToV(page.widthInches),
305
+ }).$container[0];
306
+
307
+ pageContainerEl.style.transform = transform;
308
+ pageContainerEl.classList.toggle('BRpage-visible', this.visiblePages.includes(page));
309
+ return pageContainerEl;
310
+ }
311
+
312
+ /************** VIRTUAL SCROLLING LOGIC **************/
313
+
314
+ updateVisibleRegion = () => {
315
+ const { scrollTop, scrollLeft } = this;
316
+ // clientHeight excludes scrollbars, which is good.
317
+ const clientWidth = this.htmlDimensionsCacher.clientWidth;
318
+ const clientHeight = this.htmlDimensionsCacher.clientHeight;
319
+
320
+ // Note: scrollTop, and clientWidth all are in visible space;
321
+ // i.e. they are affects by the CSS transforms.
322
+
323
+ const vToW = this.visiblePixelsToWorldUnits;
324
+ this.visibleRegion = {
325
+ top: vToW(scrollTop),
326
+ height: vToW(clientHeight),
327
+ // TODO: These are very likely wrong
328
+ left: vToW(scrollLeft),
329
+ width: vToW(clientWidth),
330
+ };
331
+ }
332
+
333
+ /**
334
+ * @returns {PageModel[]}
335
+ */
336
+ computeRenderedPages() {
337
+ // Also render 1 page before/after
338
+ // @ts-ignore TS doesn't understand the filtering out of null values
339
+ return [
340
+ this.visiblePages[0]?.prev,
341
+ ...this.visiblePages,
342
+ this.visiblePages[this.visiblePages.length - 1]?.next,
343
+ ]
344
+ .filter(p => p)
345
+ // Never render more than 10 pages! Usually means something is wrong
346
+ .slice(0, 10);
347
+ }
348
+
349
+ throttledUpdateRenderedPages = throttle(() => {
350
+ this.renderedPages = this.computeRenderedPages();
351
+ this.requestUpdate();
352
+ }, 100, null)
353
+
354
+ /**
355
+ * @param {PageModel[]} pages
356
+ * @param {number} spacing
357
+ */
358
+ computePageTops(pages, spacing) {
359
+ /** @type {{ [pageIndex: string]: number }} */
360
+ const result = {};
361
+ let top = spacing;
362
+ for (const page of pages) {
363
+ result[page.index] = top;
364
+ top += page.heightInches + spacing;
365
+ }
366
+ return result;
367
+ }
368
+
369
+ /**
370
+ * @param {PageModel} page
371
+ * @returns {number}
372
+ */
373
+ computeDefaultScale(page) {
374
+ // Default to real size if it fits, otherwise default to full width
375
+ const containerWidthIn = this.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
376
+ return Math.min(1, containerWidthIn / (page.widthInches + 2 * this.SPACING_IN)) || 1;
377
+ }
378
+
379
+ computeWorldDimensions() {
380
+ return {
381
+ width: Math.max(...this.pages.map(p => p.widthInches)) + 2 * this.SPACING_IN,
382
+ height:
383
+ sum(this.pages.map(p => p.heightInches)) +
384
+ (this.pages.length + 1) * this.SPACING_IN,
385
+ };
386
+ }
387
+
388
+ computeVisiblePages() {
389
+ return this.pages.filter(page => {
390
+ const PT = this.pageTops[page.index];
391
+ const PB = PT + page.heightInches;
392
+
393
+ const VT = this.visibleRegion.top;
394
+ const VB = VT + this.visibleRegion.height;
395
+ return PT <= VB && PB >= VT;
396
+ });
397
+ }
398
+
399
+ /************** ZOOMING LOGIC **************/
400
+
401
+ /**
402
+ * @param {number} newScale
403
+ * @param {number} oldScale
404
+ */
405
+ updateViewportOnZoom(newScale, oldScale) {
406
+ const container = this;
407
+ const { scrollTop: T, scrollLeft: L } = container;
408
+ const W = this.htmlDimensionsCacher.clientWidth;
409
+ const H = this.htmlDimensionsCacher.clientHeight;
410
+
411
+ // Scale factor change
412
+ const F = newScale / oldScale;
413
+
414
+ // Where in the viewport the zoom is centered on
415
+ const XPOS = this.scaleCenter.x;
416
+ const YPOS = this.scaleCenter.y;
417
+ const oldCenter = {
418
+ x: L + XPOS * W,
419
+ y: T + YPOS * H,
420
+ };
421
+ const newCenter = {
422
+ x: F * oldCenter.x,
423
+ y: F * oldCenter.y,
424
+ };
425
+ container.scrollTop = newCenter.y - YPOS * H;
426
+ container.scrollLeft = newCenter.x - XPOS * W;
427
+ this.updateVisibleRegion();
428
+ }
429
+
430
+ /************** INPUT HANDLERS **************/
431
+
432
+ attachScrollListeners = () => {
433
+ this.addEventListener("scroll", this.updateVisibleRegion);
434
+ this.scrollClassAdder.attach();
435
+ }
436
+
437
+ detachScrollListeners = () => {
438
+ this.removeEventListener("scroll", this.updateVisibleRegion);
439
+ this.scrollClassAdder.detach();
440
+ }
441
+ }