@internetarchive/bookreader 5.0.0-6-multiple-files → 5.0.0-60

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