@internetarchive/bookreader 5.0.0-6-14 → 5.0.0-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (271) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +72 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +241 -140
  6. package/BookReader/BookReader.js +1 -1
  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/close-circle-dark.svg +1 -0
  13. package/BookReader/icons/magnify-minus.svg +1 -1
  14. package/BookReader/icons/magnify-plus.svg +1 -1
  15. package/BookReader/icons/pause.svg +1 -1
  16. package/BookReader/icons/playback-speed.svg +1 -1
  17. package/BookReader/icons/read-aloud.svg +1 -1
  18. package/BookReader/icons/voice.svg +1 -0
  19. package/BookReader/images/BRicons.svg +2 -2
  20. package/BookReader/images/books_graphic.svg +1 -1
  21. package/BookReader/images/icon_book.svg +1 -1
  22. package/BookReader/images/icon_gear.svg +1 -1
  23. package/BookReader/images/icon_info.svg +1 -1
  24. package/BookReader/images/icon_playback-rate.svg +1 -1
  25. package/BookReader/images/icon_search_button.svg +1 -1
  26. package/BookReader/images/icon_share.svg +1 -1
  27. package/BookReader/images/icon_speaker.svg +1 -1
  28. package/BookReader/images/icon_speaker_open.svg +1 -1
  29. package/BookReader/images/marker_chap-off.svg +1 -1
  30. package/BookReader/images/marker_chap-on.svg +1 -1
  31. package/BookReader/images/marker_srch-on.svg +1 -1
  32. package/BookReader/jquery-3.js +2 -0
  33. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  34. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  35. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  36. package/BookReader/plugins/plugin.autoplay.js +1 -1
  37. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  38. package/BookReader/plugins/plugin.chapters.js +1 -1
  39. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  40. package/BookReader/plugins/plugin.iframe.js +1 -1
  41. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  42. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  43. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  44. package/BookReader/plugins/plugin.resume.js +1 -1
  45. package/BookReader/plugins/plugin.resume.js.map +1 -1
  46. package/BookReader/plugins/plugin.search.js +1 -1
  47. package/BookReader/plugins/plugin.search.js.map +1 -1
  48. package/BookReader/plugins/plugin.text_selection.js +1 -1
  49. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  50. package/BookReader/plugins/plugin.tts.js +1 -1
  51. package/BookReader/plugins/plugin.tts.js.map +1 -1
  52. package/BookReader/plugins/plugin.url.js +1 -1
  53. package/BookReader/plugins/plugin.url.js.map +1 -1
  54. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  55. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  56. package/BookReader/webcomponents-bundle.js +3 -0
  57. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  58. package/BookReader/webcomponents-bundle.js.map +1 -0
  59. package/BookReaderDemo/BookReaderDemo.css +14 -1
  60. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  61. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  62. package/BookReaderDemo/IADemoBr.js +147 -0
  63. package/BookReaderDemo/demo-advanced.html +2 -2
  64. package/BookReaderDemo/demo-autoplay.html +2 -1
  65. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  66. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  67. package/BookReaderDemo/demo-fullscreen.html +2 -1
  68. package/BookReaderDemo/demo-iiif.html +2 -1
  69. package/BookReaderDemo/demo-internetarchive.html +84 -17
  70. package/BookReaderDemo/demo-multiple.html +2 -1
  71. package/BookReaderDemo/demo-preview-pages.html +2 -1
  72. package/BookReaderDemo/demo-simple.html +2 -1
  73. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  74. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  75. package/BookReaderDemo/immersion-1up.html +2 -1
  76. package/BookReaderDemo/immersion-mode.html +2 -1
  77. package/BookReaderDemo/toggle_controls.html +2 -1
  78. package/BookReaderDemo/view_mode.html +2 -1
  79. package/BookReaderDemo/viewmode-cycle.html +2 -3
  80. package/CHANGELOG.md +244 -0
  81. package/README.md +14 -1
  82. package/babel.config.js +19 -0
  83. package/codecov.yml +6 -0
  84. package/index.html +3 -0
  85. package/jsconfig.json +19 -0
  86. package/netlify.toml +5 -0
  87. package/package.json +70 -59
  88. package/renovate.json +52 -0
  89. package/scripts/preversion.js +4 -1
  90. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  91. package/src/BookNavigator/assets/button-base.js +9 -2
  92. package/src/BookNavigator/assets/ia-logo.js +17 -0
  93. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  94. package/src/BookNavigator/assets/icon_close.js +1 -1
  95. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  96. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  97. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  98. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  99. package/src/BookNavigator/book-navigator.js +585 -0
  100. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  101. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  102. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  103. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  104. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  105. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  106. package/src/BookNavigator/delete-modal-actions.js +1 -1
  107. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  108. package/src/BookNavigator/downloads/downloads.js +41 -25
  109. package/src/BookNavigator/search/search-provider.js +80 -28
  110. package/src/BookNavigator/search/search-results.js +34 -25
  111. package/src/BookNavigator/sharing.js +27 -0
  112. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  113. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  114. package/src/BookNavigator/volumes/volumes-provider.js +111 -0
  115. package/src/BookNavigator/volumes/volumes.js +188 -0
  116. package/src/BookReader/BookModel.js +59 -30
  117. package/src/BookReader/DebugConsole.js +3 -3
  118. package/src/BookReader/DragScrollable.js +233 -0
  119. package/src/BookReader/Mode1Up.js +56 -351
  120. package/src/BookReader/Mode1UpLit.js +391 -0
  121. package/src/BookReader/Mode2Up.js +73 -1318
  122. package/src/BookReader/Mode2UpLit.js +781 -0
  123. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  124. package/src/BookReader/ModeSmoothZoom.js +211 -0
  125. package/src/BookReader/ModeThumb.js +17 -11
  126. package/src/BookReader/Navbar/Navbar.js +10 -36
  127. package/src/BookReader/PageContainer.js +69 -6
  128. package/src/BookReader/ReduceSet.js +1 -1
  129. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  130. package/src/BookReader/events.js +2 -0
  131. package/src/BookReader/options.js +24 -2
  132. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  133. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  134. package/src/BookReader/utils.js +108 -13
  135. package/src/BookReader.js +481 -828
  136. package/src/assets/icons/close-circle-dark.svg +1 -0
  137. package/src/assets/icons/magnify-minus.svg +3 -7
  138. package/src/assets/icons/magnify-plus.svg +3 -7
  139. package/src/assets/icons/voice.svg +1 -0
  140. package/src/css/_BRBookmarks.scss +1 -1
  141. package/src/css/_BRComponent.scss +1 -1
  142. package/src/css/_BRmain.scss +33 -0
  143. package/src/css/_BRnav.scss +4 -26
  144. package/src/css/_BRpages.scss +147 -40
  145. package/src/css/_BRsearch.scss +25 -11
  146. package/src/css/_TextSelection.scss +16 -17
  147. package/src/css/_colorbox.scss +2 -2
  148. package/src/css/_controls.scss +17 -5
  149. package/src/css/_icons.scss +7 -1
  150. package/src/ia-bookreader/ia-bookreader.js +224 -0
  151. package/src/plugins/plugin.archive_analytics.js +3 -3
  152. package/src/plugins/plugin.autoplay.js +4 -9
  153. package/src/plugins/plugin.chapters.js +28 -35
  154. package/src/plugins/plugin.mobile_nav.js +11 -10
  155. package/src/plugins/plugin.resume.js +3 -3
  156. package/src/plugins/plugin.text_selection.js +32 -41
  157. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  158. package/src/plugins/search/plugin.search.js +179 -103
  159. package/src/plugins/search/view.js +59 -44
  160. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  161. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  162. package/src/plugins/tts/PageChunk.js +15 -21
  163. package/src/plugins/tts/PageChunkIterator.js +8 -12
  164. package/src/plugins/tts/WebTTSEngine.js +87 -71
  165. package/src/plugins/tts/plugin.tts.js +94 -125
  166. package/src/plugins/tts/utils.js +0 -25
  167. package/src/plugins/url/UrlPlugin.js +193 -0
  168. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  169. package/src/util/docCookies.js +21 -2
  170. package/tests/e2e/README.md +37 -0
  171. package/tests/e2e/autoplay.test.js +2 -2
  172. package/tests/e2e/base.test.js +7 -7
  173. package/tests/e2e/helpers/base.js +28 -23
  174. package/tests/e2e/helpers/debug.js +1 -1
  175. package/tests/e2e/helpers/desktopSearch.js +14 -13
  176. package/tests/e2e/helpers/mobileSearch.js +3 -3
  177. package/tests/e2e/helpers/params.js +17 -0
  178. package/tests/e2e/helpers/rightToLeft.js +4 -10
  179. package/tests/e2e/models/Navigation.js +13 -4
  180. package/tests/e2e/rightToLeft.test.js +4 -5
  181. package/tests/e2e/viewmode.test.js +40 -33
  182. package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
  183. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  184. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  185. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  186. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  187. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  188. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  189. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  190. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +104 -60
  191. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  192. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  193. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  194. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  195. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +59 -14
  196. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  197. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  198. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  199. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  200. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  201. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  202. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  203. package/tests/jest/BookReader/ModeSmoothZoom.test.js +175 -0
  204. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  205. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  206. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  207. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  208. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  209. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  210. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  211. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  212. package/tests/jest/BookReader/utils.test.js +217 -0
  213. package/tests/jest/BookReader.keyboard.test.js +190 -0
  214. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  215. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  216. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  217. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  218. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  219. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  220. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  221. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  222. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  223. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  224. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +57 -47
  225. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  226. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  227. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  228. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  229. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  230. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  231. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  232. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  233. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  234. package/tests/jest/setup.js +3 -0
  235. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  236. package/tests/jest/util/docCookies.test.js +24 -0
  237. package/tests/{util → jest/util}/strings.test.js +1 -1
  238. package/tests/{utils.js → jest/utils.js} +38 -0
  239. package/webpack.config.js +11 -5
  240. package/.babelrc +0 -12
  241. package/.dependabot/config.yml +0 -6
  242. package/.testcaferc.json +0 -5
  243. package/BookReader/bookreader-component-bundle.js +0 -1450
  244. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  245. package/BookReader/bookreader-component-bundle.js.map +0 -1
  246. package/BookReader/jquery-1.10.1.js +0 -2
  247. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  248. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  249. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  250. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  251. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  252. package/karma.conf.js +0 -23
  253. package/src/BookNavigator/BookModel.js +0 -14
  254. package/src/BookNavigator/BookNavigator.js +0 -438
  255. package/src/BookNavigator/assets/book-loader.js +0 -27
  256. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  257. package/src/BookNavigator/search/a-search-result.js +0 -55
  258. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  259. package/src/ItemNavigator/ItemNavigator.js +0 -372
  260. package/src/ItemNavigator/providers/sharing.js +0 -29
  261. package/src/dragscrollable-br.js +0 -261
  262. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  263. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  264. package/tests/BookReader/Mode1Up.test.js +0 -164
  265. package/tests/BookReader/Mode2Up.test.js +0 -247
  266. package/tests/BookReader/utils.test.js +0 -109
  267. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  268. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  269. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  270. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  271. 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.options.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,15 +1126,28 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1128
1126
  }
1129
1127
 
1130
1128
  this.isFullscreenActive = true;
1131
- this.animating = true;
1132
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear',() => {
1133
- this.resize();
1134
- this.jumpToIndex(currentIndex);
1135
- this.animating = false;
1136
- });
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);
1137
1138
 
1138
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
1139
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');
1140
1151
  };
1141
1152
 
1142
1153
  /**
@@ -1146,27 +1157,35 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1146
1157
  * - fires custom event
1147
1158
  * @param { boolean } bindKeyboardControls
1148
1159
  */
1149
- BookReader.prototype.exitFullScreen = function() {
1150
- this.refs.$brContainer.css('opacity', 0);
1151
-
1152
- $(document).unbind('keyup', this._fullscreenCloseHandler);
1153
-
1154
- var windowWidth = $(window).width();
1160
+ BookReader.prototype.exitFullScreen = async function () {
1161
+ this.refs.$br.addClass('BRfullscreenAnimation');
1162
+ $(document).off('keyup', this._fullscreenCloseHandler);
1155
1163
 
1164
+ const windowWidth = $(window).width();
1156
1165
  const canShow2up = this.options.controls.twoPage.visible;
1157
1166
  if (canShow2up && (windowWidth <= this.onePageMinBreakpoint)) {
1158
1167
  this.switchMode(this.constMode2up);
1159
1168
  }
1160
1169
 
1161
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
+
1162
1175
  this.updateBrClasses();
1163
- this.animating = true;
1164
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', () => {
1165
- this.resize();
1166
- this.animating = false;
1167
- });
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
+ }
1184
+
1168
1185
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1169
- this.trigger(BookReader.eventNames.fullscreenToggled);
1186
+ // Remove "?view=theater"
1187
+ this.trigger(BookReader.eventNames.fragmentChange);
1188
+ this.refs.$br.removeClass('BRfullscreenAnimation');
1170
1189
  };
1171
1190
 
1172
1191
  /**
@@ -1180,7 +1199,7 @@ BookReader.prototype.currentIndex = function() {
1180
1199
  return this.firstIndex; // $$$ TODO page in center of view would be better
1181
1200
  } else if (this.mode == this.constMode2up) {
1182
1201
  // Only allow indices that are actually present in book
1183
- return utils.clamp(this.firstIndex, 0, this._models.book.getNumLeafs() - 1);
1202
+ return utils.clamp(this.firstIndex, 0, this.book.getNumLeafs() - 1);
1184
1203
  } else {
1185
1204
  throw 'currentIndex called for unimplemented mode ' + this.mode;
1186
1205
  }
@@ -1197,11 +1216,9 @@ BookReader.prototype.updateFirstIndex = function(
1197
1216
  index,
1198
1217
  { suppressFragmentChange = false } = {}
1199
1218
  ) {
1200
- // Called multiple times when defaults contains "mode/1up",
1201
- // including after init(). Skip fragment change if no index change
1202
- if (this.firstIndex === index) {
1203
- suppressFragmentChange = true;
1204
- }
1219
+ // If there's no change, do nothing
1220
+ if (this.firstIndex === index) return;
1221
+
1205
1222
  this.firstIndex = index;
1206
1223
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1207
1224
  this.trigger(BookReader.eventNames.fragmentChange);
@@ -1212,8 +1229,12 @@ BookReader.prototype.updateFirstIndex = function(
1212
1229
  if (this.options.initialSearchTerm && !suppressFragmentChange) {
1213
1230
  this.suppressFragmentChange = false;
1214
1231
  }
1215
- this.trigger('pageChanged');
1216
- 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);
1217
1238
  };
1218
1239
 
1219
1240
  /**
@@ -1260,24 +1281,24 @@ BookReader.prototype.leftmost = function() {
1260
1281
  }
1261
1282
  };
1262
1283
 
1263
- BookReader.prototype.next = function() {
1284
+ BookReader.prototype.next = function({triggerStop = true} = {}) {
1264
1285
  if (this.constMode2up == this.mode) {
1265
- this.trigger(BookReader.eventNames.stop);
1266
- this.flipFwdToIndex(null);
1286
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1287
+ this._modes.mode2Up.mode2UpLit.flipAnimation('next');
1267
1288
  } else {
1268
- if (this.firstIndex < this.lastDisplayableIndex()) {
1289
+ if (this.firstIndex < this.book.getNumLeafs() - 1) {
1269
1290
  this.jumpToIndex(this.firstIndex + 1);
1270
1291
  }
1271
1292
  }
1272
1293
  };
1273
1294
 
1274
- BookReader.prototype.prev = function() {
1295
+ BookReader.prototype.prev = function({triggerStop = true} = {}) {
1275
1296
  const isOnFrontPage = this.firstIndex < 1;
1276
1297
  if (isOnFrontPage) return;
1277
1298
 
1278
1299
  if (this.constMode2up == this.mode) {
1279
- this.trigger(BookReader.eventNames.stop);
1280
- this.flipBackToIndex(null);
1300
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1301
+ this._modes.mode2Up.mode2UpLit.flipAnimation('prev');
1281
1302
  } else {
1282
1303
  if (this.firstIndex >= 1) {
1283
1304
  this.jumpToIndex(this.firstIndex - 1);
@@ -1286,257 +1307,13 @@ BookReader.prototype.prev = function() {
1286
1307
  };
1287
1308
 
1288
1309
  BookReader.prototype.first = function() {
1289
- this.jumpToIndex(this.firstDisplayableIndex());
1310
+ this.jumpToIndex(0);
1290
1311
  };
1291
1312
 
1292
1313
  BookReader.prototype.last = function() {
1293
- this.jumpToIndex(this.lastDisplayableIndex());
1294
- };
1295
-
1296
- /**
1297
- * Scrolls down one screen view
1298
- */
1299
- BookReader.prototype.scrollDown = function() {
1300
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1301
- if ( this.mode == this.constMode1up && (this.reduce >= this.onePageGetAutofitHeight()) ) {
1302
- // Whole pages are visible, scroll whole page only
1303
- return this.next();
1304
- }
1305
-
1306
- this.refs.$brContainer.stop(true).animate(
1307
- { scrollTop: '+=' + this._scrollAmount() + 'px'},
1308
- 400, 'easeInOutExpo'
1309
- );
1310
- return true;
1311
- } else {
1312
- return false;
1313
- }
1314
- };
1315
-
1316
- /**
1317
- * Scrolls up one screen view
1318
- */
1319
- BookReader.prototype.scrollUp = function() {
1320
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1321
- if ( this.mode == this.constMode1up && (this.reduce >= this.onePageGetAutofitHeight()) ) {
1322
- // Whole pages are visible, scroll whole page only
1323
- return this.prev();
1324
- }
1325
-
1326
- this.refs.$brContainer.stop(true).animate(
1327
- { scrollTop: '-=' + this._scrollAmount() + 'px'},
1328
- 400, 'easeInOutExpo'
1329
- );
1330
- return true;
1331
- } else {
1332
- return false;
1333
- }
1314
+ this.jumpToIndex(this.book.getNumLeafs() - 1);
1334
1315
  };
1335
1316
 
1336
- /**
1337
- * The amount to scroll vertically in integer pixels
1338
- */
1339
- BookReader.prototype._scrollAmount = function() {
1340
- if (this.constMode1up == this.mode) {
1341
- // Overlap by % of page size
1342
- return parseInt(this.refs.$brContainer.prop('clientHeight') - this._models.book.getPageHeight(this.currentIndex()) / this.reduce * 0.03);
1343
- }
1344
-
1345
- return parseInt(0.9 * this.refs.$brContainer.prop('clientHeight'));
1346
- };
1347
-
1348
- /**
1349
- * @deprecated No longer used; will be remove in v5
1350
- */
1351
- BookReader.prototype.prefetchImg = async function(index, fetchNow = false) {
1352
- console.warn('Call to deprecated function: BookReader.prefetchImg. No-op.');
1353
- };
1354
-
1355
- /**
1356
- * @deprecated No longer used; will be remove in v5
1357
- */
1358
- BookReader.prototype.pruneUnusedImgs = function() {
1359
- console.warn('Call to deprecated function: BookReader.pruneUnused. No-op.');
1360
- };
1361
-
1362
- /************************/
1363
- /** Mode1Up extensions **/
1364
- /************************/
1365
- /** @deprecated not used outside BookReader */
1366
- BookReader.prototype.prepareOnePageView = Mode1Up.prototype.prepare;
1367
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'prepare', 'prepareOnePageView');
1368
- /** @deprecated not used outside BookReader */
1369
- BookReader.prototype.drawLeafsOnePage = Mode1Up.prototype.drawLeafs;
1370
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'drawLeafs', 'drawLeafsOnePage');
1371
- /** @deprecated not used outside BookReader */
1372
- BookReader.prototype.zoom1up = Mode1Up.prototype.zoom;
1373
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'zoom', 'zoom1up');
1374
- /** @deprecated not used outside Mode1Up */
1375
- BookReader.prototype.onePageGetAutofitWidth = Mode1Up.prototype.getAutofitWidth;
1376
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitWidth', 'onePageGetAutofitWidth');
1377
- /** @deprecated not used outside Mode1Up, BookReader */
1378
- BookReader.prototype.onePageGetAutofitHeight = Mode1Up.prototype.getAutofitHeight;
1379
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitHeight', 'onePageGetAutofitHeight');
1380
- /** @deprecated not used outside Mode1Up, BookReader */
1381
- BookReader.prototype.onePageGetPageTop = Mode1Up.prototype.getPageTop;
1382
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getPageTop', 'onePageGetPageTop');
1383
- /** @deprecated not used outside Mode1Up, BookReader */
1384
- BookReader.prototype.onePageCalculateReductionFactors = Mode1Up.prototype.calculateReductionFactors;
1385
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateReductionFactors', 'onePageCalculateReductionFactors');
1386
- /** @deprecated not used outside Mode1Up, BookReader */
1387
- BookReader.prototype.resizePageView1up = Mode1Up.prototype.resizePageView;
1388
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'resizePageView', 'resizePageView1up');
1389
- /** @deprecated not used outside Mode1Up */
1390
- BookReader.prototype.onePageCalculateViewDimensions = Mode1Up.prototype.calculateViewDimensions;
1391
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateViewDimensions', 'onePageCalculateViewDimensions');
1392
- /** @deprecated not used outside Mode1Up */
1393
- BookReader.prototype.centerX1up = Mode1Up.prototype.centerX;
1394
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerX', 'centerX1up');
1395
- /** @deprecated not used outside Mode1Up */
1396
- BookReader.prototype.centerY1up = Mode1Up.prototype.centerY;
1397
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerY', 'centerY1up');
1398
-
1399
- /************************/
1400
- /** Mode2Up extensions **/
1401
- /************************/
1402
- /** @deprecated not used outside Mode2Up */
1403
- BookReader.prototype.zoom2up = Mode2Up.prototype.zoom;
1404
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'zoom', 'zoom2up');
1405
- BookReader.prototype.twoPageGetAutofitReduce = Mode2Up.prototype.getAutofitReduce;
1406
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getAutofitReduce', 'twoPageGetAutofitReduce');
1407
- BookReader.prototype.flipBackToIndex = Mode2Up.prototype.flipBackToIndex;
1408
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipBackToIndex', 'flipBackToIndex');
1409
- BookReader.prototype.flipFwdToIndex = Mode2Up.prototype.flipFwdToIndex;
1410
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipFwdToIndex', 'flipFwdToIndex');
1411
- BookReader.prototype.setHilightCss2UP = Mode2Up.prototype.setHilightCss;
1412
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setHilightCss', 'setHilightCss2UP');
1413
- /** @deprecated not used outside Mode2Up */
1414
- BookReader.prototype.setClickHandler2UP = Mode2Up.prototype.setClickHandler;
1415
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setClickHandler', 'setClickHandler2UP');
1416
- /** @deprecated not used outside Mode2Up */
1417
- BookReader.prototype.drawLeafsTwoPage = Mode2Up.prototype.drawLeafs;
1418
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'drawLeafs', 'drawLeafsTwoPage');
1419
- /** @deprecated not used outside BookReader */
1420
- BookReader.prototype.prepareTwoPageView = Mode2Up.prototype.prepareTwoPageView;
1421
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareTwoPageView', 'prepareTwoPageView');
1422
- /** @deprecated not used outside Mode2Up */
1423
- BookReader.prototype.prepareTwoPagePopUp = Mode2Up.prototype.preparePopUp;
1424
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'preparePopUp', 'prepareTwoPagePopUp');
1425
- /** @deprecated not used outside BookReader, Mode2Up */
1426
- BookReader.prototype.calculateSpreadSize = Mode2Up.prototype.calculateSpreadSize;
1427
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateSpreadSize', 'calculateSpreadSize');
1428
- /** @deprecated not used outside BookReader, Mode2Up */
1429
- BookReader.prototype.getIdealSpreadSize = Mode2Up.prototype.getIdealSpreadSize;
1430
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getIdealSpreadSize', 'getIdealSpreadSize');
1431
- /** @deprecated not used outside BookReader, Mode2Up */
1432
- BookReader.prototype.getSpreadSizeFromReduce = Mode2Up.prototype.getSpreadSizeFromReduce;
1433
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getSpreadSizeFromReduce', 'getSpreadSizeFromReduce');
1434
- /** @deprecated unused */
1435
- BookReader.prototype.twoPageIsZoomedIn = Mode2Up.prototype.isZoomedIn;
1436
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'isZoomedIn', 'twoPageIsZoomedIn');
1437
- /** @deprecated not used outside BookReader */
1438
- BookReader.prototype.twoPageCalculateReductionFactors = Mode2Up.prototype.calculateReductionFactors;
1439
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateReductionFactors', 'twoPageCalculateReductionFactors');
1440
- /** @deprecated unused */
1441
- BookReader.prototype.twoPageSetCursor = Mode2Up.prototype.setCursor;
1442
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setCursor', 'twoPageSetCursor');
1443
- /** @deprecated unused outside BookReader, Mode2Up */
1444
- BookReader.prototype.flipLeftToRight = Mode2Up.prototype.flipLeftToRight;
1445
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipLeftToRight', 'flipLeftToRight');
1446
- /** @deprecated unused outside BookReader, Mode2Up */
1447
- BookReader.prototype.flipRightToLeft = Mode2Up.prototype.flipRightToLeft;
1448
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipRightToLeft', 'flipRightToLeft');
1449
- /** @deprecated unused outside Mode2Up */
1450
- BookReader.prototype.setMouseHandlers2UP = Mode2Up.prototype.setMouseHandlers;
1451
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setMouseHandlers', 'setMouseHandlers2UP');
1452
- /** @deprecated unused outside BookReader, Mode2Up */
1453
- BookReader.prototype.prepareFlipLeftToRight = Mode2Up.prototype.prepareFlipLeftToRight;
1454
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipLeftToRight', 'prepareFlipLeftToRight');
1455
- /** @deprecated unused outside BookReader, Mode2Up */
1456
- BookReader.prototype.prepareFlipRightToLeft = Mode2Up.prototype.prepareFlipRightToLeft;
1457
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipRightToLeft', 'prepareFlipRightToLeft');
1458
- /** @deprecated unused outside Mode2Up */
1459
- BookReader.prototype.getPageWidth2UP = Mode2Up.prototype.getPageWidth;
1460
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getPageWidth', 'getPageWidth2UP');
1461
- /** @deprecated unused outside Mode2Up */
1462
- BookReader.prototype.twoPageGutter = Mode2Up.prototype.gutter;
1463
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutter', 'twoPageGutter');
1464
- /** @deprecated unused outside Mode2Up */
1465
- BookReader.prototype.twoPageTop = Mode2Up.prototype.top;
1466
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'top', 'twoPageTop');
1467
- /** @deprecated unused outside Mode2Up */
1468
- BookReader.prototype.twoPageCoverWidth = Mode2Up.prototype.coverWidth;
1469
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'coverWidth', 'twoPageCoverWidth');
1470
- /** @deprecated unused outside Mode2Up */
1471
- BookReader.prototype.twoPageGetViewCenter = Mode2Up.prototype.getViewCenter;
1472
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getViewCenter', 'twoPageGetViewCenter');
1473
- /** @deprecated unused outside BookReader, Mode2Up */
1474
- BookReader.prototype.twoPageCenterView = Mode2Up.prototype.centerView;
1475
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'centerView', 'twoPageCenterView');
1476
- /** @deprecated unused outside Mode2Up */
1477
- BookReader.prototype.twoPageFlipAreaHeight = Mode2Up.prototype.flipAreaHeight;
1478
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaHeight', 'twoPageFlipAreaHeight');
1479
- /** @deprecated unused outside Mode2Up */
1480
- BookReader.prototype.twoPageFlipAreaWidth = Mode2Up.prototype.flipAreaWidth;
1481
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaWidth', 'twoPageFlipAreaWidth');
1482
- /** @deprecated unused outside BookReader, Mode2Up */
1483
- BookReader.prototype.twoPageFlipAreaTop = Mode2Up.prototype.flipAreaTop;
1484
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaTop', 'twoPageFlipAreaTop');
1485
- /** @deprecated unused outside Mode2Up */
1486
- BookReader.prototype.twoPageLeftFlipAreaLeft = Mode2Up.prototype.leftFlipAreaLeft;
1487
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leftFlipAreaLeft', 'twoPageLeftFlipAreaLeft');
1488
- /** @deprecated unused outside Mode2Up */
1489
- BookReader.prototype.twoPageRightFlipAreaLeft = Mode2Up.prototype.rightFlipAreaLeft;
1490
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'rightFlipAreaLeft', 'twoPageRightFlipAreaLeft');
1491
- /** @deprecated unused outside BookReader, Mode2Up */
1492
- BookReader.prototype.gutterOffsetForIndex = Mode2Up.prototype.gutterOffsetForIndex;
1493
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutterOffsetForIndex', 'gutterOffsetForIndex');
1494
- /** @deprecated unused outside BookReader, Mode2Up */
1495
- BookReader.prototype.leafEdgeWidth = Mode2Up.prototype.leafEdgeWidth;
1496
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leafEdgeWidth', 'leafEdgeWidth');
1497
- /** @deprecated unused outside BookReader, Mode2Up */
1498
- BookReader.prototype.jumpIndexForLeftEdgePageX = Mode2Up.prototype.jumpIndexForLeftEdgePageX;
1499
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForLeftEdgePageX', 'jumpIndexForLeftEdgePageX');
1500
- /** @deprecated unused outside BookReader, Mode2Up */
1501
- BookReader.prototype.jumpIndexForRightEdgePageX = Mode2Up.prototype.jumpIndexForRightEdgePageX;
1502
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForRightEdgePageX', 'jumpIndexForRightEdgePageX');
1503
- /** @deprecated unused outside Mode2Up */
1504
- BookReader.prototype.prefetch = Mode2Up.prototype.prefetch;
1505
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prefetch', 'prefetch');
1506
- /** @deprecated unused outside Mode2Up */
1507
- BookReader.prototype.setSpreadIndices = Mode2Up.prototype.setSpreadIndices;
1508
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setSpreadIndices', 'setSpreadIndices');
1509
- /**
1510
- * Immediately stop flip animations. Callbacks are triggered.
1511
- */
1512
- BookReader.prototype.stopFlipAnimations = function() {
1513
- this.trigger(BookReader.eventNames.stop);
1514
-
1515
- // Stop animation, clear queue, trigger callbacks
1516
- if (this.leafEdgeTmp) {
1517
- $(this.leafEdgeTmp).stop(false, true);
1518
- }
1519
- jQuery.each(this._modes.mode2Up.pageContainers, function() {
1520
- $(this.$container).stop(false, true);
1521
- });
1522
-
1523
- // And again since animations also queued in callbacks
1524
- if (this.leafEdgeTmp) {
1525
- $(this.leafEdgeTmp).stop(false, true);
1526
- }
1527
- jQuery.each(this._modes.mode2Up.pageContainers, function() {
1528
- $(this.$container).stop(false, true);
1529
- });
1530
- };
1531
-
1532
- /**
1533
- * Returns true if keyboard navigation should be disabled for the event
1534
- * @param {Event}
1535
- * @return {boolean}
1536
- */
1537
- BookReader.prototype.keyboardNavigationIsDisabled = function(event) {
1538
- return event.target.tagName == "INPUT";
1539
- };
1540
1317
 
1541
1318
  /**
1542
1319
  * @template TClass extends { br: BookReader }
@@ -1560,30 +1337,9 @@ function exposeOverrideableMethod(Class, classKey, method, brMethod = method) {
1560
1337
  /***********************/
1561
1338
  /** Navbar extensions **/
1562
1339
  /***********************/
1340
+ /** This cannot be removed yet because plugin.tts.js overrides it */
1563
1341
  BookReader.prototype.initNavbar = Navbar.prototype.init;
1564
1342
  exposeOverrideableMethod(Navbar, '_components.navbar', 'init', 'initNavbar');
1565
- BookReader.prototype.switchNavbarControls = Navbar.prototype.switchNavbarControls;
1566
- exposeOverrideableMethod(Navbar, '_components.navbar', 'switchNavbarControls');
1567
- BookReader.prototype.updateViewModeButton = Navbar.prototype.updateViewModeButton;
1568
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateViewModeButton');
1569
- BookReader.prototype.getNavPageNumString = Navbar.prototype.getNavPageNumString;
1570
- exposeOverrideableMethod(Navbar, '_components.navbar', 'getNavPageNumString');
1571
- /** @deprecated */
1572
- BookReader.prototype.initEmbedNavbar = Navbar.prototype.initEmbed;
1573
- exposeOverrideableMethod(Navbar, '_components.navbar', 'initEmbed', 'initEmbedNavbar');
1574
- /** @deprecated unused */
1575
- BookReader.prototype.getNavPageNumHtml = getNavPageNumHtml;
1576
- /** @deprecated unused outside this file */
1577
- BookReader.prototype.updateNavPageNum = Navbar.prototype.updateNavPageNum;
1578
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavPageNum');
1579
- /** @deprecated unused outside this file */
1580
- BookReader.prototype.updateNavIndex = Navbar.prototype.updateNavIndex;
1581
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavIndex');
1582
- /** @deprecated unused outside this file */
1583
- BookReader.prototype.updateNavIndexThrottled = utils.throttle(BookReader.prototype.updateNavIndex, 250, false);
1584
- /** @deprecated unused */
1585
- BookReader.prototype.updateNavIndexDebounced = utils.debounce(BookReader.prototype.updateNavIndex, 500, false);
1586
-
1587
1343
 
1588
1344
  /************************/
1589
1345
  /** Toolbar extensions **/
@@ -1598,15 +1354,6 @@ BookReader.prototype.buildInfoDiv = Toolbar.prototype.buildInfoDiv;
1598
1354
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildInfoDiv');
1599
1355
  BookReader.prototype.getToolBarHeight = Toolbar.prototype.getToolBarHeight;
1600
1356
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'getToolBarHeight');
1601
- /** @deprecated zoom no longer in toolbar */
1602
- BookReader.prototype.updateToolbarZoom = Toolbar.prototype.updateToolbarZoom;
1603
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'updateToolbarZoom');
1604
- /** @deprecated unused */
1605
- BookReader.prototype.blankInfoDiv = blankInfoDiv;
1606
- /** @deprecated unused */
1607
- BookReader.prototype.blankShareDiv = blankShareDiv;
1608
- /** @deprecated unused */
1609
- BookReader.prototype.createPopup = createPopup;
1610
1357
 
1611
1358
  /**
1612
1359
  * Bind navigation handlers
@@ -1626,20 +1373,6 @@ BookReader.prototype.bindNavigationHandlers = function() {
1626
1373
  this.trigger(BookReader.eventNames.stop);
1627
1374
  this.right();
1628
1375
  },
1629
- book_up: () => {
1630
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1631
- this.scrollUp();
1632
- } else {
1633
- this.prev();
1634
- }
1635
- },
1636
- book_down: () => {
1637
- if ($.inArray(this.mode, [this.constMode1up, this.constModeThumb]) >= 0) {
1638
- this.scrollDown();
1639
- } else {
1640
- this.next();
1641
- }
1642
- },
1643
1376
  book_top: this.first.bind(this),
1644
1377
  book_bottom: this.last.bind(this),
1645
1378
  book_leftmost: this.leftmost.bind(this),
@@ -1665,7 +1398,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1665
1398
  },
1666
1399
  full: () => {
1667
1400
  if (this.ui == 'embed') {
1668
- var url = this.$('.BRembedreturn a').attr('href');
1401
+ const url = this.$('.BRembedreturn a').attr('href');
1669
1402
  window.open(url);
1670
1403
  } else {
1671
1404
  this.toggleFullscreen();
@@ -1673,23 +1406,29 @@ BookReader.prototype.bindNavigationHandlers = function() {
1673
1406
  },
1674
1407
  };
1675
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
+
1676
1415
  jIcons.filter('.fit').bind('fit', function() {
1677
1416
  // XXXmang implement autofit zoom
1678
1417
  });
1679
1418
 
1680
1419
  for (const control in navigationControls) {
1681
1420
  jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
1682
- navigationControls[control]()
1421
+ navigationControls[control]();
1683
1422
  return false;
1684
1423
  });
1685
1424
  }
1686
1425
 
1687
- var $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1688
- var $brNavCntlTopEl = this.$('.BRnavCntlTop');
1426
+ const $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1427
+ const $brNavCntlTopEl = this.$('.BRnavCntlTop');
1689
1428
 
1690
1429
  this.$('.BRnavCntl').click(
1691
1430
  function() {
1692
- var promises = [];
1431
+ const promises = [];
1693
1432
  // TODO don't use magic constants
1694
1433
  // TODO move this to a function
1695
1434
  if ($brNavCntlBtmEl.hasClass('BRdn')) {
@@ -1709,7 +1448,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1709
1448
  $brNavCntlBtmEl.addClass('BRdn').removeClass('BRup');
1710
1449
  $brNavCntlTopEl.addClass('BRup').removeClass('BRdn');
1711
1450
  self.$('.BRnavCntlBtm.BRnavCntl').animate({height:'30px'});
1712
- self.$('.BRvavCntl').animate({opacity:1})
1451
+ self.$('.BRvavCntl').animate({opacity:1});
1713
1452
  }
1714
1453
  $.when.apply($, promises).done(function() {
1715
1454
  // Only do full resize in auto mode and need to recalc. size
@@ -1727,24 +1466,28 @@ BookReader.prototype.bindNavigationHandlers = function() {
1727
1466
  });
1728
1467
  }
1729
1468
  );
1730
- $brNavCntlBtmEl.mouseover(function() {
1731
- if ($(this).hasClass('BRup')) {
1732
- self.$('.BRnavCntl').animate({opacity:1},250);
1733
- }
1734
- }).mouseleave(function() {
1735
- if ($(this).hasClass('BRup')) {
1736
- self.$('.BRnavCntl').animate({opacity:.75},250);
1737
- }
1738
- });
1739
- $brNavCntlTopEl.mouseover(function() {
1740
- if ($(this).hasClass('BRdn')) {
1741
- self.$('.BRnavCntl').animate({opacity:1},250);
1742
- }
1743
- }).mouseleave(function() {
1744
- if ($(this).hasClass('BRdn')) {
1745
- self.$('.BRnavCntl').animate({opacity:.75},250);
1746
- }
1747
- });
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
+ });
1748
1491
 
1749
1492
  this.initSwipeData();
1750
1493
 
@@ -1782,7 +1525,7 @@ BookReader.prototype.navigationMousemoveHandler = function(event) {
1782
1525
  if (event.data['br'].uiAutoHide) {
1783
1526
  // 77px is an approximate height of the Internet Archive Top Nav
1784
1527
  // 75 & 76 (pixels) provide used in this context is checked against the IA top nav height
1785
- var navkey = $(document).height() - 75;
1528
+ const navkey = $(document).height() - 75;
1786
1529
  if ((event.pageY < 76) || (event.pageY > navkey)) {
1787
1530
  // inside or near navigation elements
1788
1531
  event.data['br'].hideNavigation();
@@ -1809,11 +1552,11 @@ BookReader.prototype.initSwipeData = function(clientX, clientY) {
1809
1552
  deltaX: 0,
1810
1553
  deltaY: 0,
1811
1554
  deltaT: 0
1812
- }
1555
+ };
1813
1556
  };
1814
1557
 
1815
1558
  BookReader.prototype.swipeMousedownHandler = function(event) {
1816
- var self = event.data['br'];
1559
+ const self = event.data['br'];
1817
1560
 
1818
1561
  // We should be the last bubble point for the page images
1819
1562
  // Disable image drag and select, but keep right-click
@@ -1821,13 +1564,13 @@ BookReader.prototype.swipeMousedownHandler = function(event) {
1821
1564
  return !self.protected;
1822
1565
  }
1823
1566
 
1824
- $(event.target).bind('mouseout.swipe',
1567
+ $(event.target).on('mouseout.swipe',
1825
1568
  { 'br': self},
1826
1569
  self.swipeMouseupHandler
1827
- ).bind('mouseup.swipe',
1570
+ ).on('mouseup.swipe',
1828
1571
  { 'br': self},
1829
1572
  self.swipeMouseupHandler
1830
- ).bind('mousemove.swipe',
1573
+ ).on('mousemove.swipe',
1831
1574
  { 'br': self },
1832
1575
  self.swipeMousemoveHandler
1833
1576
  );
@@ -1843,8 +1586,8 @@ BookReader.prototype.swipeMousedownHandler = function(event) {
1843
1586
  };
1844
1587
 
1845
1588
  BookReader.prototype.swipeMousemoveHandler = function(event) {
1846
- var self = event.data['br'];
1847
- var _swipe = self._swipe;
1589
+ const self = event.data['br'];
1590
+ const _swipe = self._swipe;
1848
1591
  if (! _swipe.mightBeSwiping) {
1849
1592
  return;
1850
1593
  }
@@ -1854,12 +1597,12 @@ BookReader.prototype.swipeMousemoveHandler = function(event) {
1854
1597
  _swipe.deltaY = event.clientY - _swipe.startY;
1855
1598
  _swipe.deltaT = (new Date).getTime() - _swipe.startTime;
1856
1599
 
1857
- var absX = Math.abs(_swipe.deltaX);
1858
- var absY = Math.abs(_swipe.deltaY);
1600
+ const absX = Math.abs(_swipe.deltaX);
1601
+ const absY = Math.abs(_swipe.deltaY);
1859
1602
 
1860
1603
  // Minimum distance in the amount of tim to trigger the swipe
1861
- var minSwipeLength = Math.min(self.refs.$br.width() / 5, 80);
1862
- var maxSwipeTime = 400;
1604
+ const minSwipeLength = Math.min(self.refs.$br.width() / 5, 80);
1605
+ const maxSwipeTime = 400;
1863
1606
 
1864
1607
  // Check for horizontal swipe
1865
1608
  if (absX > absY && (absX > minSwipeLength) && _swipe.deltaT < maxSwipeTime) {
@@ -1893,11 +1636,11 @@ BookReader.prototype.swipeMousemoveHandler = function(event) {
1893
1636
  };
1894
1637
 
1895
1638
  BookReader.prototype.swipeMouseupHandler = function(event) {
1896
- var _swipe = event.data['br']._swipe;
1639
+ const _swipe = event.data['br']._swipe;
1897
1640
  _swipe.mightBeSwiping = false;
1898
1641
  _swipe.mightBeDragging = false;
1899
1642
 
1900
- $(event.target).unbind('mouseout.swipe').unbind('mouseup.swipe').unbind('mousemove.swipe');
1643
+ $(event.target).off('mouseout.swipe').off('mouseup.swipe').off('mousemove.swipe');
1901
1644
 
1902
1645
  if (_swipe.didSwipe || _swipe.didDrag) {
1903
1646
  // Swallow event if completed swipe gesture
@@ -1910,20 +1653,21 @@ BookReader.prototype.swipeMouseupHandler = function(event) {
1910
1653
  };
1911
1654
 
1912
1655
  BookReader.prototype.bindMozTouchHandlers = function() {
1913
- var self = this;
1656
+ const self = this;
1914
1657
 
1915
1658
  // Currently only want touch handlers in 2up
1916
- this.refs.$br.bind('MozTouchDown', function(event) {
1917
- if (this.mode == self.constMode2up) {
1918
- event.preventDefault();
1919
- }
1920
- })
1921
- .bind('MozTouchMove', function(event) {
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) {
1922
1666
  if (this.mode == self.constMode2up) {
1923
1667
  event.preventDefault();
1924
1668
  }
1925
1669
  })
1926
- .bind('MozTouchUp', function(event) {
1670
+ .on('MozTouchUp', function(event) {
1927
1671
  if (this.mode == self.constMode2up) {
1928
1672
  event.preventDefault();
1929
1673
  }
@@ -1936,8 +1680,8 @@ BookReader.prototype.bindMozTouchHandlers = function() {
1936
1680
  */
1937
1681
  BookReader.prototype.navigationIsVisible = function() {
1938
1682
  // $$$ doesn't account for transitioning states, nav must be fully visible to return true
1939
- var toolpos = this.refs.$BRtoolbar.position();
1940
- var tooltop = toolpos.top;
1683
+ const toolpos = this.refs.$BRtoolbar.position();
1684
+ const tooltop = toolpos.top;
1941
1685
  return tooltop == 0;
1942
1686
  };
1943
1687
 
@@ -1946,19 +1690,19 @@ BookReader.prototype.navigationIsVisible = function() {
1946
1690
  * Defaults to SHOW the navigation chrome
1947
1691
  */
1948
1692
  BookReader.prototype.setNavigationView = function brSetNavigationView(hide) {
1949
- var animationLength = this.constNavAnimationDuration;
1950
- var animationType = 'linear';
1951
- var resizePageContainer = function resizePageContainer () {
1693
+ const animationLength = this.constNavAnimationDuration;
1694
+ const animationType = 'linear';
1695
+ const resizePageContainer = function resizePageContainer () {
1952
1696
  /* main page container fills whole container */
1953
1697
  if (this.constMode2up !== this.mode) {
1954
- var animate = true;
1698
+ const animate = true;
1955
1699
  this.resizeBRcontainer(animate);
1956
1700
  }
1957
1701
  this.trigger(BookReader.eventNames.navToggled);
1958
1702
  }.bind(this);
1959
1703
 
1960
- var toolbarHeight = 0;
1961
- var navbarHeight = 0;
1704
+ let toolbarHeight = 0;
1705
+ let navbarHeight = 0;
1962
1706
  if (hide) {
1963
1707
  toolbarHeight = this.getToolBarHeight() * -1;
1964
1708
  navbarHeight = this.getFooterHeight() * -1;
@@ -1989,7 +1733,7 @@ BookReader.prototype.setNavigationView = function brSetNavigationView(hide) {
1989
1733
  BookReader.prototype.hideNavigation = function() {
1990
1734
  // Check if navigation is showing
1991
1735
  if (this.navigationIsVisible()) {
1992
- var hide = true;
1736
+ const hide = true;
1993
1737
  this.setNavigationView(hide);
1994
1738
  }
1995
1739
  };
@@ -2004,109 +1748,16 @@ BookReader.prototype.showNavigation = function() {
2004
1748
  }
2005
1749
  };
2006
1750
 
2007
- /**
2008
- * Returns the index of the first visible page, dependent on the mode.
2009
- * $$$ Currently we cannot display the front/back cover in 2-up and will need to update
2010
- * this function when we can as part of https://bugs.launchpad.net/gnubook/+bug/296788
2011
- * @return {number}
2012
- */
2013
- BookReader.prototype.firstDisplayableIndex = function() {
2014
- if (this.mode != this.constMode2up) {
2015
- return 0;
2016
- }
2017
-
2018
- if ('rl' != this.pageProgression) {
2019
- // LTR
2020
- if (this._models.book.getPageSide(0) == 'L') {
2021
- return 0;
2022
- } else {
2023
- return -1;
2024
- }
2025
- } else {
2026
- // RTL
2027
- if (this._models.book.getPageSide(0) == 'R') {
2028
- return 0;
2029
- } else {
2030
- return -1;
2031
- }
2032
- }
2033
- };
2034
-
2035
- /**
2036
- * Returns the index of the last visible page, dependent on the mode.
2037
- * $$$ Currently we cannot display the front/back cover in 2-up and will need to update
2038
- * this function when we can as part of https://bugs.launchpad.net/gnubook/+bug/296788
2039
- * @return {number}
2040
- */
2041
- BookReader.prototype.lastDisplayableIndex = function() {
2042
-
2043
- var lastIndex = this._models.book.getNumLeafs() - 1;
2044
-
2045
- if (this.mode != this.constMode2up) {
2046
- return lastIndex;
2047
- }
2048
-
2049
- if ('rl' != this.pageProgression) {
2050
- // LTR
2051
- if (this._models.book.getPageSide(lastIndex) == 'R') {
2052
- return lastIndex;
2053
- } else {
2054
- return lastIndex + 1;
2055
- }
2056
- } else {
2057
- // RTL
2058
- if (this._models.book.getPageSide(lastIndex) == 'L') {
2059
- return lastIndex;
2060
- } else {
2061
- return lastIndex + 1;
2062
- }
2063
- }
2064
- };
2065
1751
 
2066
1752
 
2067
1753
  /**************************/
2068
1754
  /** BookModel extensions **/
2069
1755
  /**************************/
2070
- /** @deprecated not used outside */
2071
- BookReader.prototype.getMedianPageSize = BookModel.prototype.getMedianPageSize;
2072
- exposeOverrideableMethod(BookModel, '_models.book', 'getMedianPageSize');
2073
- BookReader.prototype._getPageWidth = BookModel.prototype._getPageWidth;
2074
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageWidth');
2075
- BookReader.prototype._getPageHeight = BookModel.prototype._getPageHeight;
2076
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageHeight');
2077
- BookReader.prototype.getPageIndex = BookModel.prototype.getPageIndex;
2078
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndex');
2079
- /** @deprecated not used outside */
2080
- BookReader.prototype.getPageIndices = BookModel.prototype.getPageIndices;
2081
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndices');
2082
- BookReader.prototype.getPageName = BookModel.prototype.getPageName;
2083
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageName');
2084
- BookReader.prototype.getNumLeafs = BookModel.prototype.getNumLeafs;
2085
- exposeOverrideableMethod(BookModel, '_models.book', 'getNumLeafs');
2086
- BookReader.prototype.getPageWidth = BookModel.prototype.getPageWidth;
2087
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageWidth');
2088
- BookReader.prototype.getPageHeight = BookModel.prototype.getPageHeight;
2089
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageHeight');
1756
+ // Must modify petabox extension, which expects this on the prototype
1757
+ // before removing.
2090
1758
  BookReader.prototype.getPageURI = BookModel.prototype.getPageURI;
2091
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageURI');
2092
- BookReader.prototype.getPageSide = BookModel.prototype.getPageSide;
2093
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageSide');
2094
- BookReader.prototype.getPageNum = BookModel.prototype.getPageNum;
2095
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageNum');
2096
- BookReader.prototype.getPageProp = BookModel.prototype.getPageProp;
2097
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageProp');
2098
- BookReader.prototype.getSpreadIndices = BookModel.prototype.getSpreadIndices;
2099
- exposeOverrideableMethod(BookModel, '_models.book', 'getSpreadIndices');
2100
- BookReader.prototype.leafNumToIndex = BookModel.prototype.leafNumToIndex;
2101
- exposeOverrideableMethod(BookModel, '_models.book', 'leafNumToIndex');
2102
- BookReader.prototype.parsePageString = BookModel.prototype.parsePageString;
2103
- exposeOverrideableMethod(BookModel, '_models.book', 'parsePageString');
2104
- /** @deprecated unused */
2105
- BookReader.prototype._getDataFlattened = BookModel.prototype._getDataFlattened;
2106
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataFlattened');
2107
- /** @deprecated unused */
2108
- BookReader.prototype._getDataProp = BookModel.prototype._getDataProp;
2109
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataProp');
1759
+ exposeOverrideableMethod(BookModel, 'book', 'getPageURI');
1760
+
2110
1761
 
2111
1762
  // Parameter related functions
2112
1763
 
@@ -2137,7 +1788,7 @@ BookReader.prototype.updateFromParams = function(params) {
2137
1788
  }
2138
1789
  } else if ('undefined' != typeof(params.page)) {
2139
1790
  // $$$ this assumes page numbers are unique
2140
- if (params.page != this._models.book.getPageNum(this.currentIndex())) {
1791
+ if (params.page != this.book.getPageNum(this.currentIndex())) {
2141
1792
  this.jumpToPage(params.page);
2142
1793
  }
2143
1794
  }
@@ -2171,7 +1822,7 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2171
1822
  // check there are enough pages to display
2172
1823
  // $$$ this is a workaround for the mis-feature that we can't display
2173
1824
  // short books in 2up mode
2174
- if (this._models.book.getNumLeafs() < 2) {
1825
+ if (this.book.getNumLeafs() < 2) {
2175
1826
  return false;
2176
1827
  }
2177
1828
  }
@@ -2179,31 +1830,6 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2179
1830
  return true;
2180
1831
  };
2181
1832
 
2182
-
2183
- /**
2184
- * @deprecated. Use PageModel.getURISrcSet. Slated for removal in v5.
2185
- * Returns the srcset with correct URIs or void string if out of range
2186
- * Also makes the reduce argument optional
2187
- * @param {number} index
2188
- * @param {number} [reduce]
2189
- * @param {number} [rotate]
2190
- * @return {string}
2191
- */
2192
- BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2193
- const page = this._models.book.getPage(index, false);
2194
- // Synthesize page
2195
- if (!page) return "";
2196
-
2197
- // reduce not passed in
2198
- // $$$ this probably won't work for thumbnail mode
2199
- if ('undefined' == typeof(reduce)) {
2200
- reduce = page.height / this.twoPage.height;
2201
- }
2202
-
2203
- return page.getURISrcSet(reduce, rotate);
2204
- }
2205
-
2206
-
2207
1833
  /**
2208
1834
  * Returns the page URI or transparent image if out of range
2209
1835
  * Also makes the reduce argument optional
@@ -2213,7 +1839,7 @@ BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2213
1839
  * @return {string}
2214
1840
  */
2215
1841
  BookReader.prototype._getPageURI = function(index, reduce, rotate) {
2216
- const page = this._models.book.getPage(index, false);
1842
+ const page = this.book.getPage(index, false);
2217
1843
  // Synthesize page
2218
1844
  if (!page) return this.imagesBaseURL + "transparent.png";
2219
1845
 
@@ -2227,21 +1853,37 @@ BookReader.prototype._getPageURI = function(index, reduce, rotate) {
2227
1853
  };
2228
1854
 
2229
1855
  /**
2230
- * @param {string}
1856
+ * @param {string} msg
1857
+ * @param {function|undefined} onCloseCallback
2231
1858
  */
2232
- BookReader.prototype.showProgressPopup = function(msg) {
1859
+ BookReader.prototype.showProgressPopup = function(msg, onCloseCallback) {
2233
1860
  if (this.popup) return;
2234
1861
 
2235
1862
  this.popup = document.createElement("div");
2236
1863
  $(this.popup).prop('className', 'BRprogresspopup');
2237
- 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");
2238
1880
  $(bar).css({
2239
1881
  height: '20px'
2240
1882
  }).prop('className', 'BRprogressbar');
2241
1883
  $(this.popup).append(bar);
2242
1884
 
2243
1885
  if (msg) {
2244
- var msgdiv = document.createElement("div");
1886
+ const msgdiv = document.createElement("div");
2245
1887
  msgdiv.innerHTML = msg;
2246
1888
  $(this.popup).append(msgdiv);
2247
1889
  }
@@ -2263,7 +1905,7 @@ BookReader.prototype.initUIStrings = function() {
2263
1905
  // the toolbar and nav bar easier
2264
1906
 
2265
1907
  // Setup tooltips -- later we could load these from a file for i18n
2266
- var titles = {
1908
+ const titles = {
2267
1909
  '.logo': 'Go to Archive.org', // $$$ update after getting OL record
2268
1910
  '.zoom_in': 'Zoom in',
2269
1911
  '.zoom_out': 'Zoom out',
@@ -2279,8 +1921,6 @@ BookReader.prototype.initUIStrings = function() {
2279
1921
  '.full': 'Toggle fullscreen',
2280
1922
  '.book_left': 'Flip left',
2281
1923
  '.book_right': 'Flip right',
2282
- '.book_up': 'Page up',
2283
- '.book_down': 'Page down',
2284
1924
  '.play': 'Play',
2285
1925
  '.pause': 'Pause',
2286
1926
  '.BRdn': 'Show/hide nav bar', // Would have to keep updating on state change to have just "Hide nav bar"
@@ -2295,10 +1935,10 @@ BookReader.prototype.initUIStrings = function() {
2295
1935
  titles['.book_rightmost'] = 'First page';
2296
1936
  }
2297
1937
 
2298
- for (var icon in titles) {
1938
+ for (const icon in titles) {
2299
1939
  this.$(icon).prop('title', titles[icon]);
2300
1940
  }
2301
- }
1941
+ };
2302
1942
 
2303
1943
  /**
2304
1944
  * Reloads images. Useful when some images might have failed.
@@ -2306,7 +1946,7 @@ BookReader.prototype.initUIStrings = function() {
2306
1946
  BookReader.prototype.reloadImages = function() {
2307
1947
  this.refs.$brContainer.find('img').each(function(index, elem) {
2308
1948
  if (!elem.complete || elem.naturalHeight === 0) {
2309
- var src = elem.src;
1949
+ const src = elem.src;
2310
1950
  elem.src = '';
2311
1951
  setTimeout(function() {
2312
1952
  elem.src = src;
@@ -2320,16 +1960,16 @@ BookReader.prototype.reloadImages = function() {
2320
1960
  * @return {number}
2321
1961
  */
2322
1962
  BookReader.prototype.getFooterHeight = function() {
2323
- 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;
2324
1964
  if ($heightEl && this.refs.$BRfooter) {
2325
- var outerHeight = $heightEl.outerHeight();
2326
- var bottom = parseInt(this.refs.$BRfooter.css('bottom'));
1965
+ const outerHeight = $heightEl.outerHeight();
1966
+ const bottom = parseInt(this.refs.$BRfooter.css('bottom'));
2327
1967
  if (!isNaN(outerHeight) && !isNaN(bottom)) {
2328
1968
  return outerHeight + bottom;
2329
1969
  }
2330
1970
  }
2331
1971
  return 0;
2332
- }
1972
+ };
2333
1973
 
2334
1974
  // Basic Usage built-in Methods (can be overridden through options)
2335
1975
  // This implementation uses options.data value for populating BookReader
@@ -2339,10 +1979,11 @@ BookReader.prototype.getFooterHeight = function() {
2339
1979
  * @return {Object}
2340
1980
  */
2341
1981
  BookReader.prototype.paramsFromCurrent = function() {
2342
- var params = {};
1982
+ const params = {};
2343
1983
 
2344
- var index = this.currentIndex();
2345
- var pageNum = this._models.book.getPageNum(index);
1984
+ // Path params
1985
+ const index = this.currentIndex();
1986
+ const pageNum = this.book.getPageNum(index);
2346
1987
  if ((pageNum === 0) || pageNum) {
2347
1988
  params.page = pageNum;
2348
1989
  }
@@ -2350,10 +1991,17 @@ BookReader.prototype.paramsFromCurrent = function() {
2350
1991
  params.index = index;
2351
1992
  params.mode = this.mode;
2352
1993
 
1994
+ // Unused params
2353
1995
  // $$$ highlight
2354
1996
  // $$$ region
2355
1997
 
2356
- // search
1998
+ // Querystring params
1999
+ // View
2000
+ const fullscreenView = 'theater';
2001
+ if (this.isFullscreenActive) {
2002
+ params.view = fullscreenView;
2003
+ }
2004
+ // Search
2357
2005
  if (this.enableSearch) {
2358
2006
  params.search = this.searchTerm;
2359
2007
  }
@@ -2374,7 +2022,7 @@ BookReader.prototype.paramsFromCurrent = function() {
2374
2022
  * @return {Object}
2375
2023
  */
2376
2024
  BookReader.prototype.paramsFromFragment = function(fragment) {
2377
- var params = {};
2025
+ const params = {};
2378
2026
 
2379
2027
  // For backwards compatibility we allow an initial # character
2380
2028
  // (as from window.location.hash) but don't require it
@@ -2383,7 +2031,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2383
2031
  }
2384
2032
 
2385
2033
  // Simple #nn syntax
2386
- var oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
2034
+ const oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
2387
2035
  if ( !isNaN(oldStyleLeafNum) ) {
2388
2036
  params.index = oldStyleLeafNum;
2389
2037
 
@@ -2392,9 +2040,9 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2392
2040
  }
2393
2041
 
2394
2042
  // Split into key-value pairs
2395
- var urlArray = fragment.split('/');
2396
- var urlHash = {};
2397
- 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) {
2398
2046
  urlHash[urlArray[i]] = urlArray[i + 1];
2399
2047
  }
2400
2048
 
@@ -2424,7 +2072,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2424
2072
 
2425
2073
  // $$$ process /theme
2426
2074
  if (urlHash['theme'] != undefined) {
2427
- params.theme = urlHash['theme']
2075
+ params.theme = urlHash['theme'];
2428
2076
  }
2429
2077
  return params;
2430
2078
  };
@@ -2481,6 +2129,9 @@ BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
2481
2129
  /**
2482
2130
  * Create, update querystring from the params object
2483
2131
  *
2132
+ * Handles:
2133
+ * view=
2134
+ * q=
2484
2135
  * @param {Object} params
2485
2136
  * @param {string} currQueryString
2486
2137
  * @param {string} [urlMode]
@@ -2492,27 +2143,29 @@ BookReader.prototype.queryStringFromParams = function(
2492
2143
  urlMode = 'hash'
2493
2144
  ) {
2494
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
+
2495
2155
  if (params.search && urlMode === 'history') {
2496
- newParams.set('q', params.search)
2156
+ newParams.set('q', params.search);
2497
2157
  }
2498
2158
  // https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
2499
2159
  // Note: This method returns the query string without the question mark.
2500
2160
  const result = newParams.toString();
2501
2161
  return result ? '?' + result : '';
2502
- }
2162
+ };
2503
2163
 
2504
2164
  /**
2505
2165
  * Helper to select within instance's elements
2506
2166
  */
2507
2167
  BookReader.prototype.$ = function(selector) {
2508
2168
  return this.refs.$br.find(selector);
2509
- }
2510
-
2511
- /**
2512
- * Polyfill for deprecated method
2513
- */
2514
- jQuery.curCSS = function(element, prop, val) {
2515
- return jQuery(element).css(prop, val);
2516
2169
  };
2517
2170
 
2518
2171
  window.BookReader = BookReader;