@internetarchive/bookreader 5.0.0-95 → 5.0.0-96

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 (305) hide show
  1. package/BookReader/BookReader.css +2251 -0
  2. package/BookReader/BookReader.js +3 -0
  3. package/BookReader/BookReader.js.LICENSE.txt +72 -0
  4. package/BookReader/BookReader.js.map +1 -0
  5. package/BookReader/hypothesis/LICENSE +50 -0
  6. package/BookReader/hypothesis/README.md +55 -0
  7. package/BookReader/hypothesis/build/boot.js +1 -0
  8. package/BookReader/hypothesis/build/manifest.json +20 -0
  9. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +184 -0
  10. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  11. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +798 -0
  12. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  13. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +711 -0
  14. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/styles/annotator.css +2235 -0
  16. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  17. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  18. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  19. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  20. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  38. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  39. package/BookReader/hypothesis/build/styles/katex.min.css +2 -0
  40. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  41. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +2 -0
  42. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/sidebar.css +2731 -0
  44. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/ui-playground.css +2659 -0
  46. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  47. package/BookReader/hypothesis/package.json +126 -0
  48. package/BookReader/ia-bookreader-bundle.js +1782 -0
  49. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  50. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  51. package/BookReader/icons/1up.svg +1 -0
  52. package/BookReader/icons/2up.svg +1 -0
  53. package/BookReader/icons/advance.svg +3 -0
  54. package/BookReader/icons/chevron-right.svg +1 -0
  55. package/BookReader/icons/close-circle-dark.svg +1 -0
  56. package/BookReader/icons/close-circle.svg +1 -0
  57. package/BookReader/icons/fullscreen.svg +1 -0
  58. package/BookReader/icons/fullscreen_exit.svg +1 -0
  59. package/BookReader/icons/hamburger.svg +1 -0
  60. package/BookReader/icons/left-arrow.svg +1 -0
  61. package/BookReader/icons/magnify-minus.svg +1 -0
  62. package/BookReader/icons/magnify-plus.svg +1 -0
  63. package/BookReader/icons/magnify.svg +1 -0
  64. package/BookReader/icons/pause.svg +1 -0
  65. package/BookReader/icons/play.svg +1 -0
  66. package/BookReader/icons/playback-speed.svg +1 -0
  67. package/BookReader/icons/read-aloud.svg +1 -0
  68. package/BookReader/icons/review.svg +3 -0
  69. package/BookReader/icons/thumbnails.svg +1 -0
  70. package/BookReader/icons/voice.svg +1 -0
  71. package/BookReader/icons/volume-full.svg +1 -0
  72. package/BookReader/images/BRicons.png +0 -0
  73. package/BookReader/images/BRicons.svg +5 -0
  74. package/BookReader/images/BRicons_ia.png +0 -0
  75. package/BookReader/images/back_pages.png +0 -0
  76. package/BookReader/images/book_bottom_icon.png +0 -0
  77. package/BookReader/images/book_down_icon.png +0 -0
  78. package/BookReader/images/book_left_icon.png +0 -0
  79. package/BookReader/images/book_leftmost_icon.png +0 -0
  80. package/BookReader/images/book_right_icon.png +0 -0
  81. package/BookReader/images/book_rightmost_icon.png +0 -0
  82. package/BookReader/images/book_top_icon.png +0 -0
  83. package/BookReader/images/book_up_icon.png +0 -0
  84. package/BookReader/images/books_graphic.svg +1 -0
  85. package/BookReader/images/booksplit.png +0 -0
  86. package/BookReader/images/control_pause_icon.png +0 -0
  87. package/BookReader/images/control_play_icon.png +0 -0
  88. package/BookReader/images/embed_icon.png +0 -0
  89. package/BookReader/images/hypothesis.ico +0 -0
  90. package/BookReader/images/icon-home-ia.png +0 -0
  91. package/BookReader/images/icon_OL-logo-xs.png +0 -0
  92. package/BookReader/images/icon_alert-xs.png +0 -0
  93. package/BookReader/images/icon_book.svg +1 -0
  94. package/BookReader/images/icon_bookmark.svg +1 -0
  95. package/BookReader/images/icon_close-pop.png +0 -0
  96. package/BookReader/images/icon_download.png +0 -0
  97. package/BookReader/images/icon_gear.svg +1 -0
  98. package/BookReader/images/icon_hamburger.svg +1 -0
  99. package/BookReader/images/icon_home.png +0 -0
  100. package/BookReader/images/icon_home.svg +1 -0
  101. package/BookReader/images/icon_home_ia.png +0 -0
  102. package/BookReader/images/icon_indicator.png +0 -0
  103. package/BookReader/images/icon_info.svg +1 -0
  104. package/BookReader/images/icon_one_page.svg +1 -0
  105. package/BookReader/images/icon_pause.svg +1 -0
  106. package/BookReader/images/icon_play.svg +1 -0
  107. package/BookReader/images/icon_playback-rate.svg +1 -0
  108. package/BookReader/images/icon_return.png +0 -0
  109. package/BookReader/images/icon_search_button.svg +1 -0
  110. package/BookReader/images/icon_share.svg +1 -0
  111. package/BookReader/images/icon_skip-ahead.svg +1 -0
  112. package/BookReader/images/icon_skip-back.svg +2 -0
  113. package/BookReader/images/icon_speaker.svg +1 -0
  114. package/BookReader/images/icon_speaker_open.svg +1 -0
  115. package/BookReader/images/icon_thumbnails.svg +1 -0
  116. package/BookReader/images/icon_toc.svg +1 -0
  117. package/BookReader/images/icon_two_pages.svg +1 -0
  118. package/BookReader/images/icon_zoomer.png +0 -0
  119. package/BookReader/images/loading.gif +0 -0
  120. package/BookReader/images/logo_icon.png +0 -0
  121. package/BookReader/images/marker_chap-off.png +0 -0
  122. package/BookReader/images/marker_chap-off.svg +1 -0
  123. package/BookReader/images/marker_chap-off_ia.png +0 -0
  124. package/BookReader/images/marker_chap-on.png +0 -0
  125. package/BookReader/images/marker_chap-on.svg +1 -0
  126. package/BookReader/images/marker_srch-on.svg +1 -0
  127. package/BookReader/images/marker_srchchap-off.png +0 -0
  128. package/BookReader/images/marker_srchchap-on.png +0 -0
  129. package/BookReader/images/nav_control-dn.png +0 -0
  130. package/BookReader/images/nav_control-dn_ia.png +0 -0
  131. package/BookReader/images/nav_control-up.png +0 -0
  132. package/BookReader/images/nav_control-up_ia.png +0 -0
  133. package/BookReader/images/nav_control.png +0 -0
  134. package/BookReader/images/one_page_mode_icon.png +0 -0
  135. package/BookReader/images/paper-badge.png +0 -0
  136. package/BookReader/images/print_icon.png +0 -0
  137. package/BookReader/images/progressbar.gif +0 -0
  138. package/BookReader/images/right_edges.png +0 -0
  139. package/BookReader/images/slider.png +0 -0
  140. package/BookReader/images/slider_ia.png +0 -0
  141. package/BookReader/images/thumbnail_mode_icon.png +0 -0
  142. package/BookReader/images/transparent.png +0 -0
  143. package/BookReader/images/two_page_mode_icon.png +0 -0
  144. package/BookReader/images/unviewable_page.png +0 -0
  145. package/BookReader/images/zoom_in_icon.png +0 -0
  146. package/BookReader/images/zoom_out_icon.png +0 -0
  147. package/BookReader/jquery-3.js +2 -0
  148. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  149. package/BookReader/plugins/plugin.archive_analytics.js +2 -0
  150. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -0
  151. package/BookReader/plugins/plugin.autoplay.js +2 -0
  152. package/BookReader/plugins/plugin.autoplay.js.map +1 -0
  153. package/BookReader/plugins/plugin.chapters.js +26 -0
  154. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  155. package/BookReader/plugins/plugin.chapters.js.map +1 -0
  156. package/BookReader/plugins/plugin.experiments.js +3 -0
  157. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  158. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  159. package/BookReader/plugins/plugin.iframe.js +2 -0
  160. package/BookReader/plugins/plugin.iframe.js.map +1 -0
  161. package/BookReader/plugins/plugin.iiif.js +2 -0
  162. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  163. package/BookReader/plugins/plugin.resume.js +2 -0
  164. package/BookReader/plugins/plugin.resume.js.map +1 -0
  165. package/BookReader/plugins/plugin.search.js +3 -0
  166. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  167. package/BookReader/plugins/plugin.search.js.map +1 -0
  168. package/BookReader/plugins/plugin.text_selection.js +3 -0
  169. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  170. package/BookReader/plugins/plugin.text_selection.js.map +1 -0
  171. package/BookReader/plugins/plugin.tts.js +3 -0
  172. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +29 -0
  173. package/BookReader/plugins/plugin.tts.js.map +1 -0
  174. package/BookReader/plugins/plugin.url.js +2 -0
  175. package/BookReader/plugins/plugin.url.js.map +1 -0
  176. package/BookReader/plugins/plugin.vendor-fullscreen.js +2 -0
  177. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -0
  178. package/BookReader/webcomponents-bundle.js +3 -0
  179. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  180. package/BookReader/webcomponents-bundle.js.map +1 -0
  181. package/package.json +6 -1
  182. package/src/BookReader/BookModel.js +564 -0
  183. package/src/BookReader/DragScrollable.js +233 -0
  184. package/src/BookReader/ImageCache.js +149 -0
  185. package/src/BookReader/Mode1Up.js +110 -0
  186. package/src/BookReader/Mode1UpLit.js +388 -0
  187. package/src/BookReader/Mode2Up.js +107 -0
  188. package/src/BookReader/Mode2UpLit.js +777 -0
  189. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  190. package/src/BookReader/ModeSmoothZoom.js +312 -0
  191. package/src/BookReader/ModeThumb.js +344 -0
  192. package/src/BookReader/Navbar/Navbar.js +355 -0
  193. package/src/BookReader/PageContainer.js +172 -0
  194. package/src/BookReader/ReduceSet.js +26 -0
  195. package/src/BookReader/Toolbar/Toolbar.js +362 -0
  196. package/src/BookReader/events.js +19 -0
  197. package/src/BookReader/options.js +387 -0
  198. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  199. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  200. package/src/BookReader/utils/SelectionObserver.js +45 -0
  201. package/src/BookReader/utils/classes.js +36 -0
  202. package/src/BookReader/utils.js +313 -0
  203. package/.eslintrc.cjs +0 -51
  204. package/.gitattributes +0 -2
  205. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  206. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  207. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  208. package/.github/workflows/node.js.yml +0 -102
  209. package/.github/workflows/npm-publish.yml +0 -23
  210. package/.testcaferc.cjs +0 -10
  211. package/BookReaderDemo/BookReaderDemo.css +0 -40
  212. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -112
  213. package/BookReaderDemo/BookReaderJSSimple.js +0 -56
  214. package/BookReaderDemo/IADemoBr.js +0 -149
  215. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  216. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  217. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  218. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  219. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  220. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  221. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  222. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  223. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  224. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  225. package/BookReaderDemo/demo-advanced.html +0 -33
  226. package/BookReaderDemo/demo-embed-iframe-src.html +0 -85
  227. package/BookReaderDemo/demo-embed.html +0 -26
  228. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -34
  229. package/BookReaderDemo/demo-fullscreen.html +0 -31
  230. package/BookReaderDemo/demo-iiif.html +0 -121
  231. package/BookReaderDemo/demo-internetarchive.html +0 -271
  232. package/BookReaderDemo/demo-multiple.html +0 -44
  233. package/BookReaderDemo/demo-preview-pages.html +0 -1093
  234. package/BookReaderDemo/demo-simple.html +0 -35
  235. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -34
  236. package/BookReaderDemo/ia-multiple-volumes-manifest.js +0 -169
  237. package/BookReaderDemo/immersion-1up.html +0 -64
  238. package/BookReaderDemo/immersion-mode.html +0 -33
  239. package/BookReaderDemo/toggle_controls.html +0 -54
  240. package/BookReaderDemo/view_mode.html +0 -40
  241. package/BookReaderDemo/viewmode-cycle.html +0 -40
  242. package/CHANGELOG.md +0 -1087
  243. package/CONTRIBUTING.md +0 -7
  244. package/babel.config.cjs +0 -20
  245. package/codecov.yml +0 -23
  246. package/index.html +0 -34
  247. package/netlify.toml +0 -9
  248. package/renovate.json +0 -52
  249. package/screenshot.png +0 -0
  250. package/scripts/postversion.js +0 -11
  251. package/scripts/preversion.js +0 -15
  252. package/scripts/version.js +0 -24
  253. package/tests/e2e/README.md +0 -112
  254. package/tests/e2e/autoplay.test.js +0 -16
  255. package/tests/e2e/base.test.js +0 -27
  256. package/tests/e2e/helpers/base.js +0 -263
  257. package/tests/e2e/helpers/debug.js +0 -13
  258. package/tests/e2e/helpers/mockSearch.js +0 -90
  259. package/tests/e2e/helpers/params.js +0 -17
  260. package/tests/e2e/helpers/rightToLeft.js +0 -23
  261. package/tests/e2e/helpers/search.js +0 -73
  262. package/tests/e2e/models/BookReader.js +0 -11
  263. package/tests/e2e/models/Navigation.js +0 -39
  264. package/tests/e2e/rightToLeft.test.js +0 -19
  265. package/tests/e2e/viewmode.test.js +0 -44
  266. package/tests/jest/BookNavigator/book-navigator.test.js +0 -653
  267. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +0 -43
  268. package/tests/jest/BookNavigator/bookmarks/bookmark-edit.test.js +0 -132
  269. package/tests/jest/BookNavigator/bookmarks/bookmarks-list.test.js +0 -221
  270. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +0 -45
  271. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +0 -67
  272. package/tests/jest/BookNavigator/downloads/downloads.test.js +0 -53
  273. package/tests/jest/BookNavigator/search/search-provider.test.js +0 -179
  274. package/tests/jest/BookNavigator/search/search-results.test.js +0 -289
  275. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +0 -49
  276. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +0 -80
  277. package/tests/jest/BookNavigator/visual-adjustments.test.js +0 -200
  278. package/tests/jest/BookReader.keyboard.test.js +0 -190
  279. package/tests/jest/BookReader.options.test.js +0 -47
  280. package/tests/jest/BookReader.test.js +0 -316
  281. package/tests/jest/plugins/plugin.archive_analytics.test.js +0 -20
  282. package/tests/jest/plugins/plugin.autoplay.test.js +0 -35
  283. package/tests/jest/plugins/plugin.chapters.test.js +0 -193
  284. package/tests/jest/plugins/plugin.iframe.test.js +0 -42
  285. package/tests/jest/plugins/plugin.resume.test.js +0 -85
  286. package/tests/jest/plugins/plugin.text_selection.test.js +0 -447
  287. package/tests/jest/plugins/plugin.vendor-fullscreen.test.js +0 -65
  288. package/tests/jest/plugins/search/plugin.search.test.js +0 -120
  289. package/tests/jest/plugins/search/plugin.search.view.test.js +0 -131
  290. package/tests/jest/plugins/search/utils.js +0 -25
  291. package/tests/jest/plugins/search/utils.test.js +0 -29
  292. package/tests/jest/plugins/tts/AbstractTTSEngine.test.js +0 -173
  293. package/tests/jest/plugins/tts/FestivalTTSEngine.test.js +0 -59
  294. package/tests/jest/plugins/tts/PageChunk.test.js +0 -57
  295. package/tests/jest/plugins/tts/PageChunkIterator.test.js +0 -179
  296. package/tests/jest/plugins/tts/WebTTSEngine.test.js +0 -178
  297. package/tests/jest/plugins/tts/utils.test.js +0 -74
  298. package/tests/jest/plugins/url/UrlPlugin.test.js +0 -198
  299. package/tests/jest/plugins/url/plugin.url.test.js +0 -168
  300. package/tests/jest/setup.js +0 -3
  301. package/tests/jest/util/browserSniffing.test.js +0 -62
  302. package/tests/jest/util/docCookies.test.js +0 -24
  303. package/tests/jest/util/strings.test.js +0 -63
  304. package/tests/jest/utils.js +0 -83
  305. package/webpack.config.js +0 -97
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@internetarchive/bookreader",
3
- "version": "5.0.0-95",
3
+ "version": "5.0.0-96",
4
4
  "description": "The Internet Archive BookReader.",
5
5
  "type": "module",
6
+ "files": [
7
+ "BookReader/",
8
+ "src/",
9
+ "jsconfig.json"
10
+ ],
6
11
  "repository": {
7
12
  "type": "git",
8
13
  "url": "git+https://github.com/internetarchive/bookreader.git"
@@ -0,0 +1,564 @@
1
+ // @ts-check
2
+ import { DEFAULT_OPTIONS } from './options.js';
3
+ import { clamp } from './utils.js';
4
+ /** @typedef {import('./options.js').PageData} PageData */
5
+ /** @typedef {import('../BookReader.js').default} BookReader */
6
+
7
+ /**
8
+ * Contains information about the Book/Document independent of the way it is
9
+ * being rendering. Nothing here should reference e.g. the mode, zoom, etc.
10
+ * It's just information about the book and its pages (usually as specified
11
+ * in the BookReader data option.)
12
+ */
13
+ export class BookModel {
14
+ /**
15
+ * @param {BookReader} br
16
+ */
17
+ constructor(br) {
18
+ this.br = br;
19
+ this.reduceSet = br.reduceSet;
20
+ this.ppi = br.options?.ppi ?? DEFAULT_OPTIONS.ppi;
21
+ /** @type {'lr' | 'rl'} Page progression */
22
+ this.pageProgression = br.options?.pageProgression ?? DEFAULT_OPTIONS.pageProgression;
23
+
24
+ /** @type {{width: number, height: number}} memoize storage */
25
+ this._medianPageSize = null;
26
+ /** @type {[PageData[], number]} */
27
+ this._getDataFlattenedCached = null;
28
+ }
29
+
30
+ /** Get median width/height of page in inches. Memoized for performance. */
31
+ getMedianPageSizeInches() {
32
+ if (this._medianPageSize) {
33
+ return this._medianPageSize;
34
+ }
35
+
36
+ const widths = [];
37
+ const heights = [];
38
+ for (const page of this.pagesIterator()) {
39
+ widths.push(page.widthInches);
40
+ heights.push(page.heightInches);
41
+ }
42
+
43
+ widths.sort((a, b) => a - b);
44
+ heights.sort((a, b) => a - b);
45
+
46
+ this._medianPageSize = {
47
+ width: widths[Math.floor(widths.length / 2)],
48
+ height: heights[Math.floor(heights.length / 2)],
49
+ };
50
+ return this._medianPageSize;
51
+ }
52
+
53
+ /**
54
+ * Returns the page width for the given index, or first or last page if out of range
55
+ * @deprecated see getPageWidth
56
+ * @param {PageIndex} index
57
+ */
58
+ _getPageWidth(index) {
59
+ // Synthesize a page width for pages not actually present in book.
60
+ // May or may not be the best approach.
61
+ // If index is out of range we return the width of first or last page
62
+ index = clamp(index, 0, this.getNumLeafs() - 1);
63
+ return this.getPageWidth(index);
64
+ }
65
+
66
+ /**
67
+ * Returns the page height for the given index, or first or last page if out of range
68
+ * @deprecated see getPageHeight
69
+ * @param {PageIndex} index
70
+ */
71
+ _getPageHeight(index) {
72
+ const clampedIndex = clamp(index, 0, this.getNumLeafs() - 1);
73
+ return this.getPageHeight(clampedIndex);
74
+ }
75
+
76
+ /**
77
+ * Returns the *highest* index the given page number, or undefined
78
+ * @param {PageNumString} pageNum
79
+ * @return {PageIndex|undefined}
80
+ */
81
+ getPageIndex(pageNum) {
82
+ const pageIndices = this.getPageIndices(pageNum);
83
+ return pageIndices.length ? pageIndices[pageIndices.length - 1] : undefined;
84
+ }
85
+
86
+ /**
87
+ * Returns an array (possibly empty) of the indices with the given page number
88
+ * @param {PageNumString} pageNum
89
+ * @return {PageIndex[]}
90
+ */
91
+ getPageIndices(pageNum) {
92
+ const indices = [];
93
+
94
+ // Check for special "nXX" page number
95
+ if (pageNum.slice(0,1) == 'n') {
96
+ try {
97
+ const pageIntStr = pageNum.slice(1, pageNum.length);
98
+ const pageIndex = parseInt(pageIntStr);
99
+ indices.push(pageIndex);
100
+ return indices;
101
+ } catch (err) {
102
+ // Do nothing... will run through page names and see if one matches
103
+ }
104
+ }
105
+
106
+ for (let i = 0; i < this.getNumLeafs(); i++) {
107
+ if (this.getPageNum(i) == pageNum) {
108
+ indices.push(i);
109
+ }
110
+ }
111
+
112
+ return indices;
113
+ }
114
+
115
+ /**
116
+ * Returns the name of the page as it should be displayed in the user interface
117
+ * @param {PageIndex} index
118
+ * @return {string}
119
+ */
120
+ getPageName(index) {
121
+ return 'Page ' + this.getPageNum(index);
122
+ }
123
+
124
+ /**
125
+ * @return {number} the total number of leafs (like an array length)
126
+ */
127
+ getNumLeafs() {
128
+ // For deprecated interface support, if numLeafs is set, use that.
129
+ if (this.br.numLeafs !== undefined)
130
+ return this.br.numLeafs;
131
+ return this._getDataFlattened().length;
132
+ }
133
+
134
+ /**
135
+ * @param {PageIndex} index
136
+ * @return {Number|undefined}
137
+ */
138
+ getPageWidth(index) {
139
+ return this.getPageProp(index, 'width');
140
+ }
141
+
142
+ /**
143
+ * @param {PageIndex} index
144
+ * @return {Number|undefined}
145
+ */
146
+ getPageHeight(index) {
147
+ return this.getPageProp(index, 'height');
148
+ }
149
+
150
+ /**
151
+ * @param {PageIndex} index
152
+ * @param {number} reduce - not used in default implementation
153
+ * @param {number} rotate - not used in default implementation
154
+ * @return {string|undefined}
155
+ */
156
+ // eslint-disable-next-line no-unused-vars
157
+ getPageURI(index, reduce, rotate) {
158
+ if (!this.getPageProp(index, 'viewable', true)) {
159
+ const uri = this.br.options.unviewablePageURI;
160
+ if (uri.startsWith('.')) {
161
+ // It's a relative path, so make it relative to the images path
162
+ return this.br.options.imagesBaseURL + uri;
163
+ } else {
164
+ return uri;
165
+ }
166
+ } else {
167
+ return this.getPageProp(index, 'uri');
168
+ }
169
+ }
170
+
171
+ /**
172
+ * @param {PageIndex} index
173
+ * @return {'L' | 'R'}
174
+ */
175
+ getPageSide(index) {
176
+ return this.getPageProp(index, 'pageSide') || (index % 2 === 0 ? 'R' : 'L');
177
+ }
178
+
179
+ /**
180
+ * @param {PageIndex} index
181
+ * @return {PageNumString}
182
+ */
183
+ getPageNum(index) {
184
+ const pageNum = this.getPageProp(index, 'pageNum');
185
+ return pageNum === undefined ? `n${index}` : pageNum;
186
+ }
187
+
188
+ /**
189
+ * Generalized property accessor.
190
+ * @param {PageIndex} index
191
+ * @param {keyof PageData} propName
192
+ * @param {*} [fallbackValue] return if undefined
193
+ * @return {*|undefined}
194
+ */
195
+ getPageProp(index, propName, fallbackValue = undefined) {
196
+ return this._getDataProp(index, propName, fallbackValue);
197
+ }
198
+
199
+ /**
200
+ * This function returns the left and right indices for the user-visible
201
+ * spread that contains the given index.
202
+ * @note Can return indices out of range of what's in the book.
203
+ * @param {PageIndex} pindex
204
+ * @return {[PageIndex, PageIndex]} eg [0, 1]
205
+ */
206
+ getSpreadIndices(pindex) {
207
+ if (this.pageProgression == 'rl') {
208
+ return this.getPageSide(pindex) == 'R' ? [pindex + 1, pindex] : [pindex, pindex - 1];
209
+ } else {
210
+ return this.getPageSide(pindex) == 'L' ? [pindex, pindex + 1] : [pindex - 1, pindex];
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Single images in the Internet Archive scandata.xml metadata are (somewhat incorrectly)
216
+ * given a "leaf" number. Some of these images from the scanning process should not
217
+ * be displayed in the BookReader (for example colour calibration cards). Since some
218
+ * of the scanned images will not be displayed in the BookReader (those marked with
219
+ * addToAccessFormats false in the scandata.xml) leaf numbers and BookReader page
220
+ * indexes are generally not the same. This function returns the BookReader page
221
+ * index given a scanned leaf number.
222
+ *
223
+ * This function is used, for example, to map between search results (that use the
224
+ * leaf numbers) and the displayed pages in the BookReader.
225
+ * @param {LeafNum} leafNum
226
+ * @return {PageIndex}
227
+ */
228
+ leafNumToIndex(leafNum) {
229
+ const index = this._getDataFlattened()
230
+ .findIndex(d => d.leafNum == leafNum);
231
+ // If no match is found, fall back to the leafNum provide (leafNum == index)
232
+ return index > -1 ? index : leafNum;
233
+ }
234
+
235
+ /**
236
+ * Parses the pageString format
237
+ * @param {PageString} pageString
238
+ * @return {PageIndex|undefined}
239
+ */
240
+ parsePageString(pageString) {
241
+ let pageIndex;
242
+ // Check for special "leaf"
243
+ const leafMatch = /^leaf(\d+)/.exec(pageString);
244
+ if (leafMatch) {
245
+ pageIndex = this.leafNumToIndex(parseInt(leafMatch[1], 10));
246
+ if (pageIndex === null) {
247
+ pageIndex = undefined; // to match return type of getPageIndex
248
+ }
249
+ } else {
250
+ pageIndex = this.getPageIndex(pageString);
251
+ }
252
+ return pageIndex;
253
+ }
254
+
255
+ /**
256
+ * @param {number} index use negatives to get page relative to end
257
+ * @param loop whether to loop (i.e. -1 == last page)
258
+ */
259
+ getPage(index, loop = true) {
260
+ const numLeafs = this.getNumLeafs();
261
+ if (!loop && (index < 0 || index >= numLeafs)) {
262
+ return undefined;
263
+ }
264
+ if (index < 0 && index >= -numLeafs) {
265
+ index += numLeafs;
266
+ }
267
+ index = index % numLeafs;
268
+ return new PageModel(this, index);
269
+ }
270
+
271
+ /**
272
+ * @param {object} [arg0]
273
+ * @param {number} [arg0.start] inclusive
274
+ * @param {number} [arg0.end] exclusive
275
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Yield only first unviewable
276
+ * of a chunk of unviewable pages instead of each page
277
+ * @return {Generator<PageModel>}
278
+ */
279
+ * pagesIterator({ start = 0, end = Infinity, combineConsecutiveUnviewables = false } = {}) {
280
+ start = Math.max(0, start);
281
+ end = Math.min(end, this.getNumLeafs());
282
+
283
+ for (let i = start; i < end; i++) {
284
+ const page = this.getPage(i);
285
+ if (combineConsecutiveUnviewables && page.isConsecutiveUnviewable) continue;
286
+
287
+ yield page;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Flatten the nested structure (make 1d array), and also add pageSide prop
293
+ * @return {PageData[]}
294
+ */
295
+ _getDataFlattened() {
296
+ if (this._getDataFlattenedCached && this._getDataFlattenedCached[1] === this.br.data.length)
297
+ return this._getDataFlattenedCached[0];
298
+
299
+ let prevPageSide = null;
300
+ /** @type {number|null} */
301
+ let unviewablesChunkStart = null;
302
+ let index = 0;
303
+ // @ts-ignore TS doesn't know about flatMap for some reason
304
+ const flattened = this.br.data.flatMap(spread => {
305
+ return spread.map(page => {
306
+ if (!page.pageSide) {
307
+ if (prevPageSide === null) {
308
+ page.pageSide = spread.length === 2 ? 'L' : 'R';
309
+ } else {
310
+ page.pageSide = prevPageSide === 'L' ? 'R' : 'L';
311
+ }
312
+ }
313
+ prevPageSide = page.pageSide;
314
+
315
+ if (page.viewable === false) {
316
+ if (unviewablesChunkStart === null) {
317
+ page.unviewablesStart = unviewablesChunkStart = index;
318
+ } else {
319
+ page.unviewablesStart = unviewablesChunkStart;
320
+ }
321
+ } else {
322
+ unviewablesChunkStart = null;
323
+ }
324
+
325
+ index++;
326
+ return page;
327
+ });
328
+ });
329
+
330
+ // length is used as a cache breaker
331
+ this._getDataFlattenedCached = [flattened, this.br.data.length];
332
+ return flattened;
333
+ }
334
+
335
+ /**
336
+ * Helper. Return a prop for a given index. Returns `fallbackValue` if index is invalid or
337
+ * property not on page.
338
+ * @param {PageIndex} index
339
+ * @param {keyof PageData} prop
340
+ * @param {*} fallbackValue return if property not on the record
341
+ * @return {*}
342
+ */
343
+ _getDataProp(index, prop, fallbackValue = undefined) {
344
+ const dataf = this._getDataFlattened();
345
+ const invalidIndex = isNaN(index) || index < 0 || index >= dataf.length;
346
+ if (invalidIndex || 'undefined' == typeof(dataf[index][prop]))
347
+ return fallbackValue;
348
+ return dataf[index][prop];
349
+ }
350
+ }
351
+
352
+ /**
353
+ * A controlled schema for page data.
354
+ */
355
+ export class PageModel {
356
+ /**
357
+ * @param {BookModel} book
358
+ * @param {PageIndex} index
359
+ */
360
+ constructor(book, index) {
361
+ // Values less than 10 cause the UI to not work correctly
362
+ const pagePPI = book._getDataProp(index, 'ppi', book.ppi);
363
+ this.ppi = Math.max(pagePPI < 10 ? book.ppi : pagePPI, 10);
364
+ this.book = book;
365
+ this.index = index;
366
+ this.width = book.getPageWidth(index);
367
+ this.widthInches = this.width / this.ppi;
368
+ this.height = book.getPageHeight(index);
369
+ this.heightInches = this.height / this.ppi;
370
+ this.pageSide = book.getPageSide(index);
371
+ this.leafNum = book._getDataProp(index, 'leafNum', this.index);
372
+
373
+ /** @type {boolean} */
374
+ this.isViewable = book._getDataProp(index, 'viewable', true);
375
+ /** @type {PageIndex} The first in the series of unviewable pages this is in. */
376
+ this.unviewablesStart = book._getDataProp(index, 'unviewablesStart') || null;
377
+ /**
378
+ * Consecutive unviewable pages are pages in an unviewable "chunk" which are not the first
379
+ * of that chunk.
380
+ */
381
+ this.isConsecutiveUnviewable = !this.isViewable && this.unviewablesStart != this.index;
382
+
383
+ this._rawData = this.book._getDataFlattened()[this.index];
384
+ }
385
+
386
+ /**
387
+ * Updates the page to no longer be unviewable. Assumes the
388
+ * Page's URI is already set/correct.
389
+ */
390
+ makeViewable(newViewableState = true) {
391
+ if (this.isViewable == newViewableState) return;
392
+
393
+ if (newViewableState) {
394
+ this._rawData.viewable = true;
395
+ delete this._rawData.unviewablesStart;
396
+ // Update any subsequent page to now point to the right "start"
397
+ for (const page of this.book.pagesIterator({ start: this.index + 1 })) {
398
+ if (page.isViewable) break;
399
+ page._rawData.unviewablesStart = this.index + 1;
400
+ }
401
+ } else {
402
+ this._rawData.viewable = false;
403
+ this._rawData.unviewablesStart = (this.prev && !this.prev.isViewable) ? this.prev.unviewablesStart : this.index;
404
+ // Update any subsequent page to now point to the right "start"
405
+ for (const page of this.book.pagesIterator({ start: this.index + 1 })) {
406
+ if (!page.isViewable) break;
407
+ page._rawData.unviewablesStart = this._rawData.unviewablesStart;
408
+ }
409
+ }
410
+ }
411
+
412
+ get prev() {
413
+ return this.findPrev();
414
+ }
415
+
416
+ get next() {
417
+ return this.findNext();
418
+ }
419
+
420
+ /** @type {PageModel | null} */
421
+ get left() {
422
+ return this.book.pageProgression === 'lr' ? this.prev : this.next;
423
+ }
424
+
425
+ /** @type {PageModel | null} */
426
+ get right() {
427
+ return this.book.pageProgression === 'lr' ? this.next : this.prev;
428
+ }
429
+
430
+ /**
431
+ * @type {{left: PageModel | null, right: PageModel | null}}
432
+ */
433
+ get spread() {
434
+ return {
435
+ left: this.pageSide === 'L' ? this : this.left,
436
+ right: this.pageSide === 'R' ? this : this.right,
437
+ };
438
+ }
439
+
440
+ /**
441
+ * @param {number} pages
442
+ */
443
+ goLeft(pages) {
444
+ const newIndex = this.book.pageProgression === 'lr' ? this.index - pages : this.index + pages;
445
+ return this.book.getPage(newIndex);
446
+ }
447
+
448
+ /**
449
+ * @param {number} pages
450
+ */
451
+ goRight(pages) {
452
+ const newIndex = this.book.pageProgression === 'lr' ? this.index + pages : this.index - pages;
453
+ return this.book.getPage(newIndex);
454
+ }
455
+
456
+ /**
457
+ * @param {number} reduce
458
+ * @param {number} rotate
459
+ */
460
+ getURI(reduce, rotate) {
461
+ return this.book.getPageURI(this.index, reduce, rotate);
462
+ }
463
+
464
+ /**
465
+ * Return the asserted page number for this page, or, if one is not
466
+ * present, the n-prefixed page index.
467
+ * @returns {PageNumString}
468
+ */
469
+ getPageNum() {
470
+ return this.book.getPageNum(this.index);
471
+ }
472
+
473
+ /**
474
+ * Returns the srcset with correct URIs or void string if out of range
475
+ * @param {number} reduce
476
+ * @param {number} [rotate]
477
+ */
478
+ getURISrcSet(reduce, rotate = 0) {
479
+ const { reduceSet } = this.book;
480
+ const initialReduce = reduceSet.floor(reduce);
481
+ // We don't need to repeat the initial reduce in the srcset
482
+ const topReduce = reduceSet.decr(initialReduce);
483
+ const reduces = [];
484
+ for (let r = topReduce; r >= 1; r = reduceSet.decr(r)) {
485
+ reduces.push(r);
486
+ }
487
+ return reduces
488
+ .map(r => `${this.getURI(r, rotate)} ${initialReduce / r}x`)
489
+ .join(', ');
490
+ }
491
+
492
+ /**
493
+ * @param {object} [arg0]
494
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
495
+ * of a series of unviewable pages instead of each page
496
+ * @return {PageModel|undefined}
497
+ */
498
+ findNext({ combineConsecutiveUnviewables = false } = {}) {
499
+ return this.book
500
+ .pagesIterator({ start: this.index + 1, combineConsecutiveUnviewables })
501
+ .next().value;
502
+ }
503
+
504
+ /**
505
+ * @param {object} [arg0]
506
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
507
+ * of a series of unviewable pages instead of each page
508
+ * @return {PageModel|undefined}
509
+ */
510
+ findPrev({ combineConsecutiveUnviewables = false } = {}) {
511
+ if (this.index == 0) return undefined;
512
+
513
+ if (combineConsecutiveUnviewables) {
514
+ if (this.isConsecutiveUnviewable) {
515
+ return this.book.getPage(this.unviewablesStart);
516
+ } else {
517
+ // Recursively goes backward through the book
518
+ // TODO make a reverse iterator to make it look identical to findNext
519
+ const prev = new PageModel(this.book, this.index - 1);
520
+ return prev.isViewable ? prev : prev.findPrev({ combineConsecutiveUnviewables });
521
+ }
522
+ } else {
523
+ return new PageModel(this.book, this.index - 1);
524
+ }
525
+ }
526
+
527
+ /**
528
+ * @param {object} [arg0]
529
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
530
+ * of a series of unviewable pages instead of each page
531
+ * @return {PageModel|undefined}
532
+ */
533
+ findLeft({ combineConsecutiveUnviewables = false } = {}) {
534
+ return this.book.pageProgression === 'lr' ? this.findPrev({ combineConsecutiveUnviewables }) : this.findNext({ combineConsecutiveUnviewables });
535
+ }
536
+
537
+ /**
538
+ * @param {object} [arg0]
539
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
540
+ * of a series of unviewable pages instead of each page
541
+ * @return {PageModel|undefined}
542
+ */
543
+ findRight({ combineConsecutiveUnviewables = false } = {}) {
544
+ return this.book.pageProgression === 'lr' ? this.findNext({ combineConsecutiveUnviewables }) : this.findPrev({ combineConsecutiveUnviewables });
545
+ }
546
+ }
547
+
548
+ // There are a few main ways we can reference a specific page in a book:
549
+ /**
550
+ * @typedef {string} PageNumString
551
+ * The way page numbers are usually displayed in the UI. Either
552
+ * an asserted page number if the book has one (e.g. '18', or 'A-1'),
553
+ * or the n-prefixed 0-based index (e.g. 'n7')
554
+ */
555
+ /**
556
+ * @typedef {number} LeafNum
557
+ * Internal number to IA scans. Can be 0 or 1 indexed. Unclear it it's consecutive.
558
+ */
559
+ /**
560
+ * @typedef {string} PageString
561
+ * Possible values: /^(leaf)?\d+$/ Example: 'leaf7', '18'
562
+ * If leaf-prefixed, then the number is a LeafNum. Otherwise it's a PageNumString
563
+ */
564
+ /** @typedef {number} PageIndex 0-based index of all the pages */