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

Sign up to get free protection for your applications and to get access to all the features.
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;