@internetarchive/bookreader 5.0.0-9-multiple-files → 5.0.0-90

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 (333) hide show
  1. package/.eslintrc.js +21 -19
  2. package/.github/workflows/node.js.yml +81 -7
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +505 -1442
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -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/images/unviewable_page.png +0 -0
  58. package/BookReader/jquery-3.js +2 -0
  59. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  60. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  61. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js +1 -165
  63. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  64. package/BookReader/plugins/plugin.chapters.js +22 -301
  65. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  66. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  67. package/BookReader/plugins/plugin.iframe.js +1 -74
  68. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  69. package/BookReader/plugins/plugin.iiif.js +2 -0
  70. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  71. package/BookReader/plugins/plugin.resume.js +1 -368
  72. package/BookReader/plugins/plugin.resume.js.map +1 -1
  73. package/BookReader/plugins/plugin.search.js +2 -1420
  74. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.search.js.map +1 -1
  76. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  77. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  78. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  79. package/BookReader/plugins/plugin.tts.js +2 -9193
  80. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  81. package/BookReader/plugins/plugin.tts.js.map +1 -1
  82. package/BookReader/plugins/plugin.url.js +1 -269
  83. package/BookReader/plugins/plugin.url.js.map +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  85. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  86. package/BookReader/webcomponents-bundle.js +3 -0
  87. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  88. package/BookReader/webcomponents-bundle.js.map +1 -0
  89. package/BookReaderDemo/BookReaderDemo.css +18 -19
  90. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +144 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  95. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  96. package/BookReaderDemo/demo-fullscreen.html +2 -4
  97. package/BookReaderDemo/demo-iiif.html +99 -12
  98. package/BookReaderDemo/demo-internetarchive.html +214 -18
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +526 -525
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +595 -33
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +5 -2
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +70 -62
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +0 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +10 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/book-navigator.js +590 -0
  125. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  126. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  127. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  128. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  129. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  130. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  131. package/src/BookNavigator/delete-modal-actions.js +1 -1
  132. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  133. package/src/BookNavigator/downloads/downloads.js +29 -25
  134. package/src/BookNavigator/search/search-provider.js +80 -28
  135. package/src/BookNavigator/search/search-results.js +29 -26
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/viewable-files.js +95 -0
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
  140. package/src/BookReader/BookModel.js +76 -41
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/ImageCache.js +48 -15
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +777 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +19 -13
  150. package/src/BookReader/Navbar/Navbar.js +70 -54
  151. package/src/BookReader/PageContainer.js +116 -22
  152. package/src/BookReader/ReduceSet.js +3 -3
  153. package/src/BookReader/Toolbar/Toolbar.js +14 -41
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +73 -15
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils/classes.js +1 -1
  160. package/src/BookReader/utils.js +128 -13
  161. package/src/BookReader.js +562 -1078
  162. package/src/BookReaderPlugin.js +44 -0
  163. package/src/assets/icons/close-circle-dark.svg +1 -0
  164. package/src/assets/icons/magnify-minus.svg +3 -7
  165. package/src/assets/icons/magnify-plus.svg +3 -7
  166. package/src/assets/icons/voice.svg +1 -0
  167. package/src/assets/images/unviewable_page.png +0 -0
  168. package/src/css/BookReader.scss +1 -17
  169. package/src/css/_BRBookmarks.scss +1 -1
  170. package/src/css/_BRComponent.scss +1 -1
  171. package/src/css/_BRicon.scss +8 -2
  172. package/src/css/_BRmain.scss +33 -27
  173. package/src/css/_BRnav.scss +12 -42
  174. package/src/css/_BRpages.scss +170 -42
  175. package/src/css/_BRsearch.scss +68 -230
  176. package/src/css/_BRtoolbar.scss +5 -5
  177. package/src/css/_TextSelection.scss +87 -27
  178. package/src/css/_colorbox.scss +2 -2
  179. package/src/css/_controls.scss +24 -7
  180. package/src/css/_icons.scss +7 -1
  181. package/src/ia-bookreader/ia-bookreader.js +224 -0
  182. package/src/plugins/plugin.archive_analytics.js +84 -78
  183. package/src/plugins/plugin.autoplay.js +99 -104
  184. package/src/plugins/plugin.chapters.js +237 -191
  185. package/src/plugins/plugin.iframe.js +1 -1
  186. package/src/plugins/plugin.iiif.js +141 -0
  187. package/src/plugins/plugin.resume.js +53 -50
  188. package/src/plugins/plugin.text_selection.js +503 -175
  189. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  190. package/src/plugins/search/plugin.search.js +183 -121
  191. package/src/plugins/search/utils.js +43 -0
  192. package/src/plugins/search/view.js +67 -202
  193. package/src/plugins/tts/AbstractTTSEngine.js +75 -45
  194. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  195. package/src/plugins/tts/PageChunk.js +16 -23
  196. package/src/plugins/tts/PageChunkIterator.js +11 -17
  197. package/src/plugins/tts/WebTTSEngine.js +88 -72
  198. package/src/plugins/tts/plugin.tts.js +310 -350
  199. package/src/plugins/tts/utils.js +16 -26
  200. package/src/plugins/url/UrlPlugin.js +191 -0
  201. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  202. package/src/util/browserSniffing.js +22 -0
  203. package/src/util/docCookies.js +21 -2
  204. package/src/util/strings.js +1 -0
  205. package/tests/e2e/README.md +37 -0
  206. package/tests/e2e/autoplay.test.js +9 -6
  207. package/tests/e2e/base.test.js +8 -16
  208. package/tests/e2e/helpers/base.js +55 -50
  209. package/tests/e2e/helpers/debug.js +1 -1
  210. package/tests/e2e/helpers/mockSearch.js +19 -22
  211. package/tests/e2e/helpers/params.js +17 -0
  212. package/tests/e2e/helpers/rightToLeft.js +8 -14
  213. package/tests/e2e/helpers/search.js +73 -0
  214. package/tests/e2e/models/Navigation.js +20 -37
  215. package/tests/e2e/rightToLeft.test.js +4 -5
  216. package/tests/e2e/viewmode.test.js +40 -33
  217. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  218. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  219. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  220. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  221. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  222. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  223. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  224. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  225. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
  226. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  227. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  228. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  229. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  230. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  231. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  232. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  233. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  234. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  235. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  236. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  237. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  238. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +42 -29
  239. package/tests/jest/BookReader/PageContainer.test.js +238 -0
  240. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  241. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
  242. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  243. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  244. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  245. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  246. package/tests/jest/BookReader/utils.test.js +250 -0
  247. package/tests/jest/BookReader.keyboard.test.js +190 -0
  248. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
  249. package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
  250. package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
  251. package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
  252. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  253. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
  254. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
  255. package/tests/jest/plugins/plugin.text_selection.test.js +316 -0
  256. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  257. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
  258. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +42 -9
  259. package/tests/jest/plugins/search/utils.js +25 -0
  260. package/tests/jest/plugins/search/utils.test.js +29 -0
  261. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +30 -10
  262. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  263. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  264. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  265. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  266. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  267. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  268. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +57 -18
  269. package/tests/jest/setup.js +3 -0
  270. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  271. package/tests/jest/util/docCookies.test.js +24 -0
  272. package/tests/{util → jest/util}/strings.test.js +1 -1
  273. package/tests/{utils.js → jest/utils.js} +38 -0
  274. package/webpack.config.js +16 -10
  275. package/.babelrc +0 -12
  276. package/.dependabot/config.yml +0 -6
  277. package/.testcaferc.json +0 -5
  278. package/BookReader/bookreader-component-bundle.js +0 -14330
  279. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  280. package/BookReader/bookreader-component-bundle.js.map +0 -1
  281. package/BookReader/icons/sort-ascending.svg +0 -1
  282. package/BookReader/icons/sort-descending.svg +0 -1
  283. package/BookReader/jquery-1.10.1.js +0 -108
  284. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  285. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  286. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  287. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  288. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  289. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  290. package/BookReaderDemo/IIIFBookReader.js +0 -207
  291. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  292. package/BookReaderDemo/demo-autoplay.html +0 -38
  293. package/BookReaderDemo/demo-iiif.js +0 -26
  294. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  295. package/karma.conf.js +0 -23
  296. package/src/BookNavigator/BookModel.js +0 -14
  297. package/src/BookNavigator/BookNavigator.js +0 -452
  298. package/src/BookNavigator/assets/book-loader.js +0 -27
  299. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  300. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  301. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  302. package/src/BookNavigator/search/a-search-result.js +0 -55
  303. package/src/BookNavigator/volumes/volumes-provider.js +0 -108
  304. package/src/BookNavigator/volumes/volumes.js +0 -162
  305. package/src/BookReader/DebugConsole.js +0 -54
  306. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  307. package/src/ItemNavigator/ItemNavigator.js +0 -372
  308. package/src/ItemNavigator/providers/sharing.js +0 -29
  309. package/src/assets/icons/sort-ascending.svg +0 -1
  310. package/src/assets/icons/sort-descending.svg +0 -1
  311. package/src/css/_MobileNav.scss +0 -194
  312. package/src/dragscrollable-br.js +0 -261
  313. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  314. package/src/plugins/plugin.mobile_nav.js +0 -287
  315. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  316. package/tests/BookReader/DebugConsole.test.js +0 -25
  317. package/tests/BookReader/Mode1Up.test.js +0 -164
  318. package/tests/BookReader/Mode2Up.test.js +0 -247
  319. package/tests/BookReader/PageContainer.test.js +0 -115
  320. package/tests/BookReader/utils.test.js +0 -109
  321. package/tests/e2e/helpers/desktopSearch.js +0 -72
  322. package/tests/e2e/helpers/mobileSearch.js +0 -85
  323. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  324. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  325. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  326. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  327. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  328. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  329. package/tests/plugins/plugin.autoplay.test.js +0 -52
  330. package/tests/plugins/plugin.chapters.test.js +0 -130
  331. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  332. package/tests/plugins/plugin.text_selection.test.js +0 -203
  333. package/tests/util/docCookies.test.js +0 -15
@@ -4,11 +4,6 @@ import { clamp } from './utils.js';
4
4
  /** @typedef {import('./options.js').PageData} PageData */
5
5
  /** @typedef {import('../BookReader.js').default} BookReader */
6
6
 
7
- // URI to display when a page is not viewable.
8
- // TODO Render configurable html for the user instead.
9
- // FIXME Don't reference files on archive.org
10
- const UNVIEWABLE_PAGE_URI = '/bookreader/static/preview-default.png';
11
-
12
7
  /**
13
8
  * Contains information about the Book/Document independent of the way it is
14
9
  * being rendering. Nothing here should reference e.g. the mode, zoom, etc.
@@ -23,42 +18,15 @@ export class BookModel {
23
18
  this.br = br;
24
19
  this.reduceSet = br.reduceSet;
25
20
  this.ppi = br.options?.ppi ?? DEFAULT_OPTIONS.ppi;
21
+ /** @type {'lr' | 'rl'} Page progression */
22
+ this.pageProgression = br.options?.pageProgression ?? DEFAULT_OPTIONS.pageProgression;
26
23
 
27
24
  /** @type {{width: number, height: number}} memoize storage */
28
25
  this._medianPageSize = null;
29
- /** @deprecated @type {{width: number, height: number}} memoize storage */
30
- this._medianPageSizePixels = null;
31
26
  /** @type {[PageData[], number]} */
32
27
  this._getDataFlattenedCached = null;
33
28
  }
34
29
 
35
- /**
36
- * @deprecated Use getMedianPageSizeInches
37
- * Memoized
38
- * @return {{width: number, height: number}}
39
- */
40
- getMedianPageSize() {
41
- if (this._medianPageSizePixels) {
42
- return this._medianPageSizePixels;
43
- }
44
-
45
- // A little expensive but we just do it once
46
- const widths = [];
47
- const heights = [];
48
- for (let i = 0; i < this.getNumLeafs(); i++) {
49
- widths.push(this.getPageWidth(i));
50
- heights.push(this.getPageHeight(i));
51
- }
52
-
53
- widths.sort();
54
- heights.sort();
55
- this._medianPageSizePixels = {
56
- width: widths[Math.floor(widths.length / 2)],
57
- height: heights[Math.floor(heights.length / 2)]
58
- };
59
- return this._medianPageSizePixels;
60
- }
61
-
62
30
  /** Get median width/height of page in inches. Memoized for performance. */
63
31
  getMedianPageSizeInches() {
64
32
  if (this._medianPageSize) {
@@ -72,12 +40,12 @@ export class BookModel {
72
40
  heights.push(page.heightInches);
73
41
  }
74
42
 
75
- widths.sort();
76
- heights.sort();
43
+ widths.sort((a, b) => a - b);
44
+ heights.sort((a, b) => a - b);
77
45
 
78
46
  this._medianPageSize = {
79
47
  width: widths[Math.floor(widths.length / 2)],
80
- height: heights[Math.floor(heights.length / 2)]
48
+ height: heights[Math.floor(heights.length / 2)],
81
49
  };
82
50
  return this._medianPageSize;
83
51
  }
@@ -187,7 +155,17 @@ export class BookModel {
187
155
  */
188
156
  // eslint-disable-next-line no-unused-vars
189
157
  getPageURI(index, reduce, rotate) {
190
- return !this.getPageProp(index, 'viewable', true) ? UNVIEWABLE_PAGE_URI : this.getPageProp(index, 'uri');
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
+ }
191
169
  }
192
170
 
193
171
  /**
@@ -226,7 +204,7 @@ export class BookModel {
226
204
  * @return {[PageIndex, PageIndex]} eg [0, 1]
227
205
  */
228
206
  getSpreadIndices(pindex) {
229
- if (this.br.pageProgression == 'rl') {
207
+ if (this.pageProgression == 'rl') {
230
208
  return this.getPageSide(pindex) == 'R' ? [pindex + 1, pindex] : [pindex, pindex - 1];
231
209
  } else {
232
210
  return this.getPageSide(pindex) == 'L' ? [pindex, pindex + 1] : [pindex - 1, pindex];
@@ -379,8 +357,9 @@ export class PageModel {
379
357
  * @param {PageIndex} index
380
358
  */
381
359
  constructor(book, index) {
382
- // TODO: Get default from config
383
- this.ppi = book._getDataProp(index, 'ppi', book.ppi);
360
+ // Values less than 10 cause the UI to not work correctly
361
+ const pagePPI = book._getDataProp(index, 'ppi', book.ppi);
362
+ this.ppi = Math.max(pagePPI < 10 ? book.ppi : pagePPI, 10);
384
363
  this.book = book;
385
364
  this.index = index;
386
365
  this.width = book.getPageWidth(index);
@@ -437,6 +416,42 @@ export class PageModel {
437
416
  return this.findNext();
438
417
  }
439
418
 
419
+ /** @type {PageModel | null} */
420
+ get left() {
421
+ return this.book.pageProgression === 'lr' ? this.prev : this.next;
422
+ }
423
+
424
+ /** @type {PageModel | null} */
425
+ get right() {
426
+ return this.book.pageProgression === 'lr' ? this.next : this.prev;
427
+ }
428
+
429
+ /**
430
+ * @type {{left: PageModel | null, right: PageModel | null}}
431
+ */
432
+ get spread() {
433
+ return {
434
+ left: this.pageSide === 'L' ? this : this.left,
435
+ right: this.pageSide === 'R' ? this : this.right,
436
+ };
437
+ }
438
+
439
+ /**
440
+ * @param {number} pages
441
+ */
442
+ goLeft(pages) {
443
+ const newIndex = this.book.pageProgression === 'lr' ? this.index - pages : this.index + pages;
444
+ return this.book.getPage(newIndex);
445
+ }
446
+
447
+ /**
448
+ * @param {number} pages
449
+ */
450
+ goRight(pages) {
451
+ const newIndex = this.book.pageProgression === 'lr' ? this.index + pages : this.index - pages;
452
+ return this.book.getPage(newIndex);
453
+ }
454
+
440
455
  /**
441
456
  * @param {number} reduce
442
457
  * @param {number} rotate
@@ -498,6 +513,26 @@ export class PageModel {
498
513
  return new PageModel(this.book, this.index - 1);
499
514
  }
500
515
  }
516
+
517
+ /**
518
+ * @param {object} [arg0]
519
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
520
+ * of a series of unviewable pages instead of each page
521
+ * @return {PageModel|void}
522
+ */
523
+ findLeft({ combineConsecutiveUnviewables = false } = {}) {
524
+ return this.book.pageProgression === 'lr' ? this.findPrev({ combineConsecutiveUnviewables }) : this.findNext({ combineConsecutiveUnviewables });
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|void}
532
+ */
533
+ findRight({ combineConsecutiveUnviewables = false } = {}) {
534
+ return this.book.pageProgression === 'lr' ? this.findNext({ combineConsecutiveUnviewables }) : this.findPrev({ combineConsecutiveUnviewables });
535
+ }
501
536
  }
502
537
 
503
538
  // There are a few main ways we can reference a specific page in a book:
@@ -0,0 +1,233 @@
1
+ // @ts-check
2
+ /*
3
+ * jQuery dragscrollable Plugin
4
+ * Based off version: 1.0 (25-Jun-2009)
5
+ * Copyright (c) 2009 Miquel Herrera
6
+ *
7
+ * Portions Copyright (c) 2010 Reg Braithwaite
8
+ * Copyright (c) 2010 Internet Archive / Michael Ang
9
+ * Copyright (c) 2016 Internet Archive / Richard Caceres
10
+ *
11
+ * Dual licensed under the MIT and GPL licenses:
12
+ * http://www.opensource.org/licenses/mit-license.php
13
+ * http://www.gnu.org/licenses/gpl.html
14
+ */
15
+
16
+ /**
17
+ * @param {string} string_of_events
18
+ * @param {string} ns
19
+ * @returns
20
+ */
21
+ function append_namespace(string_of_events, ns) {
22
+ return string_of_events
23
+ .split(' ')
24
+ .map(event_name => event_name + ns)
25
+ .join(' ');
26
+ }
27
+
28
+ function left_top(event) {
29
+ /** @type {number} */
30
+ let x;
31
+ /** @type {number} */
32
+ let y;
33
+ if (typeof(event.clientX) != 'undefined') {
34
+ x = event.clientX;
35
+ y = event.clientY;
36
+ }
37
+ else if (typeof(event.screenX) != 'undefined') {
38
+ x = event.screenX;
39
+ y = event.screenY;
40
+ }
41
+ else if (typeof(event.targetTouches) != 'undefined') {
42
+ x = event.targetTouches[0].pageX;
43
+ y = event.targetTouches[0].pageY;
44
+ }
45
+ else if (typeof(event.originalEvent) == 'undefined') {
46
+ console.error("don't understand x and y for " + event.type, event);
47
+ }
48
+ else if (typeof(event.originalEvent.clientX) != 'undefined') {
49
+ x = event.originalEvent.clientX;
50
+ y = event.originalEvent.clientY;
51
+ }
52
+ else if (typeof(event.originalEvent.screenX) != 'undefined') {
53
+ x = event.originalEvent.screenX;
54
+ y = event.originalEvent.screenY;
55
+ }
56
+ else if (typeof(event.originalEvent.targetTouches) != 'undefined') {
57
+ x = event.originalEvent.targetTouches[0].pageX;
58
+ y = event.originalEvent.targetTouches[0].pageY;
59
+ }
60
+
61
+ return { left: x, top: y };
62
+ }
63
+
64
+ const DEFAULT_OPTIONS = {
65
+ /**
66
+ * @type {String|HTMLElement} jQuery selector to apply to each wrapped element to
67
+ * find which will be the dragging elements. Defaults to the first child of scrollable
68
+ * element
69
+ */
70
+ dragSelector: '>:first',
71
+
72
+ /** Will the dragging element accept propagated events? default is yes, a propagated
73
+ * mouse event on a inner element will be accepted and processed. If set to false,
74
+ * only events originated on the draggable elements will be processed. */
75
+ acceptPropagatedEvent: true,
76
+
77
+ /**
78
+ * Prevents the event to propagate further effectively disabling other default actions
79
+ */
80
+ preventDefault: true,
81
+
82
+ dragstart: 'mousedown touchstart',
83
+ dragcontinue: 'mousemove touchmove',
84
+ dragend: 'mouseup touchend', // mouseleave
85
+ dragMinDistance: 5,
86
+ namespace: '.ds',
87
+
88
+ /** Scroll the window rather than the element */
89
+ scrollWindow: false,
90
+ };
91
+
92
+ /**
93
+ * Adds the ability to manage elements scroll by dragging
94
+ * one or more of its descendant elements. Options parameter
95
+ * allow to specifically select which inner elements will
96
+ * respond to the drag events.
97
+ * usage examples:
98
+ *
99
+ * To add the scroll by drag to the element id=viewport when dragging its
100
+ * first child accepting any propagated events
101
+ * `new DragScrollable($('#viewport')[0]);`
102
+ *
103
+ * To add the scroll by drag ability to any element div of class viewport
104
+ * when dragging its first descendant of class dragMe responding only to
105
+ * evcents originated on the '.dragMe' elements.
106
+ * ```js
107
+ * new DragScrollable($('div.viewport')[0], {
108
+ * dragSelector: '.dragMe:first',
109
+ * acceptPropagatedEvent: false
110
+ * });
111
+ * ```
112
+ *
113
+ * Notice that some 'viewports' could be nested within others but events
114
+ * would not interfere as acceptPropagatedEvent is set to false.
115
+ */
116
+ export class DragScrollable {
117
+ /**
118
+ * @param {HTMLElement} element
119
+ * @param {Partial<DEFAULT_OPTIONS>} options
120
+ */
121
+ constructor(element, options = {}) {
122
+ this.handling_element = $(element);
123
+ /** @type {typeof DEFAULT_OPTIONS} */
124
+ this.settings = $.extend({}, DEFAULT_OPTIONS, options || {});
125
+ this.firstCoord = { left: 0, top: 0 };
126
+ this.lastCoord = { left: 0, top: 0 };
127
+
128
+ this.settings.dragstart = append_namespace(this.settings.dragstart, this.settings.namespace);
129
+ this.settings.dragcontinue = append_namespace(this.settings.dragcontinue, this.settings.namespace);
130
+ //settings.dragend = append_namespace(settings.dragend, settings.namespace);
131
+
132
+ // Set mouse initiating event on the desired descendant
133
+ this.handling_element.find(this.settings.dragSelector)
134
+ .on(this.settings.dragstart, this._dragStartHandler);
135
+ }
136
+
137
+ _shouldAbort() {
138
+ const isTouchDevice = !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);
139
+ return isTouchDevice;
140
+ }
141
+
142
+ /** @param {MouseEvent} event */
143
+ _dragStartHandler = (event) => {
144
+ if (this._shouldAbort()) { return true; }
145
+
146
+ // mousedown, left click, check propagation
147
+ if (event.which > 1 ||
148
+ (!this.settings.acceptPropagatedEvent && event.target != this.handling_element[0])) {
149
+ return false;
150
+ }
151
+
152
+ // Initial coordinates will be the last when dragging
153
+ this.lastCoord = this.firstCoord = left_top(event);
154
+
155
+ this.handling_element
156
+ .on(this.settings.dragcontinue, this._dragContinueHandler)
157
+ //.on(this.settings.dragend, this._dragEndHandler)
158
+ ;
159
+
160
+ // Note, we bind using addEventListener so we can use "capture" binding
161
+ // instead of "bubble" binding
162
+ this.settings.dragend.split(' ').forEach(event_name => {
163
+ this.handling_element[0].addEventListener(event_name, this._dragEndHandler, true);
164
+ });
165
+
166
+ if (this.settings.preventDefault) {
167
+ event.preventDefault();
168
+ return false;
169
+ }
170
+ }
171
+
172
+ /** @param {MouseEvent} event */
173
+ _dragContinueHandler = (event) => { // User is dragging
174
+ // console.log('drag continue');
175
+ if (this._shouldAbort()) { return true; }
176
+
177
+ const lt = left_top(event);
178
+
179
+ // How much did the mouse move?
180
+ const delta = {
181
+ left: (lt.left - this.lastCoord.left),
182
+ top: (lt.top - this.lastCoord.top),
183
+ };
184
+
185
+ const scrollTarget = this.settings.scrollWindow ? $(window) : this.handling_element;
186
+
187
+ // Set the scroll position relative to what ever the scroll is now
188
+ scrollTarget.scrollLeft( scrollTarget.scrollLeft() - delta.left );
189
+ scrollTarget.scrollTop( scrollTarget.scrollTop() - delta.top );
190
+
191
+ // Save where the cursor is
192
+ this.lastCoord = lt;
193
+
194
+ if (this.settings.preventDefault) {
195
+ event.preventDefault();
196
+ return false;
197
+ }
198
+ }
199
+
200
+ /** @param {MouseEvent} event */
201
+ _dragEndHandler = (event) => { // Stop scrolling
202
+ //console.log('dragEndHandler');
203
+
204
+ if (this._shouldAbort()) { return true; }
205
+
206
+ this.handling_element
207
+ .off(this.settings.dragcontinue)
208
+ // Note, for some reason, even though I removeEventListener below,
209
+ // this call to unbind is still necessary. I don't know why.
210
+ .off(this.settings.dragend);
211
+
212
+ // Note, we bind using addEventListener so we can use "capture" binding
213
+ // instead of "bubble" binding
214
+ this.settings.dragend.split(' ').forEach(event_name => {
215
+ this.handling_element[0].removeEventListener(event_name, this._dragEndHandler, true);
216
+ });
217
+
218
+ // How much did the mouse move total?
219
+ const delta = {
220
+ left: Math.abs(this.lastCoord.left - this.firstCoord.left),
221
+ top: Math.abs(this.lastCoord.top - this.firstCoord.top),
222
+ };
223
+ const distance = Math.max(delta.left, delta.top);
224
+
225
+ // Allow event to propagate if min distance was not achieved
226
+ if (this.settings.preventDefault && distance > this.settings.dragMinDistance) {
227
+ event.preventDefault();
228
+ event.stopImmediatePropagation();
229
+ event.stopPropagation();
230
+ return false;
231
+ }
232
+ }
233
+ }
@@ -7,8 +7,10 @@
7
7
  /** @typedef {import("./BookModel").BookModel} BookModel */
8
8
  /** @typedef {import("./BookModel").PageIndex} PageIndex */
9
9
  /** @typedef {import("./ReduceSet").ReduceSet} ReduceSet */
10
+ /** @typedef {import("./options").BookReaderOptions} BookReaderOptions */
10
11
 
11
12
  import { Pow2ReduceSet } from "./ReduceSet";
13
+ import { DEFAULT_OPTIONS } from "./options";
12
14
 
13
15
  export class ImageCache {
14
16
  /**
@@ -16,11 +18,25 @@ export class ImageCache {
16
18
  * @param {object} opts
17
19
  * @param {boolean} [opts.useSrcSet]
18
20
  * @param {ReduceSet} [opts.reduceSet]
21
+ * @param {BookReaderOptions['renderPageURI']} [opts.renderPageURI]
19
22
  */
20
- constructor(book, { useSrcSet = false, reduceSet = Pow2ReduceSet } = {}) {
23
+ constructor(
24
+ book,
25
+ {
26
+ useSrcSet = false,
27
+ reduceSet = Pow2ReduceSet,
28
+ renderPageURI = DEFAULT_OPTIONS.renderPageURI,
29
+ } = {},
30
+ ) {
31
+ /** @type {BookModel} */
21
32
  this.book = book;
33
+ /** @type {boolean} */
22
34
  this.useSrcSet = useSrcSet;
35
+ /** @type {ReduceSet} */
23
36
  this.reduceSet = reduceSet;
37
+ /** @type {BookReaderOptions['renderPageURI']} */
38
+ this.renderPageURI = renderPageURI;
39
+
24
40
  /** @type {{ [index: number]: { reduce: number, loaded: boolean }[] }} */
25
41
  this.cache = {};
26
42
  this.defaultScale = 8;
@@ -33,19 +49,35 @@ export class ImageCache {
33
49
  *
34
50
  * @param {PageIndex} index
35
51
  * @param {Number} reduce
52
+ * @param {HTMLImageElement?} [img]
36
53
  */
37
- image(index, reduce) {
54
+ image(index, reduce, img = null) {
55
+ const finalReduce = this.getFinalReduce(index, reduce);
56
+ return this._serveImageElement(index, finalReduce, img);
57
+ }
58
+
59
+ /**
60
+ * Get the final reduce factor to use for the given index
61
+ *
62
+ * @param {PageIndex} index
63
+ * @param {Number} reduce
64
+ */
65
+ getFinalReduce(index, reduce) {
38
66
  const cachedImages = this.cache[index] || [];
39
67
  const sufficientImages = cachedImages
40
68
  .filter(x => x.loaded && x.reduce <= reduce);
69
+
41
70
  if (sufficientImages.length) {
42
71
  // Choose the largest reduction factor that meets our needs
43
72
  const bestReduce = Math.max(...sufficientImages.map(e => e.reduce));
44
- return this._serveImageElement(index, bestReduce);
73
+ // Don't need to floor here, since we know the image is in the cache
74
+ // and hence was already floor'd by the below `else` clause before
75
+ // it was added
76
+ return bestReduce;
45
77
  } else {
46
78
  // Don't use a cache entry; i.e. a fresh fetch will be made
47
79
  // for this reduce
48
- return this._serveImageElement(index, reduce);
80
+ return this.reduceSet.floor(reduce);
49
81
  }
50
82
  }
51
83
 
@@ -87,26 +119,27 @@ export class ImageCache {
87
119
  *
88
120
  * @param {PageIndex} index
89
121
  * @param {number} reduce
122
+ * @param {HTMLImageElement?} [img]
90
123
  * @returns {JQuery<HTMLImageElement>} with base image classes
91
124
  */
92
- _serveImageElement(index, reduce) {
93
- const validReduce = this.reduceSet.floor(reduce);
94
- let cacheEntry = this.cache[index]?.find(e => e.reduce == validReduce);
125
+ _serveImageElement(index, reduce, img = null) {
126
+ let cacheEntry = this.cache[index]?.find(e => e.reduce == reduce);
95
127
  if (!cacheEntry) {
96
- cacheEntry = { reduce: validReduce, loaded: false };
128
+ cacheEntry = { reduce, loaded: false };
97
129
  const entries = this.cache[index] || (this.cache[index] = []);
98
130
  entries.push(cacheEntry);
99
131
  }
100
132
  const page = this.book.getPage(index);
101
133
 
102
- const $img = $('<img />', {
103
- 'class': 'BRpageimage',
104
- 'alt': 'Book page image',
105
- src: page.getURI(validReduce, 0),
106
- })
107
- .data('reduce', validReduce);
134
+ const uri = page.getURI(reduce, 0);
135
+ const $img = $(img || document.createElement('img'))
136
+ .addClass('BRpageimage')
137
+ .attr('alt', 'Book page image')
138
+ .data('reduce', reduce)
139
+ .data('src', uri);
140
+ this.renderPageURI($img[0], uri);
108
141
  if (this.useSrcSet) {
109
- $img.attr('srcset', page.getURISrcSet(validReduce));
142
+ $img.attr('srcset', page.getURISrcSet(reduce));
110
143
  }
111
144
  if (!cacheEntry.loaded) {
112
145
  $img.one('load', () => cacheEntry.loaded = true);