@internetarchive/bookreader 5.0.0-8 → 5.0.0-80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +73 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +398 -1133
  6. package/BookReader/BookReader.js +1 -1
  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 -1
  13. package/BookReader/icons/2up.svg +1 -1
  14. package/BookReader/icons/advance.svg +1 -1
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -1
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -1
  19. package/BookReader/icons/fullscreen_exit.svg +1 -1
  20. package/BookReader/icons/hamburger.svg +1 -1
  21. package/BookReader/icons/left-arrow.svg +1 -1
  22. package/BookReader/icons/magnify-minus.svg +1 -1
  23. package/BookReader/icons/magnify-plus.svg +1 -1
  24. package/BookReader/icons/magnify.svg +1 -1
  25. package/BookReader/icons/pause.svg +1 -1
  26. package/BookReader/icons/play.svg +1 -1
  27. package/BookReader/icons/playback-speed.svg +1 -1
  28. package/BookReader/icons/read-aloud.svg +1 -1
  29. package/BookReader/icons/review.svg +1 -1
  30. package/BookReader/icons/thumbnails.svg +1 -1
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -1
  33. package/BookReader/images/BRicons.svg +3 -3
  34. package/BookReader/images/books_graphic.svg +1 -1
  35. package/BookReader/images/icon_book.svg +1 -1
  36. package/BookReader/images/icon_bookmark.svg +1 -1
  37. package/BookReader/images/icon_gear.svg +1 -1
  38. package/BookReader/images/icon_hamburger.svg +1 -1
  39. package/BookReader/images/icon_home.svg +1 -1
  40. package/BookReader/images/icon_info.svg +1 -1
  41. package/BookReader/images/icon_one_page.svg +1 -1
  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 -1
  45. package/BookReader/images/icon_search_button.svg +1 -1
  46. package/BookReader/images/icon_share.svg +1 -1
  47. package/BookReader/images/icon_skip-ahead.svg +1 -1
  48. package/BookReader/images/icon_skip-back.svg +1 -1
  49. package/BookReader/images/icon_speaker.svg +1 -1
  50. package/BookReader/images/icon_speaker_open.svg +1 -1
  51. package/BookReader/images/icon_thumbnails.svg +1 -1
  52. package/BookReader/images/icon_toc.svg +1 -1
  53. package/BookReader/images/icon_two_pages.svg +1 -1
  54. package/BookReader/images/marker_chap-off.svg +1 -1
  55. package/BookReader/images/marker_chap-on.svg +1 -1
  56. package/BookReader/images/marker_srch-on.svg +1 -1
  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 -1
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +25 -1
  64. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  65. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  66. package/BookReader/plugins/plugin.iframe.js +1 -1
  67. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  68. package/BookReader/plugins/plugin.iiif.js +2 -0
  69. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  70. package/BookReader/plugins/plugin.resume.js +1 -1
  71. package/BookReader/plugins/plugin.resume.js.map +1 -1
  72. package/BookReader/plugins/plugin.search.js +2 -1
  73. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  74. package/BookReader/plugins/plugin.search.js.map +1 -1
  75. package/BookReader/plugins/plugin.text_selection.js +2 -1
  76. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  77. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  78. package/BookReader/plugins/plugin.tts.js +1 -1
  79. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  80. package/BookReader/plugins/plugin.tts.js.map +1 -1
  81. package/BookReader/plugins/plugin.url.js +1 -1
  82. package/BookReader/plugins/plugin.url.js.map +1 -1
  83. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  85. package/BookReader/webcomponents-bundle.js +3 -0
  86. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  87. package/BookReader/webcomponents-bundle.js.map +1 -0
  88. package/BookReaderDemo/BookReaderDemo.css +18 -19
  89. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  90. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +147 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-autoplay.html +2 -3
  95. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  96. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  97. package/BookReaderDemo/demo-fullscreen.html +2 -4
  98. package/BookReaderDemo/demo-iiif.html +99 -12
  99. package/BookReaderDemo/demo-internetarchive.html +214 -18
  100. package/BookReaderDemo/demo-multiple.html +2 -1
  101. package/BookReaderDemo/demo-preview-pages.html +2 -1
  102. package/BookReaderDemo/demo-simple.html +2 -1
  103. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  104. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  105. package/BookReaderDemo/immersion-1up.html +2 -2
  106. package/BookReaderDemo/immersion-mode.html +2 -4
  107. package/BookReaderDemo/toggle_controls.html +3 -2
  108. package/BookReaderDemo/view_mode.html +2 -1
  109. package/BookReaderDemo/viewmode-cycle.html +2 -3
  110. package/CHANGELOG.md +536 -33
  111. package/README.md +14 -1
  112. package/babel.config.js +20 -0
  113. package/codecov.yml +6 -0
  114. package/index.html +4 -1
  115. package/jsconfig.json +19 -0
  116. package/netlify.toml +9 -0
  117. package/package.json +70 -60
  118. package/renovate.json +52 -0
  119. package/scripts/preversion.js +0 -1
  120. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  121. package/src/BookNavigator/assets/button-base.js +4 -2
  122. package/src/BookNavigator/assets/ia-logo.js +17 -0
  123. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  124. package/src/BookNavigator/assets/icon_close.js +1 -1
  125. package/src/BookNavigator/book-navigator.js +590 -0
  126. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  127. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  128. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  129. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  130. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  131. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  132. package/src/BookNavigator/delete-modal-actions.js +1 -1
  133. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  134. package/src/BookNavigator/downloads/downloads.js +41 -25
  135. package/src/BookNavigator/search/search-provider.js +49 -27
  136. package/src/BookNavigator/search/search-results.js +23 -9
  137. package/src/BookNavigator/sharing.js +27 -0
  138. package/src/BookNavigator/viewable-files.js +95 -0
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  140. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  141. package/src/BookReader/BookModel.js +64 -34
  142. package/src/BookReader/DragScrollable.js +233 -0
  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 +776 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +18 -12
  150. package/src/BookReader/Navbar/Navbar.js +14 -40
  151. package/src/BookReader/PageContainer.js +81 -6
  152. package/src/BookReader/ReduceSet.js +1 -1
  153. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +27 -2
  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.js +118 -13
  160. package/src/BookReader.js +427 -1061
  161. package/src/assets/icons/magnify-minus.svg +3 -7
  162. package/src/assets/icons/magnify-plus.svg +3 -7
  163. package/src/assets/icons/voice.svg +1 -0
  164. package/src/css/BookReader.scss +1 -5
  165. package/src/css/_BRBookmarks.scss +1 -1
  166. package/src/css/_BRComponent.scss +1 -1
  167. package/src/css/_BRmain.scss +16 -3
  168. package/src/css/_BRnav.scss +12 -39
  169. package/src/css/_BRpages.scss +149 -40
  170. package/src/css/_BRsearch.scss +68 -25
  171. package/src/css/_BRtoolbar.scss +5 -5
  172. package/src/css/_TextSelection.scss +87 -27
  173. package/src/css/_colorbox.scss +2 -2
  174. package/src/css/_controls.scss +20 -7
  175. package/src/css/_icons.scss +1 -1
  176. package/src/ia-bookreader/ia-bookreader.js +224 -0
  177. package/src/plugins/plugin.archive_analytics.js +3 -3
  178. package/src/plugins/plugin.autoplay.js +5 -11
  179. package/src/plugins/plugin.chapters.js +237 -191
  180. package/src/plugins/plugin.iiif.js +151 -0
  181. package/src/plugins/plugin.resume.js +3 -3
  182. package/src/plugins/plugin.text_selection.js +464 -134
  183. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  184. package/src/plugins/search/plugin.search.js +142 -125
  185. package/src/plugins/search/utils.js +43 -0
  186. package/src/plugins/search/view.js +33 -58
  187. package/src/plugins/tts/AbstractTTSEngine.js +71 -40
  188. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  189. package/src/plugins/tts/PageChunk.js +15 -21
  190. package/src/plugins/tts/PageChunkIterator.js +8 -12
  191. package/src/plugins/tts/WebTTSEngine.js +87 -71
  192. package/src/plugins/tts/plugin.tts.js +96 -127
  193. package/src/plugins/tts/utils.js +15 -25
  194. package/src/plugins/url/UrlPlugin.js +191 -0
  195. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  196. package/src/util/browserSniffing.js +22 -0
  197. package/src/util/docCookies.js +21 -2
  198. package/tests/e2e/README.md +37 -0
  199. package/tests/e2e/autoplay.test.js +2 -2
  200. package/tests/e2e/base.test.js +8 -16
  201. package/tests/e2e/helpers/base.js +53 -48
  202. package/tests/e2e/helpers/debug.js +1 -1
  203. package/tests/e2e/helpers/params.js +17 -0
  204. package/tests/e2e/helpers/rightToLeft.js +8 -14
  205. package/tests/e2e/helpers/search.js +73 -0
  206. package/tests/e2e/models/Navigation.js +20 -37
  207. package/tests/e2e/rightToLeft.test.js +4 -5
  208. package/tests/e2e/viewmode.test.js +40 -33
  209. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  210. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  211. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  212. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  213. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  214. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  215. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  216. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  217. package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
  218. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  219. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  220. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  221. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  222. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  223. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  224. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  225. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  226. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  227. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  228. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  229. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  230. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  231. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  232. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  233. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  234. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  235. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  236. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  237. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  238. package/tests/jest/BookReader/utils.test.js +229 -0
  239. package/tests/jest/BookReader.keyboard.test.js +190 -0
  240. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  241. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  242. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  243. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  244. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  245. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  246. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  247. package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
  248. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  249. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
  250. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
  251. package/tests/jest/plugins/search/utils.js +25 -0
  252. package/tests/jest/plugins/search/utils.test.js +29 -0
  253. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +29 -9
  254. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  255. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  256. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  257. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  258. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  259. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  260. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  261. package/tests/jest/setup.js +3 -0
  262. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  263. package/tests/jest/util/docCookies.test.js +24 -0
  264. package/tests/{util → jest/util}/strings.test.js +1 -1
  265. package/tests/{utils.js → jest/utils.js} +38 -0
  266. package/webpack.config.js +12 -6
  267. package/.babelrc +0 -12
  268. package/.dependabot/config.yml +0 -6
  269. package/.testcaferc.json +0 -5
  270. package/BookReader/bookreader-component-bundle.js +0 -1450
  271. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  272. package/BookReader/bookreader-component-bundle.js.map +0 -1
  273. package/BookReader/jquery-1.10.1.js +0 -2
  274. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  275. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  276. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  277. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  278. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  279. package/BookReaderDemo/IIIFBookReader.js +0 -207
  280. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  281. package/BookReaderDemo/demo-iiif.js +0 -26
  282. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  283. package/karma.conf.js +0 -23
  284. package/src/BookNavigator/BookModel.js +0 -14
  285. package/src/BookNavigator/BookNavigator.js +0 -446
  286. package/src/BookNavigator/assets/book-loader.js +0 -27
  287. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  288. package/src/BookNavigator/search/a-search-result.js +0 -55
  289. package/src/BookReader/DebugConsole.js +0 -54
  290. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  291. package/src/ItemNavigator/ItemNavigator.js +0 -376
  292. package/src/ItemNavigator/providers/sharing.js +0 -29
  293. package/src/css/_MobileNav.scss +0 -194
  294. package/src/dragscrollable-br.js +0 -261
  295. package/src/lit-wrapper.js +0 -2
  296. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  297. package/src/plugins/plugin.mobile_nav.js +0 -287
  298. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  299. package/tests/BookReader/DebugConsole.test.js +0 -25
  300. package/tests/BookReader/Mode1Up.test.js +0 -164
  301. package/tests/BookReader/Mode2Up.test.js +0 -247
  302. package/tests/BookReader/utils.test.js +0 -109
  303. package/tests/e2e/helpers/desktopSearch.js +0 -72
  304. package/tests/e2e/helpers/mobileSearch.js +0 -85
  305. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  306. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  307. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  308. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  309. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  310. package/tests/plugins/plugin.chapters.test.js +0 -130
  311. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  312. package/tests/plugins/plugin.text_selection.test.js +0 -203
  313. package/tests/util/docCookies.test.js +0 -15
package/src/BookReader.js CHANGED
@@ -19,31 +19,21 @@ This file is part of BookReader.
19
19
  The BookReader source is hosted at http://github.com/internetarchive/bookreader/
20
20
 
21
21
  */
22
- // effect.js gives acces to extra easing function (e.g. easeInOutExpo)
23
- import 'jquery-ui/ui/effect.js';
24
-
25
22
  // Needed by touch-punch
26
23
  import 'jquery-ui/ui/widget.js';
27
24
  import 'jquery-ui/ui/widgets/mouse.js';
28
25
  import 'jquery-ui-touch-punch';
29
26
 
30
- import './dragscrollable-br.js';
31
27
  import PACKAGE_JSON from '../package.json';
32
28
  import * as utils from './BookReader/utils.js';
33
29
  import { exposeOverrideable } from './BookReader/utils/classes.js';
34
- import { Navbar, getNavPageNumHtml } from './BookReader/Navbar/Navbar.js';
35
- import { DEFAULT_OPTIONS } from './BookReader/options.js';
30
+ import { Navbar } from './BookReader/Navbar/Navbar.js';
31
+ import { DEFAULT_OPTIONS, OptionsParseError } from './BookReader/options.js';
36
32
  /** @typedef {import('./BookReader/options.js').BookReaderOptions} BookReaderOptions */
37
33
  /** @typedef {import('./BookReader/options.js').ReductionFactor} ReductionFactor */
38
34
  /** @typedef {import('./BookReader/BookModel.js').PageIndex} PageIndex */
39
35
  import { EVENTS } from './BookReader/events.js';
40
- import { DebugConsole } from './BookReader/DebugConsole.js';
41
- import {
42
- Toolbar,
43
- blankInfoDiv,
44
- blankShareDiv,
45
- createPopup,
46
- } from './BookReader/Toolbar/Toolbar.js';
36
+ import { Toolbar } from './BookReader/Toolbar/Toolbar.js';
47
37
  import { BookModel } from './BookReader/BookModel.js';
48
38
  import { Mode1Up } from './BookReader/Mode1Up.js';
49
39
  import { Mode2Up } from './BookReader/Mode2Up.js';
@@ -52,10 +42,6 @@ import { ImageCache } from './BookReader/ImageCache.js';
52
42
  import { PageContainer } from './BookReader/PageContainer.js';
53
43
  import { NAMED_REDUCE_SETS } from './BookReader/ReduceSet';
54
44
 
55
- if (location.toString().indexOf('_debugShowConsole=true') != -1) {
56
- $(() => new DebugConsole().init());
57
- }
58
-
59
45
  /**
60
46
  * BookReader
61
47
  * @param {BookReaderOptions} options
@@ -152,24 +138,20 @@ BookReader.prototype.setup = function(options) {
152
138
  this.ui = options.ui;
153
139
  this.uiAutoHide = options.uiAutoHide;
154
140
 
155
- this.thumbWidth = 100; // will be overridden during prepareThumbnailView
141
+ this.thumbWidth = 100; // will be overridden during this._modes.modeThumb.prepare();
156
142
  this.thumbRowBuffer = options.thumbRowBuffer;
157
143
  this.thumbColumns = options.thumbColumns;
158
144
  this.thumbMaxLoading = options.thumbMaxLoading;
159
145
  this.thumbPadding = options.thumbPadding;
160
146
  this.displayedRows = [];
161
-
162
147
  this.displayedIndices = [];
163
- /** @deprecated Unused; will be remove in v5 */
164
- this.imgs = {};
165
- /** @deprecated No longer used; will be remove in v5 */
166
- this.prefetchedImgs = {}; //an object with numeric keys corresponding to page index, reduce
167
148
 
168
149
  this.animating = false;
169
- this.flipSpeed = options.flipSpeed;
150
+ this.flipSpeed = typeof options.flipSpeed === 'number' ? options.flipSpeed : {
151
+ 'fast': 200,
152
+ 'slow': 600,
153
+ }[options.flipSpeed] || 400;
170
154
  this.flipDelay = options.flipDelay;
171
- this.twoPagePopUp = null;
172
- this.leafEdgeTmp = null;
173
155
 
174
156
  /**
175
157
  * Represents the first displayed index
@@ -178,8 +160,7 @@ BookReader.prototype.setup = function(options) {
178
160
  * @property {number|null} firstIndex
179
161
  */
180
162
  this.firstIndex = null;
181
- this.lastDisplayableIndex2up = null;
182
- this.isFullscreenActive = false;
163
+ this.isFullscreenActive = options.startFullscreen || false;
183
164
  this.lastScroll = null;
184
165
 
185
166
  this.showLogo = options.showLogo;
@@ -212,26 +193,22 @@ BookReader.prototype.setup = function(options) {
212
193
 
213
194
  // Assign the data methods
214
195
  this.data = options.data;
215
- if (options.getNumLeafs) BookReader.prototype.getNumLeafs = options.getNumLeafs;
216
- if (options.getPageWidth) BookReader.prototype.getPageWidth = options.getPageWidth;
217
- if (options.getPageHeight) BookReader.prototype.getPageHeight = options.getPageHeight;
218
- if (options.getPageURI) BookReader.prototype.getPageURI = options.getPageURI;
219
- if (options.getPageSide) BookReader.prototype.getPageSide = options.getPageSide;
220
- if (options.getPageNum) BookReader.prototype.getPageNum = options.getPageNum;
221
- if (options.getPageProp) BookReader.prototype.getPageProp = options.getPageProp;
222
- if (options.getSpreadIndices) BookReader.prototype.getSpreadIndices = options.getSpreadIndices;
223
- if (options.leafNumToIndex) BookReader.prototype.leafNumToIndex = options.leafNumToIndex;
224
196
 
225
197
  /** @type {{[name: string]: JQuery}} */
226
198
  this.refs = {};
227
199
 
228
- /**
229
- * @private (for now) Models are largely state storing classes. This might be too much
230
- * granularity, but time will tell!
231
- */
232
- this._models = {
233
- book: new BookModel(this),
234
- };
200
+ /** The book being displayed in BookReader*/
201
+ this.book = new BookModel(this);
202
+
203
+ if (options.getNumLeafs) this.book.getNumLeafs = options.getNumLeafs.bind(this);
204
+ if (options.getPageWidth) this.book.getPageWidth = options.getPageWidth.bind(this);
205
+ if (options.getPageHeight) this.book.getPageHeight = options.getPageHeight.bind(this);
206
+ if (options.getPageURI) this.book.getPageURI = options.getPageURI.bind(this);
207
+ if (options.getPageSide) this.book.getPageSide = options.getPageSide.bind(this);
208
+ if (options.getPageNum) this.book.getPageNum = options.getPageNum.bind(this);
209
+ if (options.getPageProp) this.book.getPageProp = options.getPageProp.bind(this);
210
+ if (options.getSpreadIndices) this.book.getSpreadIndices = options.getSpreadIndices.bind(this);
211
+ if (options.leafNumToIndex) this.book.leafNumToIndex = options.leafNumToIndex.bind(this);
235
212
 
236
213
  /**
237
214
  * @private Components are 'subchunks' of bookreader functionality, usually UI related
@@ -245,14 +222,14 @@ BookReader.prototype.setup = function(options) {
245
222
  };
246
223
 
247
224
  this._modes = {
248
- mode1Up: new Mode1Up(this, this._models.book),
249
- mode2Up: new Mode2Up(this, this._models.book),
250
- modeThumb: new ModeThumb(this, this._models.book),
225
+ mode1Up: new Mode1Up(this, this.book),
226
+ mode2Up: new Mode2Up(this, this.book),
227
+ modeThumb: new ModeThumb(this, this.book),
251
228
  };
252
229
 
253
230
  /** Stores classes which we want to expose (selectively) some methods as overridable */
254
231
  this._overrideable = {
255
- '_models.book': this._models.book,
232
+ 'book': this.book,
256
233
  '_components.navbar': this._components.navbar,
257
234
  '_components.toolbar': this._components.toolbar,
258
235
  '_modes.mode1Up': this._modes.mode1Up,
@@ -261,21 +238,54 @@ BookReader.prototype.setup = function(options) {
261
238
  };
262
239
 
263
240
  /** Image cache for general image fetching */
264
- this.imageCache = new ImageCache(this._models.book, {
241
+ this.imageCache = new ImageCache(this.book, {
265
242
  useSrcSet: this.options.useSrcSet,
266
243
  reduceSet: this.reduceSet,
267
244
  });
245
+
246
+ /**
247
+ * Flag if BookReader has "focus" for keyboard shortcuts
248
+ * Initially true, set to false when:
249
+ * - BookReader scrolled out of view
250
+ * Set to true when:
251
+ * - BookReader scrolled into view
252
+ */
253
+ this.hasKeyFocus = true;
268
254
  };
269
255
 
270
- /** @deprecated unused outside Mode2Up */
271
- Object.defineProperty(BookReader.prototype, 'leafEdgeL', {
272
- get() { return this._modes.mode2Up.leafEdgeL; },
273
- set(newVal) { this._modes.mode2Up.leafEdgeL = newVal; }
274
- });
275
- /** @deprecated unused outside Mode2Up */
276
- Object.defineProperty(BookReader.prototype, 'leafEdgeR', {
277
- get() { return this._modes.mode2Up.leafEdgeR; },
278
- set(newVal) { this._modes.mode2Up.leafEdgeR = newVal; }
256
+ /**
257
+ * Get all the HTML Elements that are being/can be rendered.
258
+ * Includes cached elements which might be rendered again.
259
+ */
260
+ BookReader.prototype.getActivePageContainerElements = function() {
261
+ let containerEls = Object.values(this._modes.mode2Up.mode2UpLit.pageContainerCache).map(pc => pc.$container[0])
262
+ .concat(Object.values(this._modes.mode1Up.mode1UpLit.pageContainerCache).map(pc => pc.$container[0]));
263
+ if (this.mode == this.constModeThumb) {
264
+ containerEls = containerEls.concat(this.$('.BRpagecontainer').toArray());
265
+ }
266
+ return containerEls;
267
+ };
268
+
269
+ /**
270
+ * Get the HTML Elements for the rendered page. Note there can be more than one, since
271
+ * (at least as of writing) different modes can maintain different caches.
272
+ * @param {PageIndex} pageIndex
273
+ */
274
+ BookReader.prototype.getActivePageContainerElementsForIndex = function(pageIndex) {
275
+ return [
276
+ this._modes.mode2Up.mode2UpLit.pageContainerCache[pageIndex]?.$container?.[0],
277
+ this._modes.mode1Up.mode1UpLit.pageContainerCache[pageIndex]?.$container?.[0],
278
+ ...(this.mode == this.constModeThumb ? this.$(`.pagediv${pageIndex}`).toArray() : [])
279
+ ].filter(x => x);
280
+ };
281
+
282
+ Object.defineProperty(BookReader.prototype, 'activeMode', {
283
+ /** @return {Mode1Up | Mode2Up | ModeThumb} */
284
+ get() { return {
285
+ 1: this._modes.mode1Up,
286
+ 2: this._modes.mode2Up,
287
+ 3: this._modes.modeThumb,
288
+ }[this.mode]; },
279
289
  });
280
290
 
281
291
  /**
@@ -290,15 +300,15 @@ BookReader.util = utils;
290
300
  * @private
291
301
  */
292
302
  BookReader.prototype.extendParams = function(params, newParams) {
293
- var modifiedNewParams = $.extend({}, newParams);
303
+ const modifiedNewParams = $.extend({}, newParams);
294
304
  if ('undefined' != typeof(modifiedNewParams.page)) {
295
- var pageIndex = this._models.book.parsePageString(modifiedNewParams.page);
305
+ const pageIndex = this.book.parsePageString(modifiedNewParams.page);
296
306
  if (!isNaN(pageIndex))
297
307
  modifiedNewParams.index = pageIndex;
298
308
  delete modifiedNewParams.page;
299
309
  }
300
310
  $.extend(params, modifiedNewParams);
301
- }
311
+ };
302
312
 
303
313
  /**
304
314
  * Parses params from from various initialization contexts (url, cookie, options)
@@ -306,7 +316,7 @@ BookReader.prototype.extendParams = function(params, newParams) {
306
316
  * @return {object} the parsed params
307
317
  */
308
318
  BookReader.prototype.initParams = function() {
309
- var params = {};
319
+ const params = {};
310
320
  // Flag initializing for updateFromParams()
311
321
  params.init = true;
312
322
 
@@ -323,8 +333,8 @@ BookReader.prototype.initParams = function() {
323
333
 
324
334
  // If we have a title leaf, use that as the default instead of index 0,
325
335
  // but only use as default if book has a few pages
326
- if ('undefined' != typeof(this.titleLeaf) && this._models.book.getNumLeafs() > 2) {
327
- params.index = this._models.book.leafNumToIndex(this.titleLeaf);
336
+ if ('undefined' != typeof(this.titleLeaf) && this.book.getNumLeafs() > 2) {
337
+ params.index = this.book.leafNumToIndex(this.titleLeaf);
328
338
  } else {
329
339
  params.index = 0;
330
340
  }
@@ -355,7 +365,7 @@ BookReader.prototype.initParams = function() {
355
365
  // Check for URL plugin
356
366
  if (this.options.enableUrlPlugin) {
357
367
  // Params explicitly set in URL take precedence over all other methods
358
- var urlParams = this.paramsFromFragment(this.urlReadFragment());
368
+ let urlParams = this.paramsFromFragment(this.urlReadFragment());
359
369
 
360
370
  // Get params if hash fragment available with 'history' urlMode
361
371
  const hasHashURL = !Object.keys(urlParams).length && this.urlReadHashFragment();
@@ -377,7 +387,7 @@ BookReader.prototype.initParams = function() {
377
387
  // Check for Search plugin
378
388
  if (this.options.enableSearch) {
379
389
  // Go to first result only if no default or URL page
380
- this.goToFirstResult = !params.pageFound
390
+ this.options.goToFirstResult = !params.pageFound;
381
391
 
382
392
  // If initialSearchTerm not set
383
393
  if (!this.options.initialSearchTerm) {
@@ -389,7 +399,7 @@ BookReader.prototype.initParams = function() {
389
399
  } else {
390
400
  // If we have a query string: q=[term]
391
401
  const searchParams = new URLSearchParams(this.readQueryString());
392
- const searchTerm = searchParams.get('q')
402
+ const searchTerm = searchParams.get('q');
393
403
  if (searchTerm) {
394
404
  this.options.initialSearchTerm = utils.decodeURIComponentPlus(searchTerm);
395
405
  }
@@ -401,21 +411,21 @@ BookReader.prototype.initParams = function() {
401
411
  this.suppressFragmentChange = !params.fragmentChange;
402
412
 
403
413
  return params;
404
- }
414
+ };
405
415
 
406
416
  /**
407
417
  * Allow mocking of window.location.search
408
418
  */
409
419
  BookReader.prototype.getLocationSearch = function () {
410
420
  return window.location.search;
411
- }
421
+ };
412
422
 
413
423
  /**
414
424
  * Allow mocking of window.location.hash
415
425
  */
416
426
  BookReader.prototype.getLocationHash = function () {
417
427
  return window.location.hash;
418
- }
428
+ };
419
429
 
420
430
  /**
421
431
  * Return URL or fragment querystring
@@ -428,37 +438,63 @@ BookReader.prototype.readQueryString = function() {
428
438
  const hash = this.getLocationHash();
429
439
  const found = hash.search(/\?\w+=/);
430
440
  return found > -1 ? hash.slice(found) : '';
431
- }
441
+ };
432
442
 
433
443
  /**
434
444
  * Determines the initial mode for starting if a mode is not already
435
445
  * present in the params argument
436
446
  * @param {object} params
437
- * @return {number} the mode
447
+ * @return {1 | 2 | 3} the initial mode
438
448
  */
439
449
  BookReader.prototype.getInitialMode = function(params) {
440
- // Use params or browser width to set view mode
441
- var windowWidth = $(window).width();
442
- var nextMode;
443
- if ('undefined' != typeof(params.mode)) {
444
- nextMode = params.mode;
445
- } else if (this.ui == 'full'
446
- && this.enableMobileNav
447
- && this.isFullscreenActive
448
- && windowWidth <= this.onePageMinBreakpoint
449
- ) {
450
- // In full mode, we set the default based on width
451
- nextMode = this.constMode1up;
450
+ // if mobile breakpoint, we always show this.constMode1up mode
451
+ const windowWidth = $(window).width();
452
+ const isMobile = windowWidth && windowWidth <= this.onePageMinBreakpoint;
453
+
454
+ let initialMode;
455
+ if (params.mode) {
456
+ initialMode = params.mode;
457
+ } else if (isMobile) {
458
+ initialMode = this.constMode1up;
452
459
  } else {
453
- nextMode = this.constMode2up;
460
+ initialMode = this.constMode2up;
461
+ }
462
+
463
+ if (!this.canSwitchToMode(initialMode)) {
464
+ initialMode = this.constMode1up;
454
465
  }
455
466
 
456
- if (!this.canSwitchToMode(nextMode)) {
457
- nextMode = this.constMode1up;
467
+ // override defaults mode via `options.defaults` metadata
468
+ if (this.options.defaults) {
469
+ try {
470
+ initialMode = _modeStringToNumber(this.options.defaults);
471
+ } catch (e) {
472
+ // Can ignore this error
473
+ }
458
474
  }
459
- return nextMode;
475
+
476
+ return initialMode;
460
477
  };
461
478
 
479
+ /**
480
+ * Converts a mode string to a the mode numeric constant
481
+ * @param {'mode/1up'|'mode/2up'|'mode/thumb'} modeString
482
+ * @return {1 | 2 | 3}
483
+ */
484
+ export function _modeStringToNumber(modeString) {
485
+ const MAPPING = {
486
+ 'mode/1up': 1,
487
+ 'mode/2up': 2,
488
+ 'mode/thumb': 3,
489
+ };
490
+
491
+ if (!(modeString in MAPPING)) {
492
+ throw new OptionsParseError(`Invalid mode string: ${modeString}`);
493
+ }
494
+
495
+ return MAPPING[modeString];
496
+ }
497
+
462
498
  /**
463
499
  * This is called by the client to initialize BookReader.
464
500
  * It renders onto the DOM. It should only be called once.
@@ -467,7 +503,7 @@ BookReader.prototype.init = function() {
467
503
  this.init.initComplete = false;
468
504
  this.pageScale = this.reduce; // preserve current reduce
469
505
 
470
- var params = this.initParams();
506
+ const params = this.initParams();
471
507
 
472
508
  this.firstIndex = params.index ? params.index : 0;
473
509
 
@@ -497,19 +533,16 @@ BookReader.prototype.init = function() {
497
533
  // Explicitly ensure this.mode exists for initNavbar() below
498
534
  this.mode = params.mode;
499
535
 
500
- if (this.ui == "embed" && this.options.showNavbar) {
501
- this.initEmbedNavbar();
502
- } else {
503
- if (this.options.showToolbar) {
504
- this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
505
- }
506
- if (this.options.showNavbar) {
507
- this.initNavbar();
508
- }
536
+ // Display Navigation
537
+ if (this.options.showToolbar) {
538
+ this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
539
+ }
540
+ if (this.options.showNavbar) { // default navigation
541
+ this.initNavbar();
509
542
  }
510
543
 
511
544
  // Switch navbar controls on mobile/desktop
512
- this.switchNavbarControls();
545
+ this._components.navbar.switchNavbarControls();
513
546
 
514
547
  this.resizeBRcontainer();
515
548
  this.updateFromParams(params);
@@ -521,17 +554,17 @@ BookReader.prototype.init = function() {
521
554
  this.setupKeyListeners();
522
555
 
523
556
  this.lastScroll = (new Date().getTime());
524
- this.refs.$brContainer.bind('scroll', this, function(e) {
557
+ this.refs.$brContainer.on('scroll', this, function(e) {
525
558
  // Note, this scroll event fires for both user, and js generated calls
526
559
  // It is functioning in some cases as the primary triggerer for rendering
527
560
  e.data.lastScroll = (new Date().getTime());
528
- if (e.data.constMode2up != e.data.mode) {
561
+ if (e.data.constModeThumb == e.data.mode) {
529
562
  e.data.drawLeafsThrottled();
530
563
  }
531
564
  });
532
565
 
533
566
  if (this.options.autoResize) {
534
- $(window).bind('resize', this, function(e) {
567
+ $(window).on('resize', this, function(e) {
535
568
  e.data.resize();
536
569
  });
537
570
  $(window).on("orientationchange", this, function(e) {
@@ -548,15 +581,17 @@ BookReader.prototype.init = function() {
548
581
  this.suppressFragmentChange = false;
549
582
  }
550
583
 
584
+ if (this.options.startFullscreen) {
585
+ this.enterFullscreen(true);
586
+ }
587
+
551
588
  this.init.initComplete = true;
552
589
  this.trigger(BookReader.eventNames.PostInit);
553
590
 
554
591
  // Must be called after this.init.initComplete set to true to allow
555
592
  // BookReader.prototype.resize to run.
556
- if (this.options.startFullscreen) {
557
- this.toggleFullscreen();
558
- }
559
- }
593
+
594
+ };
560
595
 
561
596
  /**
562
597
  * @param {EVENTS} name
@@ -564,7 +599,6 @@ BookReader.prototype.init = function() {
564
599
  */
565
600
  BookReader.prototype.trigger = function(name, props = this) {
566
601
  const eventName = 'BookReader:' + name;
567
- $(document).trigger(eventName, props);
568
602
 
569
603
  utils.polyfillCustomEvent(window);
570
604
  window.dispatchEvent(new CustomEvent(eventName, {
@@ -572,14 +606,15 @@ BookReader.prototype.trigger = function(name, props = this) {
572
606
  composed: true,
573
607
  detail: { props },
574
608
  }));
609
+ $(document).trigger(eventName, props);
575
610
  };
576
611
 
577
612
  BookReader.prototype.bind = function(name, callback) {
578
- $(document).bind('BookReader:' + name, callback);
613
+ $(document).on('BookReader:' + name, callback);
579
614
  };
580
615
 
581
616
  BookReader.prototype.unbind = function(name, callback) {
582
- $(document).unbind('BookReader:' + name, callback);
617
+ $(document).off('BookReader:' + name, callback);
583
618
  };
584
619
 
585
620
  /**
@@ -591,135 +626,147 @@ BookReader.prototype.resize = function() {
591
626
  this.resizeBRcontainer();
592
627
 
593
628
  // Switch navbar controls on mobile/desktop
594
- this.switchNavbarControls();
629
+ this._components.navbar.switchNavbarControls();
595
630
 
596
631
  if (this.constMode1up == this.mode) {
597
632
  if (this.onePage.autofit != 'none') {
598
- this.resizePageView1up();
633
+ this._modes.mode1Up.resizePageView();
599
634
  this.centerPageView();
600
- if (this.enableSearch) this.updateSearchHilites(); //deletes highlights but does not call remove()
601
635
  } else {
602
636
  this.centerPageView();
603
637
  this.displayedIndices = [];
604
- if (this.enableSearch) this.updateSearchHilites(); //deletes highlights but does not call remove()
605
638
  this.drawLeafsThrottled();
606
639
  }
607
640
  } else if (this.constModeThumb == this.mode) {
608
- this.prepareThumbnailView();
641
+ this._modes.modeThumb.prepare();
609
642
  } else {
610
- // We only need to prepare again in autofit (size of spread changes)
611
- if (this.twoPage.autofit) {
612
- // most common path, esp. for archive.org books
613
- this.prepareTwoPageView();
614
- } else {
615
- // used when zoomed in
616
- // Re-center if the scrollbars have disappeared
617
- var center = this.twoPageGetViewCenter();
618
- var doRecenter = false;
619
- if (this.twoPage.totalWidth < this.refs.$brContainer.prop('clientWidth')) {
620
- center.percentageX = 0.5;
621
- doRecenter = true;
622
- }
623
- if (this.twoPage.totalHeight < this.refs.$brContainer.prop('clientHeight')) {
624
- center.percentageY = 0.5;
625
- doRecenter = true;
626
- }
627
- if (doRecenter) {
628
- this.twoPageCenterView(center.percentageX, center.percentageY);
629
- }
630
- }
643
+ this._modes.mode2Up.resizePageView();
631
644
  }
632
645
  this.trigger(BookReader.eventNames.resize);
633
646
  };
634
647
 
635
648
  /**
636
- * Binds keyboard event listeners
649
+ * Binds keyboard and keyboard focus event listeners
637
650
  */
638
- BookReader.prototype.setupKeyListeners = function() {
639
- var self = this;
640
-
641
- var KEY_PGUP = 33;
642
- var KEY_PGDOWN = 34;
643
- var KEY_END = 35;
644
- var KEY_HOME = 36;
645
-
646
- var KEY_LEFT = 37;
647
- var KEY_UP = 38;
648
- var KEY_RIGHT = 39;
649
- var KEY_DOWN = 40;
650
- // The minus(-) and equal(=) keys have different mappings for different browsers
651
- var KEY_MINUS = 189; // Chrome
652
- var KEY_MINUS_F = 173; // Firefox
653
- var KEY_NUMPAD_SUBTRACT = 109;
654
- var KEY_EQUAL = 187; // Chrome
655
- var KEY_EQUAL_F = 61; // Firefox
656
- var KEY_NUMPAD_ADD = 107;
657
-
658
- // We use document here instead of window to avoid a bug in jQuery on IE7
659
- $(document).keydown(function(e) {
660
-
661
- // Keyboard navigation
662
- if (!self.keyboardNavigationIsDisabled(e)) {
663
- switch (e.keyCode) {
664
- case KEY_PGUP:
665
- case KEY_UP:
666
- // In 1up mode page scrolling is handled by browser
667
- if (self.constMode2up == self.mode) {
668
- e.preventDefault();
669
- self.prev();
670
- }
671
- break;
672
- case KEY_DOWN:
673
- case KEY_PGDOWN:
674
- if (self.constMode2up == self.mode) {
675
- e.preventDefault();
676
- self.next();
651
+ BookReader.prototype.setupKeyListeners = function () {
652
+
653
+ // Keyboard focus by BookReader in viewport
654
+ //
655
+ // Intersection observer and callback sets BookReader keyboard
656
+ // "focus" flag off when the BookReader is not in the viewport.
657
+ if (window.IntersectionObserver) {
658
+ const observer = new IntersectionObserver((entries) => {
659
+ entries.forEach((entry) => {
660
+ if (entry.intersectionRatio === 0) {
661
+ this.hasKeyFocus = false;
662
+ } else {
663
+ this.hasKeyFocus = true;
677
664
  }
678
- break;
679
- case KEY_END:
665
+ });
666
+ }, {
667
+ root: null,
668
+ rootMargin: '0px',
669
+ threshold: [0, 0.05, 1],
670
+ });
671
+ observer.observe(this.refs.$br[0]);
672
+ }
673
+
674
+ // Keyboard listeners
675
+ document.addEventListener('keydown', (e) => {
676
+
677
+ // Ignore if BookReader "focus" flag not set
678
+ if (!this.hasKeyFocus) {
679
+ return;
680
+ }
681
+
682
+ // Ignore if modifiers are active.
683
+ if (e.getModifierState('Control') ||
684
+ e.getModifierState('Alt') ||
685
+ e.getModifierState('Meta') ||
686
+ e.getModifierState('Win') /* hack for IE */) {
687
+ return;
688
+ }
689
+
690
+ // Ignore in input elements
691
+ if (utils.isInputActive()) {
692
+ return;
693
+ }
694
+
695
+ // KeyboardEvent code values:
696
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
697
+ switch (e.key) {
698
+
699
+ // Page navigation
700
+ case "Home":
701
+ e.preventDefault();
702
+ this.first();
703
+ break;
704
+ case "End":
705
+ e.preventDefault();
706
+ this.last();
707
+ break;
708
+ case "ArrowDown":
709
+ case "PageDown":
710
+ case "Down": // hack for IE and old Gecko
711
+ // In 1up and thumb mode page scrolling handled by browser
712
+ if (this.constMode2up === this.mode) {
680
713
  e.preventDefault();
681
- self.last();
682
- break;
683
- case KEY_HOME:
714
+ this.next();
715
+ }
716
+ break;
717
+ case "ArrowUp":
718
+ case "PageUp":
719
+ case "Up": // hack for IE and old Gecko
720
+ // In 1up and thumb mode page scrolling handled by browser
721
+ if (this.constMode2up === this.mode) {
684
722
  e.preventDefault();
685
- self.first();
686
- break;
687
- case KEY_LEFT:
688
- if (self.constModeThumb != self.mode) {
689
- e.preventDefault();
690
- self.left();
691
- }
692
- break;
693
- case KEY_RIGHT:
694
- if (self.constModeThumb != self.mode) {
695
- e.preventDefault();
696
- self.right();
697
- }
698
- break;
699
- case KEY_MINUS:
700
- case KEY_MINUS_F:
701
- case KEY_NUMPAD_SUBTRACT:
723
+ this.prev();
724
+ }
725
+ break;
726
+ case "ArrowLeft":
727
+ case "Left": // hack for IE and old Gecko
728
+ // No y-scrolling in thumb mode
729
+ if (this.constModeThumb != this.mode) {
702
730
  e.preventDefault();
703
- self.zoom(-1);
704
- break;
705
- case KEY_EQUAL:
706
- case KEY_EQUAL_F:
707
- case KEY_NUMPAD_ADD:
731
+ this.left();
732
+ }
733
+ break;
734
+ case "ArrowRight":
735
+ case "Right": // hack for IE and old Gecko
736
+ // No y-scrolling in thumb mode
737
+ if (this.constModeThumb != this.mode) {
708
738
  e.preventDefault();
709
- self.zoom(+1);
710
- break;
739
+ this.right();
711
740
  }
741
+ break;
742
+ // Zoom
743
+ case '-':
744
+ case 'Subtract':
745
+ e.preventDefault();
746
+ this.zoom(-1);
747
+ break;
748
+ case '+':
749
+ case '=':
750
+ case 'Add':
751
+ e.preventDefault();
752
+ this.zoom(1);
753
+ break;
754
+ // Fullscreen
755
+ case 'F':
756
+ case 'f':
757
+ e.preventDefault();
758
+ this.toggleFullscreen();
759
+ break;
712
760
  }
713
761
  });
714
762
  };
715
763
 
716
764
  BookReader.prototype.drawLeafs = function() {
717
765
  if (this.constMode1up == this.mode) {
718
- this.drawLeafsOnePage();
719
- } else if (this.constModeThumb == this.mode) {
720
- this.drawLeafsThumbnail();
766
+ // Not needed for Mode1Up anymore
767
+ return;
721
768
  } else {
722
- this.drawLeafsTwoPage();
769
+ this.activeMode.drawLeafs();
723
770
  }
724
771
  };
725
772
 
@@ -728,7 +775,7 @@ BookReader.prototype.drawLeafs = function() {
728
775
  * @param {PageIndex} index
729
776
  */
730
777
  BookReader.prototype._createPageContainer = function(index) {
731
- return new PageContainer(this._models.book.getPage(index, false), {
778
+ return new PageContainer(this.book.getPage(index, false), {
732
779
  isProtected: this.protected,
733
780
  imageCache: this.imageCache,
734
781
  loadingImage: this.imagesBaseURL + 'loading.gif',
@@ -742,8 +789,8 @@ BookReader.prototype.bindGestures = function(jElement) {
742
789
  // when you move the book with one finger and then add another
743
790
  // finger to pinch. Gestures are aware of scroll state.
744
791
 
745
- var self = this;
746
- var numTouches = 1;
792
+ const self = this;
793
+ let numTouches = 1;
747
794
 
748
795
  jElement.unbind('touchmove').bind('touchmove', function(e) {
749
796
  if (e.originalEvent.cancelable) numTouches = e.originalEvent.touches.length;
@@ -764,24 +811,6 @@ BookReader.prototype.bindGestures = function(jElement) {
764
811
  });
765
812
  };
766
813
 
767
- /** @deprecated Not used outside ModeThumb */
768
- BookReader.prototype.drawLeafsThumbnail = ModeThumb.prototype.drawLeafs;
769
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'drawLeafs', 'drawLeafsThumbnail');
770
- /** @deprecated Not used outside ModeThumb */
771
- BookReader.prototype.lazyLoadThumbnails = ModeThumb.prototype.lazyLoadThumbnails;
772
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'lazyLoadThumbnails', 'lazyLoadThumbnails');
773
- BookReader.prototype.lazyLoadImage = ModeThumb.prototype.lazyLoadImage;
774
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'lazyLoadImage', 'lazyLoadImage');
775
- /** @deprecated Internal use only */
776
- BookReader.prototype.zoomThumb = ModeThumb.prototype.zoom;
777
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'zoom', 'zoomThumb');
778
- /** @deprecated Not used outside ModeThumb */
779
- BookReader.prototype.getThumbnailWidth = ModeThumb.prototype.getThumbnailWidth;
780
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'getThumbnailWidth', 'getThumbnailWidth');
781
- /** @deprecated Not used outside ModeThumb */
782
- BookReader.prototype.prepareThumbnailView = ModeThumb.prototype.prepare;
783
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'prepare', 'prepareThumbnailView');
784
-
785
814
  /**
786
815
  * A throttled version of drawLeafs
787
816
  */
@@ -794,29 +823,11 @@ BookReader.prototype.drawLeafsThrottled = utils.throttle(
794
823
  * @param {number} direction Pass 1 to zoom in, anything else to zoom out
795
824
  */
796
825
  BookReader.prototype.zoom = function(direction) {
797
- switch (this.mode) {
798
- case this.constMode1up:
799
- if (direction == 1) {
800
- // XXX other cases
801
- this.zoom1up('in');
802
- } else {
803
- this.zoom1up('out');
804
- }
805
- break
806
- case this.constMode2up:
807
- if (direction == 1) {
808
- // XXX other cases
809
- this.zoom2up('in');
810
- } else {
811
- this.zoom2up('out');
812
- }
813
- break
814
- case this.constModeThumb:
815
- // XXX update zoomThumb for named directions
816
- this.zoomThumb(direction);
817
- break
826
+ if (direction == 1) {
827
+ this.activeMode.zoom('in');
828
+ } else {
829
+ this.activeMode.zoom('out');
818
830
  }
819
-
820
831
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
821
832
  return;
822
833
  };
@@ -842,11 +853,11 @@ BookReader.prototype.resizeBRcontainer = function(animate) {
842
853
  bottom: this.getFooterHeight()
843
854
  });
844
855
  }
845
- }
856
+ };
846
857
 
847
858
  BookReader.prototype.centerPageView = function() {
848
- var scrollWidth = this.refs.$brContainer.prop('scrollWidth');
849
- var clientWidth = this.refs.$brContainer.prop('clientWidth');
859
+ const scrollWidth = this.refs.$brContainer.prop('scrollWidth');
860
+ const clientWidth = this.refs.$brContainer.prop('clientWidth');
850
861
  if (scrollWidth > clientWidth) {
851
862
  this.refs.$brContainer.prop('scrollLeft', (scrollWidth - clientWidth) / 2);
852
863
  }
@@ -934,7 +945,7 @@ BookReader.prototype._reduceSort = (a, b) => a.reduce - b.reduce;
934
945
  * @return {boolean} Returns true if page could be found, false otherwise.
935
946
  */
936
947
  BookReader.prototype.jumpToPage = function(pageNum) {
937
- var pageIndex = this._models.book.parsePageString(pageNum);
948
+ const pageIndex = this.book.parsePageString(pageNum);
938
949
 
939
950
  if ('undefined' != typeof(pageIndex)) {
940
951
  this.jumpToIndex(pageIndex);
@@ -950,11 +961,9 @@ BookReader.prototype.jumpToPage = function(pageNum) {
950
961
  * @param {PageIndex} index
951
962
  */
952
963
  BookReader.prototype._isIndexDisplayed = function(index) {
953
- // One up "caches" pages +- current, so exclude those in the test.
954
- return this.constMode1up == this.mode ? this.displayedIndices.slice(1, -1).includes(index) :
955
- this.displayedIndices ? this.displayedIndices.includes(index) :
956
- this.currentIndex() == index;
957
- }
964
+ return this.displayedIndices ? this.displayedIndices.includes(index) :
965
+ this.currentIndex() == index;
966
+ };
958
967
 
959
968
  /**
960
969
  * Changes the current page
@@ -965,7 +974,7 @@ BookReader.prototype._isIndexDisplayed = function(index) {
965
974
  */
966
975
  BookReader.prototype.jumpToIndex = function(index, pageX, pageY, noAnimate) {
967
976
  // Don't jump into specific unviewable page
968
- const page = this._models.book.getPage(index);
977
+ const page = this.book.getPage(index);
969
978
  if (!page.isViewable && page.unviewablesStart != page.index) {
970
979
  // If already in unviewable range, jump to end of that range
971
980
  const alreadyInPreview = this._isIndexDisplayed(page.unviewablesStart);
@@ -975,19 +984,12 @@ BookReader.prototype.jumpToIndex = function(index, pageX, pageY, noAnimate) {
975
984
 
976
985
  this.trigger(BookReader.eventNames.stop);
977
986
 
978
- if (this.constMode2up == this.mode) {
979
- this._modes.mode2Up.jumpToIndex(index);
980
- } else if (this.constModeThumb == this.mode) {
981
- this._modes.modeThumb.jumpToIndex(index);
982
- } else { // 1up
983
- this._modes.mode1Up.jumpToIndex(index, pageX, pageY, noAnimate);
984
- }
987
+ this.activeMode.jumpToIndex(index, pageX, pageY, noAnimate);
985
988
  };
986
989
 
987
990
  /**
988
991
  * Return mode or 1up if initial thumb
989
992
  * @param {number}
990
- * @see BookReader.prototype.drawLeafsThumbnail
991
993
  */
992
994
  BookReader.prototype.getPrevReadMode = function(mode) {
993
995
  if (mode === BookReader.constMode1up || mode === BookReader.constMode2up) {
@@ -996,7 +998,7 @@ BookReader.prototype.getPrevReadMode = function(mode) {
996
998
  // Initial thumb, return 1up
997
999
  return BookReader.constMode1up;
998
1000
  }
999
- }
1001
+ };
1000
1002
 
1001
1003
  /**
1002
1004
  * Switches the mode (eg 1up 2up thumb)
@@ -1024,10 +1026,13 @@ BookReader.prototype.switchMode = function(
1024
1026
  }
1025
1027
 
1026
1028
  this.trigger(BookReader.eventNames.stop);
1027
- if (this.enableSearch) this.removeSearchHilites();
1028
1029
 
1029
1030
  this.prevReadMode = this.getPrevReadMode(this.mode);
1030
1031
 
1032
+ if (this.mode != mode) {
1033
+ this.activeMode.unprepare?.();
1034
+ }
1035
+
1031
1036
  this.mode = mode;
1032
1037
 
1033
1038
  // reinstate scale if moving from thumbnail view
@@ -1040,42 +1045,31 @@ BookReader.prototype.switchMode = function(
1040
1045
 
1041
1046
  // XXX maybe better to preserve zoom in each mode
1042
1047
  if (this.constMode1up == mode) {
1043
- this.onePageCalculateReductionFactors();
1044
- this.reduce = this.quantizeReduce(this.reduce, this.onePage.reductionFactors);
1045
- this.prepareOnePageView();
1048
+ this._modes.mode1Up.prepare();
1046
1049
  } else if (this.constModeThumb == mode) {
1047
1050
  this.reduce = this.quantizeReduce(this.reduce, this.reductionFactors);
1048
- this.prepareThumbnailView();
1051
+ this._modes.modeThumb.prepare();
1049
1052
  } else {
1050
- // $$$ why don't we save autofit?
1051
- // this.twoPage.autofit = null; // Take zoom level from other mode
1052
- // spread indices not set, so let's set them
1053
- if (init || !pageFound) {
1054
- this.setSpreadIndices();
1055
- }
1056
-
1057
- this.twoPageCalculateReductionFactors(); // this sets this.twoPage && this.reduce
1058
- this.prepareTwoPageView();
1059
- this.twoPageCenterView(0.5, 0.5); // $$$ TODO preserve center
1053
+ this._modes.mode2Up.prepare();
1060
1054
  }
1061
1055
 
1062
1056
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1063
1057
  this.trigger(BookReader.eventNames.fragmentChange);
1064
1058
  }
1065
- var eventName = mode + 'PageViewSelected';
1059
+ const eventName = mode + 'PageViewSelected';
1066
1060
  this.trigger(BookReader.eventNames[eventName]);
1067
1061
 
1068
1062
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1069
1063
  };
1070
1064
 
1071
1065
  BookReader.prototype.updateBrClasses = function() {
1072
- var modeToClass = {};
1066
+ const modeToClass = {};
1073
1067
  modeToClass[this.constMode1up] = 'BRmode1up';
1074
- modeToClass[this.constMode2up] = 'BRmode2Up';
1068
+ modeToClass[this.constMode2up] = 'BRmode2up';
1075
1069
  modeToClass[this.constModeThumb] = 'BRmodeThumb';
1076
1070
 
1077
1071
  this.refs.$br
1078
- .removeClass('BRmode1up BRmode2Up BRmodeThumb')
1072
+ .removeClass('BRmode1up BRmode2up BRmodeThumb')
1079
1073
  .addClass(modeToClass[this.mode]);
1080
1074
 
1081
1075
  if (this.isFullscreen()) {
@@ -1095,31 +1089,30 @@ BookReader.prototype.isFullscreen = function() {
1095
1089
  * Toggles fullscreen
1096
1090
  * @param { boolean } bindKeyboardControls
1097
1091
  */
1098
- BookReader.prototype.toggleFullscreen = function(bindKeyboardControls = true) {
1092
+ BookReader.prototype.toggleFullscreen = async function(bindKeyboardControls = true) {
1099
1093
  if (this.isFullscreen()) {
1100
- this.exitFullScreen();
1094
+ await this.exitFullScreen();
1101
1095
  } else {
1102
- this.enterFullscreen(bindKeyboardControls);
1096
+ await this.enterFullscreen(bindKeyboardControls);
1103
1097
  }
1104
1098
  };
1105
1099
 
1106
1100
  /**
1107
1101
  * Enters fullscreen
1108
1102
  * including:
1109
- * - animation
1110
1103
  * - binds keyboard controls
1111
1104
  * - fires custom event
1112
1105
  * @param { boolean } bindKeyboardControls
1113
1106
  */
1114
- BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1107
+ BookReader.prototype.enterFullscreen = async function(bindKeyboardControls = true) {
1108
+ this.refs.$br.addClass('BRfullscreenAnimation');
1115
1109
  const currentIndex = this.currentIndex();
1116
- this.refs.$brContainer.css('opacity', 0);
1117
1110
 
1118
1111
  if (bindKeyboardControls) {
1119
1112
  this._fullscreenCloseHandler = (e) => {
1120
1113
  if (e.keyCode === 27) this.toggleFullscreen();
1121
1114
  };
1122
- $(document).keyup(this._fullscreenCloseHandler);
1115
+ $(document).on("keyup", this._fullscreenCloseHandler);
1123
1116
  }
1124
1117
 
1125
1118
  const windowWidth = $(window).width();
@@ -1128,15 +1121,28 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1128
1121
  }
1129
1122
 
1130
1123
  this.isFullscreenActive = true;
1131
- this.animating = true;
1132
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear',() => {
1133
- this.resize();
1134
- this.jumpToIndex(currentIndex);
1135
- this.animating = false;
1136
- });
1124
+ // prioritize class updates so CSS can propagate
1125
+ this.updateBrClasses();
1126
+ if (this.activeMode instanceof Mode1Up) {
1127
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(currentIndex));
1128
+ // Need the new scale to be applied before calling jumpToIndex
1129
+ this.activeMode.mode1UpLit.requestUpdate();
1130
+ await this.activeMode.mode1UpLit.updateComplete;
1131
+ }
1132
+ this.jumpToIndex(currentIndex);
1137
1133
 
1138
1134
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1135
+ // Add "?view=theater"
1136
+ this.trigger(BookReader.eventNames.fragmentChange);
1137
+ // trigger event here, so that animations,
1138
+ // class updates happen before book-nav relays to web components
1139
1139
  this.trigger(BookReader.eventNames.fullscreenToggled);
1140
+
1141
+ // resize book after all events & css updates
1142
+ await new Promise(resolve => setTimeout(resolve, 0));
1143
+
1144
+ this.resize();
1145
+ this.refs.$br.removeClass('BRfullscreenAnimation');
1140
1146
  };
1141
1147
 
1142
1148
  /**
@@ -1146,27 +1152,35 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1146
1152
  * - fires custom event
1147
1153
  * @param { boolean } bindKeyboardControls
1148
1154
  */
1149
- BookReader.prototype.exitFullScreen = function() {
1150
- this.refs.$brContainer.css('opacity', 0);
1151
-
1152
- $(document).unbind('keyup', this._fullscreenCloseHandler);
1153
-
1154
- var windowWidth = $(window).width();
1155
+ BookReader.prototype.exitFullScreen = async function () {
1156
+ this.refs.$br.addClass('BRfullscreenAnimation');
1157
+ $(document).off('keyup', this._fullscreenCloseHandler);
1155
1158
 
1159
+ const windowWidth = $(window).width();
1156
1160
  const canShow2up = this.options.controls.twoPage.visible;
1157
1161
  if (canShow2up && (windowWidth <= this.onePageMinBreakpoint)) {
1158
1162
  this.switchMode(this.constMode2up);
1159
1163
  }
1160
1164
 
1161
1165
  this.isFullscreenActive = false;
1166
+ // Trigger fullscreen event immediately
1167
+ // so that book-nav can relay to web components
1168
+ this.trigger(BookReader.eventNames.fullscreenToggled);
1169
+
1162
1170
  this.updateBrClasses();
1163
- this.animating = true;
1164
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', () => {
1165
- this.resize();
1166
- this.animating = false;
1167
- });
1171
+ await new Promise(resolve => setTimeout(resolve, 0));
1172
+ this.resize();
1173
+
1174
+ if (this.activeMode instanceof Mode1Up) {
1175
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(this.currentIndex()));
1176
+ this.activeMode.mode1UpLit.requestUpdate();
1177
+ await this.activeMode.mode1UpLit.updateComplete;
1178
+ }
1179
+
1168
1180
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1169
- this.trigger(BookReader.eventNames.fullscreenToggled);
1181
+ // Remove "?view=theater"
1182
+ this.trigger(BookReader.eventNames.fragmentChange);
1183
+ this.refs.$br.removeClass('BRfullscreenAnimation');
1170
1184
  };
1171
1185
 
1172
1186
  /**
@@ -1180,7 +1194,7 @@ BookReader.prototype.currentIndex = function() {
1180
1194
  return this.firstIndex; // $$$ TODO page in center of view would be better
1181
1195
  } else if (this.mode == this.constMode2up) {
1182
1196
  // Only allow indices that are actually present in book
1183
- return utils.clamp(this.firstIndex, 0, this._models.book.getNumLeafs() - 1);
1197
+ return utils.clamp(this.firstIndex, 0, this.book.getNumLeafs() - 1);
1184
1198
  } else {
1185
1199
  throw 'currentIndex called for unimplemented mode ' + this.mode;
1186
1200
  }
@@ -1197,11 +1211,9 @@ BookReader.prototype.updateFirstIndex = function(
1197
1211
  index,
1198
1212
  { suppressFragmentChange = false } = {}
1199
1213
  ) {
1200
- // Called multiple times when defaults contains "mode/1up",
1201
- // including after init(). Skip fragment change if no index change
1202
- if (this.firstIndex === index) {
1203
- suppressFragmentChange = true;
1204
- }
1214
+ // If there's no change, do nothing
1215
+ if (this.firstIndex === index) return;
1216
+
1205
1217
  this.firstIndex = index;
1206
1218
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1207
1219
  this.trigger(BookReader.eventNames.fragmentChange);
@@ -1212,8 +1224,12 @@ BookReader.prototype.updateFirstIndex = function(
1212
1224
  if (this.options.initialSearchTerm && !suppressFragmentChange) {
1213
1225
  this.suppressFragmentChange = false;
1214
1226
  }
1215
- this.trigger('pageChanged');
1216
- this.updateNavIndexThrottled(index);
1227
+
1228
+ this.trigger(BookReader.eventNames.pageChanged);
1229
+
1230
+ // event to know if user is actively reading
1231
+ this.trigger(BookReader.eventNames.userAction);
1232
+ this._components.navbar.updateNavIndexThrottled(index);
1217
1233
  };
1218
1234
 
1219
1235
  /**
@@ -1260,24 +1276,24 @@ BookReader.prototype.leftmost = function() {
1260
1276
  }
1261
1277
  };
1262
1278
 
1263
- BookReader.prototype.next = function() {
1279
+ BookReader.prototype.next = function({triggerStop = true} = {}) {
1264
1280
  if (this.constMode2up == this.mode) {
1265
- this.trigger(BookReader.eventNames.stop);
1266
- this.flipFwdToIndex(null);
1281
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1282
+ this._modes.mode2Up.mode2UpLit.flipAnimation('next');
1267
1283
  } else {
1268
- if (this.firstIndex < this.lastDisplayableIndex()) {
1284
+ if (this.firstIndex < this.book.getNumLeafs() - 1) {
1269
1285
  this.jumpToIndex(this.firstIndex + 1);
1270
1286
  }
1271
1287
  }
1272
1288
  };
1273
1289
 
1274
- BookReader.prototype.prev = function() {
1290
+ BookReader.prototype.prev = function({triggerStop = true} = {}) {
1275
1291
  const isOnFrontPage = this.firstIndex < 1;
1276
1292
  if (isOnFrontPage) return;
1277
1293
 
1278
1294
  if (this.constMode2up == this.mode) {
1279
- this.trigger(BookReader.eventNames.stop);
1280
- this.flipBackToIndex(null);
1295
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1296
+ this._modes.mode2Up.mode2UpLit.flipAnimation('prev');
1281
1297
  } else {
1282
1298
  if (this.firstIndex >= 1) {
1283
1299
  this.jumpToIndex(this.firstIndex - 1);
@@ -1286,257 +1302,13 @@ BookReader.prototype.prev = function() {
1286
1302
  };
1287
1303
 
1288
1304
  BookReader.prototype.first = function() {
1289
- this.jumpToIndex(this.firstDisplayableIndex());
1305
+ this.jumpToIndex(0);
1290
1306
  };
1291
1307
 
1292
1308
  BookReader.prototype.last = function() {
1293
- this.jumpToIndex(this.lastDisplayableIndex());
1294
- };
1295
-
1296
- /**
1297
- * Scrolls down one screen view
1298
- */
1299
- BookReader.prototype.scrollDown = function() {
1300
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1301
- if ( this.mode == this.constMode1up && (this.reduce >= this.onePageGetAutofitHeight()) ) {
1302
- // Whole pages are visible, scroll whole page only
1303
- return this.next();
1304
- }
1305
-
1306
- this.refs.$brContainer.stop(true).animate(
1307
- { scrollTop: '+=' + this._scrollAmount() + 'px'},
1308
- 400, 'easeInOutExpo'
1309
- );
1310
- return true;
1311
- } else {
1312
- return false;
1313
- }
1314
- };
1315
-
1316
- /**
1317
- * Scrolls up one screen view
1318
- */
1319
- BookReader.prototype.scrollUp = function() {
1320
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1321
- if ( this.mode == this.constMode1up && (this.reduce >= this.onePageGetAutofitHeight()) ) {
1322
- // Whole pages are visible, scroll whole page only
1323
- return this.prev();
1324
- }
1325
-
1326
- this.refs.$brContainer.stop(true).animate(
1327
- { scrollTop: '-=' + this._scrollAmount() + 'px'},
1328
- 400, 'easeInOutExpo'
1329
- );
1330
- return true;
1331
- } else {
1332
- return false;
1333
- }
1334
- };
1335
-
1336
- /**
1337
- * The amount to scroll vertically in integer pixels
1338
- */
1339
- BookReader.prototype._scrollAmount = function() {
1340
- if (this.constMode1up == this.mode) {
1341
- // Overlap by % of page size
1342
- return parseInt(this.refs.$brContainer.prop('clientHeight') - this._models.book.getPageHeight(this.currentIndex()) / this.reduce * 0.03);
1343
- }
1344
-
1345
- return parseInt(0.9 * this.refs.$brContainer.prop('clientHeight'));
1346
- };
1347
-
1348
- /**
1349
- * @deprecated No longer used; will be remove in v5
1350
- */
1351
- BookReader.prototype.prefetchImg = async function(index, fetchNow = false) {
1352
- console.warn('Call to deprecated function: BookReader.prefetchImg. No-op.');
1353
- };
1354
-
1355
- /**
1356
- * @deprecated No longer used; will be remove in v5
1357
- */
1358
- BookReader.prototype.pruneUnusedImgs = function() {
1359
- console.warn('Call to deprecated function: BookReader.pruneUnused. No-op.');
1309
+ this.jumpToIndex(this.book.getNumLeafs() - 1);
1360
1310
  };
1361
1311
 
1362
- /************************/
1363
- /** Mode1Up extensions **/
1364
- /************************/
1365
- /** @deprecated not used outside BookReader */
1366
- BookReader.prototype.prepareOnePageView = Mode1Up.prototype.prepare;
1367
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'prepare', 'prepareOnePageView');
1368
- /** @deprecated not used outside BookReader */
1369
- BookReader.prototype.drawLeafsOnePage = Mode1Up.prototype.drawLeafs;
1370
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'drawLeafs', 'drawLeafsOnePage');
1371
- /** @deprecated not used outside BookReader */
1372
- BookReader.prototype.zoom1up = Mode1Up.prototype.zoom;
1373
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'zoom', 'zoom1up');
1374
- /** @deprecated not used outside Mode1Up */
1375
- BookReader.prototype.onePageGetAutofitWidth = Mode1Up.prototype.getAutofitWidth;
1376
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitWidth', 'onePageGetAutofitWidth');
1377
- /** @deprecated not used outside Mode1Up, BookReader */
1378
- BookReader.prototype.onePageGetAutofitHeight = Mode1Up.prototype.getAutofitHeight;
1379
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitHeight', 'onePageGetAutofitHeight');
1380
- /** @deprecated not used outside Mode1Up, BookReader */
1381
- BookReader.prototype.onePageGetPageTop = Mode1Up.prototype.getPageTop;
1382
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getPageTop', 'onePageGetPageTop');
1383
- /** @deprecated not used outside Mode1Up, BookReader */
1384
- BookReader.prototype.onePageCalculateReductionFactors = Mode1Up.prototype.calculateReductionFactors;
1385
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateReductionFactors', 'onePageCalculateReductionFactors');
1386
- /** @deprecated not used outside Mode1Up, BookReader */
1387
- BookReader.prototype.resizePageView1up = Mode1Up.prototype.resizePageView;
1388
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'resizePageView', 'resizePageView1up');
1389
- /** @deprecated not used outside Mode1Up */
1390
- BookReader.prototype.onePageCalculateViewDimensions = Mode1Up.prototype.calculateViewDimensions;
1391
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateViewDimensions', 'onePageCalculateViewDimensions');
1392
- /** @deprecated not used outside Mode1Up */
1393
- BookReader.prototype.centerX1up = Mode1Up.prototype.centerX;
1394
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerX', 'centerX1up');
1395
- /** @deprecated not used outside Mode1Up */
1396
- BookReader.prototype.centerY1up = Mode1Up.prototype.centerY;
1397
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerY', 'centerY1up');
1398
-
1399
- /************************/
1400
- /** Mode2Up extensions **/
1401
- /************************/
1402
- /** @deprecated not used outside Mode2Up */
1403
- BookReader.prototype.zoom2up = Mode2Up.prototype.zoom;
1404
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'zoom', 'zoom2up');
1405
- BookReader.prototype.twoPageGetAutofitReduce = Mode2Up.prototype.getAutofitReduce;
1406
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getAutofitReduce', 'twoPageGetAutofitReduce');
1407
- BookReader.prototype.flipBackToIndex = Mode2Up.prototype.flipBackToIndex;
1408
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipBackToIndex', 'flipBackToIndex');
1409
- BookReader.prototype.flipFwdToIndex = Mode2Up.prototype.flipFwdToIndex;
1410
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipFwdToIndex', 'flipFwdToIndex');
1411
- BookReader.prototype.setHilightCss2UP = Mode2Up.prototype.setHilightCss;
1412
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setHilightCss', 'setHilightCss2UP');
1413
- /** @deprecated not used outside Mode2Up */
1414
- BookReader.prototype.setClickHandler2UP = Mode2Up.prototype.setClickHandler;
1415
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setClickHandler', 'setClickHandler2UP');
1416
- /** @deprecated not used outside Mode2Up */
1417
- BookReader.prototype.drawLeafsTwoPage = Mode2Up.prototype.drawLeafs;
1418
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'drawLeafs', 'drawLeafsTwoPage');
1419
- /** @deprecated not used outside BookReader */
1420
- BookReader.prototype.prepareTwoPageView = Mode2Up.prototype.prepareTwoPageView;
1421
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareTwoPageView', 'prepareTwoPageView');
1422
- /** @deprecated not used outside Mode2Up */
1423
- BookReader.prototype.prepareTwoPagePopUp = Mode2Up.prototype.preparePopUp;
1424
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'preparePopUp', 'prepareTwoPagePopUp');
1425
- /** @deprecated not used outside BookReader, Mode2Up */
1426
- BookReader.prototype.calculateSpreadSize = Mode2Up.prototype.calculateSpreadSize;
1427
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateSpreadSize', 'calculateSpreadSize');
1428
- /** @deprecated not used outside BookReader, Mode2Up */
1429
- BookReader.prototype.getIdealSpreadSize = Mode2Up.prototype.getIdealSpreadSize;
1430
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getIdealSpreadSize', 'getIdealSpreadSize');
1431
- /** @deprecated not used outside BookReader, Mode2Up */
1432
- BookReader.prototype.getSpreadSizeFromReduce = Mode2Up.prototype.getSpreadSizeFromReduce;
1433
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getSpreadSizeFromReduce', 'getSpreadSizeFromReduce');
1434
- /** @deprecated unused */
1435
- BookReader.prototype.twoPageIsZoomedIn = Mode2Up.prototype.isZoomedIn;
1436
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'isZoomedIn', 'twoPageIsZoomedIn');
1437
- /** @deprecated not used outside BookReader */
1438
- BookReader.prototype.twoPageCalculateReductionFactors = Mode2Up.prototype.calculateReductionFactors;
1439
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateReductionFactors', 'twoPageCalculateReductionFactors');
1440
- /** @deprecated unused */
1441
- BookReader.prototype.twoPageSetCursor = Mode2Up.prototype.setCursor;
1442
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setCursor', 'twoPageSetCursor');
1443
- /** @deprecated unused outside BookReader, Mode2Up */
1444
- BookReader.prototype.flipLeftToRight = Mode2Up.prototype.flipLeftToRight;
1445
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipLeftToRight', 'flipLeftToRight');
1446
- /** @deprecated unused outside BookReader, Mode2Up */
1447
- BookReader.prototype.flipRightToLeft = Mode2Up.prototype.flipRightToLeft;
1448
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipRightToLeft', 'flipRightToLeft');
1449
- /** @deprecated unused outside Mode2Up */
1450
- BookReader.prototype.setMouseHandlers2UP = Mode2Up.prototype.setMouseHandlers;
1451
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setMouseHandlers', 'setMouseHandlers2UP');
1452
- /** @deprecated unused outside BookReader, Mode2Up */
1453
- BookReader.prototype.prepareFlipLeftToRight = Mode2Up.prototype.prepareFlipLeftToRight;
1454
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipLeftToRight', 'prepareFlipLeftToRight');
1455
- /** @deprecated unused outside BookReader, Mode2Up */
1456
- BookReader.prototype.prepareFlipRightToLeft = Mode2Up.prototype.prepareFlipRightToLeft;
1457
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipRightToLeft', 'prepareFlipRightToLeft');
1458
- /** @deprecated unused outside Mode2Up */
1459
- BookReader.prototype.getPageWidth2UP = Mode2Up.prototype.getPageWidth;
1460
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getPageWidth', 'getPageWidth2UP');
1461
- /** @deprecated unused outside Mode2Up */
1462
- BookReader.prototype.twoPageGutter = Mode2Up.prototype.gutter;
1463
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutter', 'twoPageGutter');
1464
- /** @deprecated unused outside Mode2Up */
1465
- BookReader.prototype.twoPageTop = Mode2Up.prototype.top;
1466
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'top', 'twoPageTop');
1467
- /** @deprecated unused outside Mode2Up */
1468
- BookReader.prototype.twoPageCoverWidth = Mode2Up.prototype.coverWidth;
1469
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'coverWidth', 'twoPageCoverWidth');
1470
- /** @deprecated unused outside Mode2Up */
1471
- BookReader.prototype.twoPageGetViewCenter = Mode2Up.prototype.getViewCenter;
1472
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getViewCenter', 'twoPageGetViewCenter');
1473
- /** @deprecated unused outside BookReader, Mode2Up */
1474
- BookReader.prototype.twoPageCenterView = Mode2Up.prototype.centerView;
1475
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'centerView', 'twoPageCenterView');
1476
- /** @deprecated unused outside Mode2Up */
1477
- BookReader.prototype.twoPageFlipAreaHeight = Mode2Up.prototype.flipAreaHeight;
1478
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaHeight', 'twoPageFlipAreaHeight');
1479
- /** @deprecated unused outside Mode2Up */
1480
- BookReader.prototype.twoPageFlipAreaWidth = Mode2Up.prototype.flipAreaWidth;
1481
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaWidth', 'twoPageFlipAreaWidth');
1482
- /** @deprecated unused outside BookReader, Mode2Up */
1483
- BookReader.prototype.twoPageFlipAreaTop = Mode2Up.prototype.flipAreaTop;
1484
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaTop', 'twoPageFlipAreaTop');
1485
- /** @deprecated unused outside Mode2Up */
1486
- BookReader.prototype.twoPageLeftFlipAreaLeft = Mode2Up.prototype.leftFlipAreaLeft;
1487
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leftFlipAreaLeft', 'twoPageLeftFlipAreaLeft');
1488
- /** @deprecated unused outside Mode2Up */
1489
- BookReader.prototype.twoPageRightFlipAreaLeft = Mode2Up.prototype.rightFlipAreaLeft;
1490
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'rightFlipAreaLeft', 'twoPageRightFlipAreaLeft');
1491
- /** @deprecated unused outside BookReader, Mode2Up */
1492
- BookReader.prototype.gutterOffsetForIndex = Mode2Up.prototype.gutterOffsetForIndex;
1493
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutterOffsetForIndex', 'gutterOffsetForIndex');
1494
- /** @deprecated unused outside BookReader, Mode2Up */
1495
- BookReader.prototype.leafEdgeWidth = Mode2Up.prototype.leafEdgeWidth;
1496
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leafEdgeWidth', 'leafEdgeWidth');
1497
- /** @deprecated unused outside BookReader, Mode2Up */
1498
- BookReader.prototype.jumpIndexForLeftEdgePageX = Mode2Up.prototype.jumpIndexForLeftEdgePageX;
1499
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForLeftEdgePageX', 'jumpIndexForLeftEdgePageX');
1500
- /** @deprecated unused outside BookReader, Mode2Up */
1501
- BookReader.prototype.jumpIndexForRightEdgePageX = Mode2Up.prototype.jumpIndexForRightEdgePageX;
1502
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForRightEdgePageX', 'jumpIndexForRightEdgePageX');
1503
- /** @deprecated unused outside Mode2Up */
1504
- BookReader.prototype.prefetch = Mode2Up.prototype.prefetch;
1505
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prefetch', 'prefetch');
1506
- /** @deprecated unused outside Mode2Up */
1507
- BookReader.prototype.setSpreadIndices = Mode2Up.prototype.setSpreadIndices;
1508
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setSpreadIndices', 'setSpreadIndices');
1509
- /**
1510
- * Immediately stop flip animations. Callbacks are triggered.
1511
- */
1512
- BookReader.prototype.stopFlipAnimations = function() {
1513
- this.trigger(BookReader.eventNames.stop);
1514
-
1515
- // Stop animation, clear queue, trigger callbacks
1516
- if (this.leafEdgeTmp) {
1517
- $(this.leafEdgeTmp).stop(false, true);
1518
- }
1519
- jQuery.each(this._modes.mode2Up.pageContainers, function() {
1520
- $(this.$container).stop(false, true);
1521
- });
1522
-
1523
- // And again since animations also queued in callbacks
1524
- if (this.leafEdgeTmp) {
1525
- $(this.leafEdgeTmp).stop(false, true);
1526
- }
1527
- jQuery.each(this._modes.mode2Up.pageContainers, function() {
1528
- $(this.$container).stop(false, true);
1529
- });
1530
- };
1531
-
1532
- /**
1533
- * Returns true if keyboard navigation should be disabled for the event
1534
- * @param {Event}
1535
- * @return {boolean}
1536
- */
1537
- BookReader.prototype.keyboardNavigationIsDisabled = function(event) {
1538
- return event.target.tagName == "INPUT";
1539
- };
1540
1312
 
1541
1313
  /**
1542
1314
  * @template TClass extends { br: BookReader }
@@ -1560,30 +1332,9 @@ function exposeOverrideableMethod(Class, classKey, method, brMethod = method) {
1560
1332
  /***********************/
1561
1333
  /** Navbar extensions **/
1562
1334
  /***********************/
1335
+ /** This cannot be removed yet because plugin.tts.js overrides it */
1563
1336
  BookReader.prototype.initNavbar = Navbar.prototype.init;
1564
1337
  exposeOverrideableMethod(Navbar, '_components.navbar', 'init', 'initNavbar');
1565
- BookReader.prototype.switchNavbarControls = Navbar.prototype.switchNavbarControls;
1566
- exposeOverrideableMethod(Navbar, '_components.navbar', 'switchNavbarControls');
1567
- BookReader.prototype.updateViewModeButton = Navbar.prototype.updateViewModeButton;
1568
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateViewModeButton');
1569
- BookReader.prototype.getNavPageNumString = Navbar.prototype.getNavPageNumString;
1570
- exposeOverrideableMethod(Navbar, '_components.navbar', 'getNavPageNumString');
1571
- /** @deprecated */
1572
- BookReader.prototype.initEmbedNavbar = Navbar.prototype.initEmbed;
1573
- exposeOverrideableMethod(Navbar, '_components.navbar', 'initEmbed', 'initEmbedNavbar');
1574
- /** @deprecated unused */
1575
- BookReader.prototype.getNavPageNumHtml = getNavPageNumHtml;
1576
- /** @deprecated unused outside this file */
1577
- BookReader.prototype.updateNavPageNum = Navbar.prototype.updateNavPageNum;
1578
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavPageNum');
1579
- /** @deprecated unused outside this file */
1580
- BookReader.prototype.updateNavIndex = Navbar.prototype.updateNavIndex;
1581
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavIndex');
1582
- /** @deprecated unused outside this file */
1583
- BookReader.prototype.updateNavIndexThrottled = utils.throttle(BookReader.prototype.updateNavIndex, 250, false);
1584
- /** @deprecated unused */
1585
- BookReader.prototype.updateNavIndexDebounced = utils.debounce(BookReader.prototype.updateNavIndex, 500, false);
1586
-
1587
1338
 
1588
1339
  /************************/
1589
1340
  /** Toolbar extensions **/
@@ -1598,24 +1349,14 @@ BookReader.prototype.buildInfoDiv = Toolbar.prototype.buildInfoDiv;
1598
1349
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildInfoDiv');
1599
1350
  BookReader.prototype.getToolBarHeight = Toolbar.prototype.getToolBarHeight;
1600
1351
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'getToolBarHeight');
1601
- /** @deprecated zoom no longer in toolbar */
1602
- BookReader.prototype.updateToolbarZoom = Toolbar.prototype.updateToolbarZoom;
1603
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'updateToolbarZoom');
1604
- /** @deprecated unused */
1605
- BookReader.prototype.blankInfoDiv = blankInfoDiv;
1606
- /** @deprecated unused */
1607
- BookReader.prototype.blankShareDiv = blankShareDiv;
1608
- /** @deprecated unused */
1609
- BookReader.prototype.createPopup = createPopup;
1610
1352
 
1611
1353
  /**
1612
1354
  * Bind navigation handlers
1613
1355
  */
1614
1356
  BookReader.prototype.bindNavigationHandlers = function() {
1615
1357
  const self = this;
1358
+ const jIcons = this.$('.BRicon');
1616
1359
 
1617
- // Note the mobile plugin attaches itself to body, so we need to select outside
1618
- const jIcons = this.$('.BRicon').add('.BRmobileMenu .BRicon');
1619
1360
  // Map of jIcon class -> click handler
1620
1361
  const navigationControls = {
1621
1362
  book_left: () => {
@@ -1626,20 +1367,6 @@ BookReader.prototype.bindNavigationHandlers = function() {
1626
1367
  this.trigger(BookReader.eventNames.stop);
1627
1368
  this.right();
1628
1369
  },
1629
- book_up: () => {
1630
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1631
- this.scrollUp();
1632
- } else {
1633
- this.prev();
1634
- }
1635
- },
1636
- book_down: () => {
1637
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1638
- this.scrollDown();
1639
- } else {
1640
- this.next();
1641
- }
1642
- },
1643
1370
  book_top: this.first.bind(this),
1644
1371
  book_bottom: this.last.bind(this),
1645
1372
  book_leftmost: this.leftmost.bind(this),
@@ -1665,7 +1392,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1665
1392
  },
1666
1393
  full: () => {
1667
1394
  if (this.ui == 'embed') {
1668
- var url = this.$('.BRembedreturn a').attr('href');
1395
+ const url = this.$('.BRembedreturn a').attr('href');
1669
1396
  window.open(url);
1670
1397
  } else {
1671
1398
  this.toggleFullscreen();
@@ -1673,23 +1400,25 @@ BookReader.prototype.bindNavigationHandlers = function() {
1673
1400
  },
1674
1401
  };
1675
1402
 
1676
- jIcons.filter('.fit').bind('fit', function() {
1677
- // XXXmang implement autofit zoom
1403
+ // custom event for auto-loan-renew in ia-book-actions
1404
+ // - to know if user is actively reading
1405
+ this.$('nav.BRcontrols li button').on('click', () => {
1406
+ this.trigger(BookReader.eventNames.userAction);
1678
1407
  });
1679
1408
 
1680
1409
  for (const control in navigationControls) {
1681
1410
  jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
1682
- navigationControls[control]()
1411
+ navigationControls[control]();
1683
1412
  return false;
1684
1413
  });
1685
1414
  }
1686
1415
 
1687
- var $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1688
- var $brNavCntlTopEl = this.$('.BRnavCntlTop');
1416
+ const $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1417
+ const $brNavCntlTopEl = this.$('.BRnavCntlTop');
1689
1418
 
1690
1419
  this.$('.BRnavCntl').click(
1691
1420
  function() {
1692
- var promises = [];
1421
+ const promises = [];
1693
1422
  // TODO don't use magic constants
1694
1423
  // TODO move this to a function
1695
1424
  if ($brNavCntlBtmEl.hasClass('BRdn')) {
@@ -1709,7 +1438,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1709
1438
  $brNavCntlBtmEl.addClass('BRdn').removeClass('BRup');
1710
1439
  $brNavCntlTopEl.addClass('BRup').removeClass('BRdn');
1711
1440
  self.$('.BRnavCntlBtm.BRnavCntl').animate({height:'30px'});
1712
- self.$('.BRvavCntl').animate({opacity:1})
1441
+ self.$('.BRvavCntl').animate({opacity:1});
1713
1442
  }
1714
1443
  $.when.apply($, promises).done(function() {
1715
1444
  // Only do full resize in auto mode and need to recalc. size
@@ -1727,386 +1456,38 @@ BookReader.prototype.bindNavigationHandlers = function() {
1727
1456
  });
1728
1457
  }
1729
1458
  );
1730
- $brNavCntlBtmEl.mouseover(function() {
1731
- if ($(this).hasClass('BRup')) {
1732
- self.$('.BRnavCntl').animate({opacity:1},250);
1733
- }
1734
- }).mouseleave(function() {
1735
- if ($(this).hasClass('BRup')) {
1736
- self.$('.BRnavCntl').animate({opacity:.75},250);
1737
- }
1738
- });
1739
- $brNavCntlTopEl.mouseover(function() {
1740
- if ($(this).hasClass('BRdn')) {
1741
- self.$('.BRnavCntl').animate({opacity:1},250);
1742
- }
1743
- }).mouseleave(function() {
1744
- if ($(this).hasClass('BRdn')) {
1745
- self.$('.BRnavCntl').animate({opacity:.75},250);
1746
- }
1747
- });
1748
-
1749
- this.initSwipeData();
1750
-
1751
- $(document).off('mousemove.navigation', this.el);
1752
- $(document).on(
1753
- 'mousemove.navigation',
1754
- this.el,
1755
- { 'br': this },
1756
- this.navigationMousemoveHandler
1757
- );
1758
-
1759
- $(document).off('mousedown.swipe', '.BRpageimage');
1760
- $(document).on(
1761
- 'mousedown.swipe',
1762
- '.BRpageimage',
1763
- { 'br': this },
1764
- this.swipeMousedownHandler
1765
- );
1766
-
1767
- this.bindMozTouchHandlers();
1768
- };
1769
-
1770
- /**
1771
- * Unbind navigation handlers
1772
- */
1773
- BookReader.prototype.unbindNavigationHandlers = function() {
1774
- $(document).off('mousemove.navigation', this.el);
1775
- };
1776
-
1777
- /**
1778
- * Handle mousemove related to navigation. Bind at #BookReader level to allow autohide.
1779
- */
1780
- BookReader.prototype.navigationMousemoveHandler = function(event) {
1781
- // $$$ possibly not great to be calling this for every mousemove
1782
- if (event.data['br'].uiAutoHide) {
1783
- // 77px is an approximate height of the Internet Archive Top Nav
1784
- // 75 & 76 (pixels) provide used in this context is checked against the IA top nav height
1785
- var navkey = $(document).height() - 75;
1786
- if ((event.pageY < 76) || (event.pageY > navkey)) {
1787
- // inside or near navigation elements
1788
- event.data['br'].hideNavigation();
1789
- } else {
1790
- event.data['br'].showNavigation();
1791
- }
1792
- }
1793
- };
1794
-
1795
- BookReader.prototype.initSwipeData = function(clientX, clientY) {
1796
- /*
1797
- * Based on the really quite awesome "Today's Guardian" at http://guardian.gyford.com/
1798
- */
1799
- this._swipe = {
1800
- mightBeSwiping: false,
1801
- didSwipe: false,
1802
- mightBeDraggin: false,
1803
- didDrag: false,
1804
- startTime: (new Date).getTime(),
1805
- startX: clientX,
1806
- startY: clientY,
1807
- lastX: clientX,
1808
- lastY: clientY,
1809
- deltaX: 0,
1810
- deltaY: 0,
1811
- deltaT: 0
1812
- }
1813
- };
1814
-
1815
- BookReader.prototype.swipeMousedownHandler = function(event) {
1816
- var self = event.data['br'];
1817
-
1818
- // We should be the last bubble point for the page images
1819
- // Disable image drag and select, but keep right-click
1820
- if (event.which == 3) {
1821
- return !self.protected;
1822
- }
1823
-
1824
- $(event.target).bind('mouseout.swipe',
1825
- { 'br': self},
1826
- self.swipeMouseupHandler
1827
- ).bind('mouseup.swipe',
1828
- { 'br': self},
1829
- self.swipeMouseupHandler
1830
- ).bind('mousemove.swipe',
1831
- { 'br': self },
1832
- self.swipeMousemoveHandler
1833
- );
1834
-
1835
- self.initSwipeData(event.clientX, event.clientY);
1836
- self._swipe.mightBeSwiping = true;
1837
- self._swipe.mightBeDragging = true;
1838
-
1839
- event.preventDefault();
1840
- event.returnValue = false;
1841
- event.cancelBubble = true;
1842
- return false;
1843
- };
1844
-
1845
- BookReader.prototype.swipeMousemoveHandler = function(event) {
1846
- var self = event.data['br'];
1847
- var _swipe = self._swipe;
1848
- if (! _swipe.mightBeSwiping) {
1849
- return;
1850
- }
1851
-
1852
- // Update swipe data
1853
- _swipe.deltaX = event.clientX - _swipe.startX;
1854
- _swipe.deltaY = event.clientY - _swipe.startY;
1855
- _swipe.deltaT = (new Date).getTime() - _swipe.startTime;
1856
-
1857
- var absX = Math.abs(_swipe.deltaX);
1858
- var absY = Math.abs(_swipe.deltaY);
1859
-
1860
- // Minimum distance in the amount of tim to trigger the swipe
1861
- var minSwipeLength = Math.min(self.refs.$br.width() / 5, 80);
1862
- var maxSwipeTime = 400;
1863
-
1864
- // Check for horizontal swipe
1865
- if (absX > absY && (absX > minSwipeLength) && _swipe.deltaT < maxSwipeTime) {
1866
- _swipe.mightBeSwiping = false; // only trigger once
1867
- _swipe.didSwipe = true;
1868
- if (self.mode == self.constMode2up) {
1869
- if (_swipe.deltaX < 0) {
1870
- self.right();
1871
- } else {
1872
- self.left();
1459
+ $brNavCntlBtmEl
1460
+ .on("mouseover", function() {
1461
+ if ($(this).hasClass('BRup')) {
1462
+ self.$('.BRnavCntl').animate({opacity:1},250);
1873
1463
  }
1874
- }
1875
- }
1876
-
1877
- if ( _swipe.deltaT > maxSwipeTime && !_swipe.didSwipe) {
1878
- if (_swipe.mightBeDragging) {
1879
- // Dragging
1880
- _swipe.didDrag = true;
1881
- self.refs.$brContainer
1882
- .scrollTop(self.refs.$brContainer.scrollTop() - event.clientY + _swipe.lastY)
1883
- .scrollLeft(self.refs.$brContainer.scrollLeft() - event.clientX + _swipe.lastX);
1884
- }
1885
- }
1886
- _swipe.lastX = event.clientX;
1887
- _swipe.lastY = event.clientY;
1888
-
1889
- event.preventDefault();
1890
- event.returnValue = false;
1891
- event.cancelBubble = true;
1892
- return false;
1893
- };
1894
-
1895
- BookReader.prototype.swipeMouseupHandler = function(event) {
1896
- var _swipe = event.data['br']._swipe;
1897
- _swipe.mightBeSwiping = false;
1898
- _swipe.mightBeDragging = false;
1899
-
1900
- $(event.target).unbind('mouseout.swipe').unbind('mouseup.swipe').unbind('mousemove.swipe');
1901
-
1902
- if (_swipe.didSwipe || _swipe.didDrag) {
1903
- // Swallow event if completed swipe gesture
1904
- event.preventDefault();
1905
- event.returnValue = false;
1906
- event.cancelBubble = true;
1907
- return false;
1908
- }
1909
- return true;
1910
- };
1911
-
1912
- BookReader.prototype.bindMozTouchHandlers = function() {
1913
- var self = this;
1914
-
1915
- // Currently only want touch handlers in 2up
1916
- this.refs.$br.bind('MozTouchDown', function(event) {
1917
- if (this.mode == self.constMode2up) {
1918
- event.preventDefault();
1919
- }
1920
- })
1921
- .bind('MozTouchMove', function(event) {
1922
- if (this.mode == self.constMode2up) {
1923
- event.preventDefault();
1464
+ })
1465
+ .on("mouseleave", function() {
1466
+ if ($(this).hasClass('BRup')) {
1467
+ self.$('.BRnavCntl').animate({opacity:.75},250);
1468
+ }
1469
+ });
1470
+ $brNavCntlTopEl
1471
+ .on("mouseover", function() {
1472
+ if ($(this).hasClass('BRdn')) {
1473
+ self.$('.BRnavCntl').animate({opacity:1},250);
1924
1474
  }
1925
1475
  })
1926
- .bind('MozTouchUp', function(event) {
1927
- if (this.mode == self.constMode2up) {
1928
- event.preventDefault();
1476
+ .on("mouseleave", function() {
1477
+ if ($(this).hasClass('BRdn')) {
1478
+ self.$('.BRnavCntl').animate({opacity:.75},250);
1929
1479
  }
1930
1480
  });
1931
1481
  };
1932
1482
 
1933
- /**
1934
- * Returns true if the navigation elements are currently visible
1935
- * @return {boolean}
1936
- */
1937
- BookReader.prototype.navigationIsVisible = function() {
1938
- // $$$ doesn't account for transitioning states, nav must be fully visible to return true
1939
- var toolpos = this.refs.$BRtoolbar.position();
1940
- var tooltop = toolpos.top;
1941
- return tooltop == 0;
1942
- };
1943
-
1944
- /**
1945
- * Main controller that sets navigation into view.
1946
- * Defaults to SHOW the navigation chrome
1947
- */
1948
- BookReader.prototype.setNavigationView = function brSetNavigationView(hide) {
1949
- var animationLength = this.constNavAnimationDuration;
1950
- var animationType = 'linear';
1951
- var resizePageContainer = function resizePageContainer () {
1952
- /* main page container fills whole container */
1953
- if (this.constMode2up !== this.mode) {
1954
- var animate = true;
1955
- this.resizeBRcontainer(animate);
1956
- }
1957
- this.trigger(BookReader.eventNames.navToggled);
1958
- }.bind(this);
1959
-
1960
- var toolbarHeight = 0;
1961
- var navbarHeight = 0;
1962
- if (hide) {
1963
- toolbarHeight = this.getToolBarHeight() * -1;
1964
- navbarHeight = this.getFooterHeight() * -1;
1965
-
1966
- this.refs.$BRtoolbar.addClass('js-menu-hide');
1967
- this.refs.$BRfooter.addClass('js-menu-hide');
1968
- } else {
1969
- this.refs.$BRtoolbar.removeClass('js-menu-hide');
1970
- this.refs.$BRfooter.removeClass('js-menu-hide');
1971
- }
1972
-
1973
- this.refs.$BRtoolbar.animate(
1974
- { top: toolbarHeight },
1975
- animationLength,
1976
- animationType,
1977
- resizePageContainer
1978
- );
1979
- this.refs.$BRfooter.animate(
1980
- { bottom: navbarHeight },
1981
- animationLength,
1982
- animationType,
1983
- resizePageContainer
1984
- );
1985
- };
1986
- /**
1987
- * Hide navigation elements, if visible
1988
- */
1989
- BookReader.prototype.hideNavigation = function() {
1990
- // Check if navigation is showing
1991
- if (this.navigationIsVisible()) {
1992
- var hide = true;
1993
- this.setNavigationView(hide);
1994
- }
1995
- };
1996
-
1997
- /**
1998
- * Show navigation elements
1999
- */
2000
- BookReader.prototype.showNavigation = function() {
2001
- // Check if navigation is hidden
2002
- if (!this.navigationIsVisible()) {
2003
- this.setNavigationView();
2004
- }
2005
- };
2006
-
2007
- /**
2008
- * Returns the index of the first visible page, dependent on the mode.
2009
- * $$$ Currently we cannot display the front/back cover in 2-up and will need to update
2010
- * this function when we can as part of https://bugs.launchpad.net/gnubook/+bug/296788
2011
- * @return {number}
2012
- */
2013
- BookReader.prototype.firstDisplayableIndex = function() {
2014
- if (this.mode != this.constMode2up) {
2015
- return 0;
2016
- }
2017
-
2018
- if ('rl' != this.pageProgression) {
2019
- // LTR
2020
- if (this._models.book.getPageSide(0) == 'L') {
2021
- return 0;
2022
- } else {
2023
- return -1;
2024
- }
2025
- } else {
2026
- // RTL
2027
- if (this._models.book.getPageSide(0) == 'R') {
2028
- return 0;
2029
- } else {
2030
- return -1;
2031
- }
2032
- }
2033
- };
2034
-
2035
- /**
2036
- * Returns the index of the last visible page, dependent on the mode.
2037
- * $$$ Currently we cannot display the front/back cover in 2-up and will need to update
2038
- * this function when we can as part of https://bugs.launchpad.net/gnubook/+bug/296788
2039
- * @return {number}
2040
- */
2041
- BookReader.prototype.lastDisplayableIndex = function() {
2042
-
2043
- var lastIndex = this._models.book.getNumLeafs() - 1;
2044
-
2045
- if (this.mode != this.constMode2up) {
2046
- return lastIndex;
2047
- }
2048
-
2049
- if ('rl' != this.pageProgression) {
2050
- // LTR
2051
- if (this._models.book.getPageSide(lastIndex) == 'R') {
2052
- return lastIndex;
2053
- } else {
2054
- return lastIndex + 1;
2055
- }
2056
- } else {
2057
- // RTL
2058
- if (this._models.book.getPageSide(lastIndex) == 'L') {
2059
- return lastIndex;
2060
- } else {
2061
- return lastIndex + 1;
2062
- }
2063
- }
2064
- };
2065
-
2066
-
2067
1483
  /**************************/
2068
1484
  /** BookModel extensions **/
2069
1485
  /**************************/
2070
- /** @deprecated not used outside */
2071
- BookReader.prototype.getMedianPageSize = BookModel.prototype.getMedianPageSize;
2072
- exposeOverrideableMethod(BookModel, '_models.book', 'getMedianPageSize');
2073
- BookReader.prototype._getPageWidth = BookModel.prototype._getPageWidth;
2074
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageWidth');
2075
- BookReader.prototype._getPageHeight = BookModel.prototype._getPageHeight;
2076
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageHeight');
2077
- BookReader.prototype.getPageIndex = BookModel.prototype.getPageIndex;
2078
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndex');
2079
- /** @deprecated not used outside */
2080
- BookReader.prototype.getPageIndices = BookModel.prototype.getPageIndices;
2081
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndices');
2082
- BookReader.prototype.getPageName = BookModel.prototype.getPageName;
2083
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageName');
2084
- BookReader.prototype.getNumLeafs = BookModel.prototype.getNumLeafs;
2085
- exposeOverrideableMethod(BookModel, '_models.book', 'getNumLeafs');
2086
- BookReader.prototype.getPageWidth = BookModel.prototype.getPageWidth;
2087
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageWidth');
2088
- BookReader.prototype.getPageHeight = BookModel.prototype.getPageHeight;
2089
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageHeight');
1486
+ // Must modify petabox extension, which expects this on the prototype
1487
+ // before removing.
2090
1488
  BookReader.prototype.getPageURI = BookModel.prototype.getPageURI;
2091
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageURI');
2092
- BookReader.prototype.getPageSide = BookModel.prototype.getPageSide;
2093
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageSide');
2094
- BookReader.prototype.getPageNum = BookModel.prototype.getPageNum;
2095
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageNum');
2096
- BookReader.prototype.getPageProp = BookModel.prototype.getPageProp;
2097
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageProp');
2098
- BookReader.prototype.getSpreadIndices = BookModel.prototype.getSpreadIndices;
2099
- exposeOverrideableMethod(BookModel, '_models.book', 'getSpreadIndices');
2100
- BookReader.prototype.leafNumToIndex = BookModel.prototype.leafNumToIndex;
2101
- exposeOverrideableMethod(BookModel, '_models.book', 'leafNumToIndex');
2102
- BookReader.prototype.parsePageString = BookModel.prototype.parsePageString;
2103
- exposeOverrideableMethod(BookModel, '_models.book', 'parsePageString');
2104
- /** @deprecated unused */
2105
- BookReader.prototype._getDataFlattened = BookModel.prototype._getDataFlattened;
2106
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataFlattened');
2107
- /** @deprecated unused */
2108
- BookReader.prototype._getDataProp = BookModel.prototype._getDataProp;
2109
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataProp');
1489
+ exposeOverrideableMethod(BookModel, 'book', 'getPageURI');
1490
+
2110
1491
 
2111
1492
  // Parameter related functions
2112
1493
 
@@ -2137,7 +1518,7 @@ BookReader.prototype.updateFromParams = function(params) {
2137
1518
  }
2138
1519
  } else if ('undefined' != typeof(params.page)) {
2139
1520
  // $$$ this assumes page numbers are unique
2140
- if (params.page != this._models.book.getPageNum(this.currentIndex())) {
1521
+ if (params.page != this.book.getPageNum(this.currentIndex())) {
2141
1522
  this.jumpToPage(params.page);
2142
1523
  }
2143
1524
  }
@@ -2171,7 +1552,7 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2171
1552
  // check there are enough pages to display
2172
1553
  // $$$ this is a workaround for the mis-feature that we can't display
2173
1554
  // short books in 2up mode
2174
- if (this._models.book.getNumLeafs() < 2) {
1555
+ if (this.book.getNumLeafs() < 2) {
2175
1556
  return false;
2176
1557
  }
2177
1558
  }
@@ -2179,31 +1560,6 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2179
1560
  return true;
2180
1561
  };
2181
1562
 
2182
-
2183
- /**
2184
- * @deprecated. Use PageModel.getURISrcSet. Slated for removal in v5.
2185
- * Returns the srcset with correct URIs or void string if out of range
2186
- * Also makes the reduce argument optional
2187
- * @param {number} index
2188
- * @param {number} [reduce]
2189
- * @param {number} [rotate]
2190
- * @return {string}
2191
- */
2192
- BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2193
- const page = this._models.book.getPage(index, false);
2194
- // Synthesize page
2195
- if (!page) return "";
2196
-
2197
- // reduce not passed in
2198
- // $$$ this probably won't work for thumbnail mode
2199
- if ('undefined' == typeof(reduce)) {
2200
- reduce = page.height / this.twoPage.height;
2201
- }
2202
-
2203
- return page.getURISrcSet(reduce, rotate);
2204
- }
2205
-
2206
-
2207
1563
  /**
2208
1564
  * Returns the page URI or transparent image if out of range
2209
1565
  * Also makes the reduce argument optional
@@ -2213,7 +1569,7 @@ BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2213
1569
  * @return {string}
2214
1570
  */
2215
1571
  BookReader.prototype._getPageURI = function(index, reduce, rotate) {
2216
- const page = this._models.book.getPage(index, false);
1572
+ const page = this.book.getPage(index, false);
2217
1573
  // Synthesize page
2218
1574
  if (!page) return this.imagesBaseURL + "transparent.png";
2219
1575
 
@@ -2279,7 +1635,7 @@ BookReader.prototype.initUIStrings = function() {
2279
1635
  // the toolbar and nav bar easier
2280
1636
 
2281
1637
  // Setup tooltips -- later we could load these from a file for i18n
2282
- var titles = {
1638
+ const titles = {
2283
1639
  '.logo': 'Go to Archive.org', // $$$ update after getting OL record
2284
1640
  '.zoom_in': 'Zoom in',
2285
1641
  '.zoom_out': 'Zoom out',
@@ -2295,8 +1651,6 @@ BookReader.prototype.initUIStrings = function() {
2295
1651
  '.full': 'Toggle fullscreen',
2296
1652
  '.book_left': 'Flip left',
2297
1653
  '.book_right': 'Flip right',
2298
- '.book_up': 'Page up',
2299
- '.book_down': 'Page down',
2300
1654
  '.play': 'Play',
2301
1655
  '.pause': 'Pause',
2302
1656
  '.BRdn': 'Show/hide nav bar', // Would have to keep updating on state change to have just "Hide nav bar"
@@ -2311,10 +1665,10 @@ BookReader.prototype.initUIStrings = function() {
2311
1665
  titles['.book_rightmost'] = 'First page';
2312
1666
  }
2313
1667
 
2314
- for (var icon in titles) {
1668
+ for (const icon in titles) {
2315
1669
  this.$(icon).prop('title', titles[icon]);
2316
1670
  }
2317
- }
1671
+ };
2318
1672
 
2319
1673
  /**
2320
1674
  * Reloads images. Useful when some images might have failed.
@@ -2322,7 +1676,7 @@ BookReader.prototype.initUIStrings = function() {
2322
1676
  BookReader.prototype.reloadImages = function() {
2323
1677
  this.refs.$brContainer.find('img').each(function(index, elem) {
2324
1678
  if (!elem.complete || elem.naturalHeight === 0) {
2325
- var src = elem.src;
1679
+ const src = elem.src;
2326
1680
  elem.src = '';
2327
1681
  setTimeout(function() {
2328
1682
  elem.src = src;
@@ -2336,16 +1690,16 @@ BookReader.prototype.reloadImages = function() {
2336
1690
  * @return {number}
2337
1691
  */
2338
1692
  BookReader.prototype.getFooterHeight = function() {
2339
- var $heightEl = this.mode == this.constMode2up ? this.refs.$BRfooter : this.refs.$BRnav;
1693
+ const $heightEl = this.mode == this.constMode2up ? this.refs.$BRfooter : this.refs.$BRnav;
2340
1694
  if ($heightEl && this.refs.$BRfooter) {
2341
- var outerHeight = $heightEl.outerHeight();
2342
- var bottom = parseInt(this.refs.$BRfooter.css('bottom'));
1695
+ const outerHeight = $heightEl.outerHeight();
1696
+ const bottom = parseInt(this.refs.$BRfooter.css('bottom'));
2343
1697
  if (!isNaN(outerHeight) && !isNaN(bottom)) {
2344
1698
  return outerHeight + bottom;
2345
1699
  }
2346
1700
  }
2347
1701
  return 0;
2348
- }
1702
+ };
2349
1703
 
2350
1704
  // Basic Usage built-in Methods (can be overridden through options)
2351
1705
  // This implementation uses options.data value for populating BookReader
@@ -2355,10 +1709,11 @@ BookReader.prototype.getFooterHeight = function() {
2355
1709
  * @return {Object}
2356
1710
  */
2357
1711
  BookReader.prototype.paramsFromCurrent = function() {
2358
- var params = {};
1712
+ const params = {};
2359
1713
 
2360
- var index = this.currentIndex();
2361
- var pageNum = this._models.book.getPageNum(index);
1714
+ // Path params
1715
+ const index = this.currentIndex();
1716
+ const pageNum = this.book.getPageNum(index);
2362
1717
  if ((pageNum === 0) || pageNum) {
2363
1718
  params.page = pageNum;
2364
1719
  }
@@ -2366,10 +1721,17 @@ BookReader.prototype.paramsFromCurrent = function() {
2366
1721
  params.index = index;
2367
1722
  params.mode = this.mode;
2368
1723
 
1724
+ // Unused params
2369
1725
  // $$$ highlight
2370
1726
  // $$$ region
2371
1727
 
2372
- // search
1728
+ // Querystring params
1729
+ // View
1730
+ const fullscreenView = 'theater';
1731
+ if (this.isFullscreenActive) {
1732
+ params.view = fullscreenView;
1733
+ }
1734
+ // Search
2373
1735
  if (this.enableSearch) {
2374
1736
  params.search = this.searchTerm;
2375
1737
  }
@@ -2390,7 +1752,7 @@ BookReader.prototype.paramsFromCurrent = function() {
2390
1752
  * @return {Object}
2391
1753
  */
2392
1754
  BookReader.prototype.paramsFromFragment = function(fragment) {
2393
- var params = {};
1755
+ const params = {};
2394
1756
 
2395
1757
  // For backwards compatibility we allow an initial # character
2396
1758
  // (as from window.location.hash) but don't require it
@@ -2399,7 +1761,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2399
1761
  }
2400
1762
 
2401
1763
  // Simple #nn syntax
2402
- var oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
1764
+ const oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
2403
1765
  if ( !isNaN(oldStyleLeafNum) ) {
2404
1766
  params.index = oldStyleLeafNum;
2405
1767
 
@@ -2408,9 +1770,9 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2408
1770
  }
2409
1771
 
2410
1772
  // Split into key-value pairs
2411
- var urlArray = fragment.split('/');
2412
- var urlHash = {};
2413
- for (var i = 0; i < urlArray.length; i += 2) {
1773
+ const urlArray = fragment.split('/');
1774
+ const urlHash = {};
1775
+ for (let i = 0; i < urlArray.length; i += 2) {
2414
1776
  urlHash[urlArray[i]] = urlArray[i + 1];
2415
1777
  }
2416
1778
 
@@ -2426,7 +1788,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2426
1788
  // Index and page
2427
1789
  if ('undefined' != typeof(urlHash['page'])) {
2428
1790
  // page was set -- may not be int
2429
- params.page = urlHash['page'];
1791
+ params.page = decodeURIComponent(urlHash['page']);
2430
1792
  }
2431
1793
 
2432
1794
  // $$$ process /region
@@ -2440,7 +1802,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2440
1802
 
2441
1803
  // $$$ process /theme
2442
1804
  if (urlHash['theme'] != undefined) {
2443
- params.theme = urlHash['theme']
1805
+ params.theme = urlHash['theme'];
2444
1806
  }
2445
1807
  return params;
2446
1808
  };
@@ -2458,11 +1820,10 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2458
1820
  * @return {string}
2459
1821
  */
2460
1822
  BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
2461
- const separator = '/';
2462
1823
  const fragments = [];
2463
1824
 
2464
1825
  if ('undefined' != typeof(params.page)) {
2465
- fragments.push('page', params.page);
1826
+ fragments.push('page', encodeURIComponent(params.page));
2466
1827
  } else {
2467
1828
  if ('undefined' != typeof(params.index)) {
2468
1829
  // Don't have page numbering but we do have the index
@@ -2488,15 +1849,18 @@ BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
2488
1849
 
2489
1850
  // search
2490
1851
  if (params.search && urlMode === 'hash') {
2491
- fragments.push('search', params.search);
1852
+ fragments.push('search', utils.encodeURIComponentPlus(params.search));
2492
1853
  }
2493
1854
 
2494
- return utils.encodeURIComponentPlus(fragments.join(separator)).replace(/%2F/g, '/');
1855
+ return fragments.join('/');
2495
1856
  };
2496
1857
 
2497
1858
  /**
2498
1859
  * Create, update querystring from the params object
2499
1860
  *
1861
+ * Handles:
1862
+ * view=
1863
+ * q=
2500
1864
  * @param {Object} params
2501
1865
  * @param {string} currQueryString
2502
1866
  * @param {string} [urlMode]
@@ -2508,27 +1872,29 @@ BookReader.prototype.queryStringFromParams = function(
2508
1872
  urlMode = 'hash'
2509
1873
  ) {
2510
1874
  const newParams = new URLSearchParams(currQueryString);
1875
+
1876
+ if (params.view) {
1877
+ // Set ?view=theater when fullscreen
1878
+ newParams.set('view', params.view);
1879
+ } else {
1880
+ // Remove
1881
+ newParams.delete('view');
1882
+ }
1883
+
2511
1884
  if (params.search && urlMode === 'history') {
2512
- newParams.set('q', params.search)
1885
+ newParams.set('q', params.search);
2513
1886
  }
2514
1887
  // https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
2515
1888
  // Note: This method returns the query string without the question mark.
2516
1889
  const result = newParams.toString();
2517
1890
  return result ? '?' + result : '';
2518
- }
1891
+ };
2519
1892
 
2520
1893
  /**
2521
1894
  * Helper to select within instance's elements
2522
1895
  */
2523
1896
  BookReader.prototype.$ = function(selector) {
2524
1897
  return this.refs.$br.find(selector);
2525
- }
2526
-
2527
- /**
2528
- * Polyfill for deprecated method
2529
- */
2530
- jQuery.curCSS = function(element, prop, val) {
2531
- return jQuery(element).css(prop, val);
2532
1898
  };
2533
1899
 
2534
1900
  window.BookReader = BookReader;