@internetarchive/bookreader 5.0.0-4 → 5.0.0-40-a1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +75 -4
  3. package/.github/workflows/npm-publish.yml +2 -16
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +83 -323
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -0
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1623 -0
  10. package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
  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/voice.svg +1 -0
  16. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  17. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  18. package/BookReader/plugins/plugin.autoplay.js +1 -1
  19. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  20. package/BookReader/plugins/plugin.chapters.js +1 -1
  21. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  22. package/BookReader/plugins/plugin.iframe.js +1 -1
  23. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  24. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  25. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  26. package/BookReader/plugins/plugin.resume.js +1 -1
  27. package/BookReader/plugins/plugin.resume.js.map +1 -1
  28. package/BookReader/plugins/plugin.search.js +1 -1
  29. package/BookReader/plugins/plugin.search.js.map +1 -1
  30. package/BookReader/plugins/plugin.text_selection.js +1 -1
  31. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  32. package/BookReader/plugins/plugin.tts.js +1 -1
  33. package/BookReader/plugins/plugin.tts.js.map +1 -1
  34. package/BookReader/plugins/plugin.url.js +1 -1
  35. package/BookReader/plugins/plugin.url.js.map +1 -1
  36. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  37. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  38. package/BookReader/webcomponents-bundle.js +3 -0
  39. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  40. package/BookReader/webcomponents-bundle.js.map +1 -0
  41. package/BookReaderDemo/BookReaderDemo.css +14 -1
  42. package/BookReaderDemo/IADemoBr.js +120 -0
  43. package/BookReaderDemo/demo-advanced.html +1 -1
  44. package/BookReaderDemo/demo-autoplay.html +1 -0
  45. package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
  46. package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
  47. package/BookReaderDemo/demo-fullscreen.html +1 -0
  48. package/BookReaderDemo/demo-iiif.html +1 -0
  49. package/BookReaderDemo/demo-internetarchive.html +74 -17
  50. package/BookReaderDemo/demo-multiple.html +1 -0
  51. package/BookReaderDemo/demo-preview-pages.html +1 -0
  52. package/BookReaderDemo/demo-simple.html +1 -0
  53. package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
  54. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  55. package/BookReaderDemo/immersion-1up.html +1 -0
  56. package/BookReaderDemo/immersion-mode.html +1 -0
  57. package/BookReaderDemo/toggle_controls.html +1 -0
  58. package/BookReaderDemo/view_mode.html +1 -0
  59. package/BookReaderDemo/viewmode-cycle.html +1 -2
  60. package/CHANGELOG.md +166 -0
  61. package/README.md +14 -1
  62. package/babel.config.js +18 -0
  63. package/codecov.yml +6 -0
  64. package/index.html +3 -0
  65. package/jsconfig.json +19 -0
  66. package/package.json +62 -47
  67. package/renovate.json +43 -0
  68. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  69. package/src/BookNavigator/assets/button-base.js +9 -2
  70. package/src/BookNavigator/assets/ia-logo.js +17 -0
  71. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  72. package/src/BookNavigator/assets/icon_close.js +1 -1
  73. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  74. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  75. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  76. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  77. package/src/BookNavigator/book-navigator.js +556 -0
  78. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  79. package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
  80. package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
  81. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  82. package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
  83. package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
  84. package/src/BookNavigator/delete-modal-actions.js +1 -1
  85. package/src/BookNavigator/downloads/downloads-provider.js +23 -17
  86. package/src/BookNavigator/downloads/downloads.js +17 -25
  87. package/src/BookNavigator/search/a-search-result.js +3 -3
  88. package/src/BookNavigator/search/search-provider.js +57 -24
  89. package/src/BookNavigator/search/search-results.js +8 -20
  90. package/src/BookNavigator/sharing.js +27 -0
  91. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
  92. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
  93. package/src/BookNavigator/volumes/volumes-provider.js +114 -0
  94. package/src/BookNavigator/volumes/volumes.js +188 -0
  95. package/src/BookReader/DebugConsole.js +3 -3
  96. package/src/BookReader/DragScrollable.js +233 -0
  97. package/src/BookReader/Mode1Up.js +51 -351
  98. package/src/BookReader/Mode1UpLit.js +441 -0
  99. package/src/BookReader/Mode2Up.js +104 -71
  100. package/src/BookReader/ModeSmoothZoom.js +179 -0
  101. package/src/BookReader/ModeThumb.js +16 -8
  102. package/src/BookReader/Navbar/Navbar.js +2 -31
  103. package/src/BookReader/PageContainer.js +57 -6
  104. package/src/BookReader/ReduceSet.js +1 -1
  105. package/src/BookReader/Toolbar/Toolbar.js +7 -7
  106. package/src/BookReader/options.js +10 -0
  107. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  108. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  109. package/src/BookReader/utils.js +68 -13
  110. package/src/BookReader.js +375 -289
  111. package/src/assets/icons/close-circle-dark.svg +1 -0
  112. package/src/assets/icons/magnify-minus.svg +3 -7
  113. package/src/assets/icons/magnify-plus.svg +3 -7
  114. package/src/assets/icons/voice.svg +1 -0
  115. package/src/css/BookReader.scss +0 -12
  116. package/src/css/_BRComponent.scss +1 -1
  117. package/src/css/_BRmain.scss +19 -24
  118. package/src/css/_BRnav.scss +4 -26
  119. package/src/css/_BRpages.scss +35 -0
  120. package/src/css/_BRsearch.scss +11 -215
  121. package/src/css/_TextSelection.scss +14 -17
  122. package/src/css/_colorbox.scss +2 -2
  123. package/src/css/_controls.scss +16 -3
  124. package/src/css/_icons.scss +6 -0
  125. package/src/ia-bookreader/ia-bookreader.js +224 -0
  126. package/src/plugins/plugin.chapters.js +26 -33
  127. package/src/plugins/plugin.mobile_nav.js +11 -10
  128. package/src/plugins/plugin.resume.js +3 -3
  129. package/src/plugins/plugin.text_selection.js +26 -39
  130. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  131. package/src/plugins/search/plugin.search.js +106 -107
  132. package/src/plugins/search/view.js +50 -163
  133. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  134. package/src/plugins/tts/FestivalTTSEngine.js +12 -13
  135. package/src/plugins/tts/PageChunk.js +15 -21
  136. package/src/plugins/tts/PageChunkIterator.js +8 -12
  137. package/src/plugins/tts/WebTTSEngine.js +64 -68
  138. package/src/plugins/tts/plugin.tts.js +79 -108
  139. package/src/plugins/url/UrlPlugin.js +184 -0
  140. package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
  141. package/tests/e2e/README.md +37 -0
  142. package/tests/e2e/autoplay.test.js +2 -2
  143. package/tests/e2e/base.test.js +7 -7
  144. package/tests/e2e/helpers/base.js +8 -3
  145. package/tests/e2e/helpers/debug.js +1 -1
  146. package/tests/e2e/helpers/desktopSearch.js +14 -13
  147. package/tests/e2e/helpers/mobileSearch.js +3 -3
  148. package/tests/e2e/helpers/params.js +17 -0
  149. package/tests/e2e/models/Navigation.js +12 -3
  150. package/tests/e2e/rightToLeft.test.js +4 -5
  151. package/tests/e2e/viewmode.test.js +38 -33
  152. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
  153. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  154. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  155. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  156. package/tests/jest/BookReader/Mode1UpLit.test.js +88 -0
  157. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
  158. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  159. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  160. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  161. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -6
  162. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  163. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  164. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  165. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  166. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  167. package/tests/jest/BookReader/utils.test.js +136 -0
  168. package/tests/jest/BookReader.keyboard.test.js +190 -0
  169. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  170. package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
  171. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  172. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
  173. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
  174. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  175. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  176. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  177. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  178. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  179. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +24 -25
  180. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
  181. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
  182. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  183. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  184. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  185. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  186. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
  187. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  188. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  189. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  190. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  191. package/tests/{util → jest/util}/strings.test.js +1 -1
  192. package/tests/{utils.js → jest/utils.js} +38 -0
  193. package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
  194. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  195. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
  196. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
  197. package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
  198. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
  199. package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
  200. package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
  201. package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
  202. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
  203. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
  204. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
  205. package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
  206. package/webpack.config.js +10 -4
  207. package/.babelrc +0 -12
  208. package/.dependabot/config.yml +0 -6
  209. package/.testcaferc.json +0 -5
  210. package/BookReader/bookreader-component-bundle.js +0 -1450
  211. package/BookReader/bookreader-component-bundle.js.map +0 -1
  212. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  213. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  214. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  215. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  216. package/src/BookNavigator/BookModel.js +0 -14
  217. package/src/BookNavigator/BookNavigator.js +0 -435
  218. package/src/BookNavigator/assets/book-loader.js +0 -27
  219. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  220. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  221. package/src/ItemNavigator/ItemNavigator.js +0 -372
  222. package/src/ItemNavigator/providers/sharing.js +0 -29
  223. package/src/dragscrollable-br.js +0 -261
  224. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  225. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  226. package/tests/BookReader/Mode1Up.test.js +0 -164
  227. package/tests/BookReader/utils.test.js +0 -109
  228. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
package/src/BookReader.js CHANGED
@@ -27,7 +27,6 @@ import 'jquery-ui/ui/widget.js';
27
27
  import 'jquery-ui/ui/widgets/mouse.js';
28
28
  import 'jquery-ui-touch-punch';
29
29
 
30
- import './dragscrollable-br.js';
31
30
  import PACKAGE_JSON from '../package.json';
32
31
  import * as utils from './BookReader/utils.js';
33
32
  import { exposeOverrideable } from './BookReader/utils/classes.js';
@@ -179,7 +178,7 @@ BookReader.prototype.setup = function(options) {
179
178
  */
180
179
  this.firstIndex = null;
181
180
  this.lastDisplayableIndex2up = null;
182
- this.isFullscreenActive = false;
181
+ this.isFullscreenActive = options.startFullscreen || false;
183
182
  this.lastScroll = null;
184
183
 
185
184
  this.showLogo = options.showLogo;
@@ -265,8 +264,52 @@ BookReader.prototype.setup = function(options) {
265
264
  useSrcSet: this.options.useSrcSet,
266
265
  reduceSet: this.reduceSet,
267
266
  });
267
+
268
+ /**
269
+ * Flag if BookReader has "focus" for keyboard shortcuts
270
+ * Initially true, set to false when:
271
+ * - BookReader scrolled out of view
272
+ * Set to true when:
273
+ * - BookReader scrolled into view
274
+ */
275
+ this.hasKeyFocus = true;
276
+ };
277
+
278
+ /**
279
+ * Get all the HTML Elements that are being/can be rendered.
280
+ * Includes cached elements which might be rendered again.
281
+ */
282
+ BookReader.prototype.getActivePageContainerElements = function() {
283
+ let containerEls = Object.values(this._modes.mode2Up.pageContainers).map(pc => pc.$container[0])
284
+ .concat(Object.values(this._modes.mode1Up.mode1UpLit.pageContainerCache).map(pc => pc.$container[0]));
285
+ if (this.mode == this.constModeThumb) {
286
+ containerEls = containerEls.concat(this.$('.BRpagecontainer').toArray());
287
+ }
288
+ return containerEls;
289
+ };
290
+
291
+ /**
292
+ * Get the HTML Elements for the rendered page. Note there can be more than one, since
293
+ * (at least as of writing) different modes can maintain different caches.
294
+ * @param {PageIndex} pageIndex
295
+ */
296
+ BookReader.prototype.getActivePageContainerElementsForIndex = function(pageIndex) {
297
+ return [
298
+ this._modes.mode2Up.pageContainers[pageIndex]?.$container?.[0],
299
+ this._modes.mode1Up.mode1UpLit.pageContainerCache[pageIndex]?.$container?.[0],
300
+ ...(this.mode == this.constModeThumb ? this.$(`.pagediv${pageIndex}`).toArray() : [])
301
+ ].filter(x => x);
268
302
  };
269
303
 
304
+ Object.defineProperty(BookReader.prototype, 'activeMode', {
305
+ /** @return {Mode1Up | Mode2Up | ModeThumb} */
306
+ get() { return {
307
+ 1: this._modes.mode1Up,
308
+ 2: this._modes.mode2Up,
309
+ 3: this._modes.modeThumb,
310
+ }[this.mode]; },
311
+ });
312
+
270
313
  /** @deprecated unused outside Mode2Up */
271
314
  Object.defineProperty(BookReader.prototype, 'leafEdgeL', {
272
315
  get() { return this._modes.mode2Up.leafEdgeL; },
@@ -290,15 +333,15 @@ BookReader.util = utils;
290
333
  * @private
291
334
  */
292
335
  BookReader.prototype.extendParams = function(params, newParams) {
293
- var modifiedNewParams = $.extend({}, newParams);
336
+ const modifiedNewParams = $.extend({}, newParams);
294
337
  if ('undefined' != typeof(modifiedNewParams.page)) {
295
- var pageIndex = this._models.book.parsePageString(modifiedNewParams.page);
338
+ const pageIndex = this._models.book.parsePageString(modifiedNewParams.page);
296
339
  if (!isNaN(pageIndex))
297
340
  modifiedNewParams.index = pageIndex;
298
341
  delete modifiedNewParams.page;
299
342
  }
300
343
  $.extend(params, modifiedNewParams);
301
- }
344
+ };
302
345
 
303
346
  /**
304
347
  * Parses params from from various initialization contexts (url, cookie, options)
@@ -306,7 +349,7 @@ BookReader.prototype.extendParams = function(params, newParams) {
306
349
  * @return {object} the parsed params
307
350
  */
308
351
  BookReader.prototype.initParams = function() {
309
- var params = {};
352
+ const params = {};
310
353
  // Flag initializing for updateFromParams()
311
354
  params.init = true;
312
355
 
@@ -355,7 +398,7 @@ BookReader.prototype.initParams = function() {
355
398
  // Check for URL plugin
356
399
  if (this.options.enableUrlPlugin) {
357
400
  // Params explicitly set in URL take precedence over all other methods
358
- var urlParams = this.paramsFromFragment(this.urlReadFragment());
401
+ let urlParams = this.paramsFromFragment(this.urlReadFragment());
359
402
 
360
403
  // Get params if hash fragment available with 'history' urlMode
361
404
  const hasHashURL = !Object.keys(urlParams).length && this.urlReadHashFragment();
@@ -377,7 +420,7 @@ BookReader.prototype.initParams = function() {
377
420
  // Check for Search plugin
378
421
  if (this.options.enableSearch) {
379
422
  // Go to first result only if no default or URL page
380
- this.goToFirstResult = !params.pageFound
423
+ this.options.goToFirstResult = !params.pageFound;
381
424
 
382
425
  // If initialSearchTerm not set
383
426
  if (!this.options.initialSearchTerm) {
@@ -389,7 +432,7 @@ BookReader.prototype.initParams = function() {
389
432
  } else {
390
433
  // If we have a query string: q=[term]
391
434
  const searchParams = new URLSearchParams(this.readQueryString());
392
- const searchTerm = searchParams.get('q')
435
+ const searchTerm = searchParams.get('q');
393
436
  if (searchTerm) {
394
437
  this.options.initialSearchTerm = utils.decodeURIComponentPlus(searchTerm);
395
438
  }
@@ -401,21 +444,21 @@ BookReader.prototype.initParams = function() {
401
444
  this.suppressFragmentChange = !params.fragmentChange;
402
445
 
403
446
  return params;
404
- }
447
+ };
405
448
 
406
449
  /**
407
450
  * Allow mocking of window.location.search
408
451
  */
409
452
  BookReader.prototype.getLocationSearch = function () {
410
453
  return window.location.search;
411
- }
454
+ };
412
455
 
413
456
  /**
414
457
  * Allow mocking of window.location.hash
415
458
  */
416
459
  BookReader.prototype.getLocationHash = function () {
417
460
  return window.location.hash;
418
- }
461
+ };
419
462
 
420
463
  /**
421
464
  * Return URL or fragment querystring
@@ -428,7 +471,7 @@ BookReader.prototype.readQueryString = function() {
428
471
  const hash = this.getLocationHash();
429
472
  const found = hash.search(/\?\w+=/);
430
473
  return found > -1 ? hash.slice(found) : '';
431
- }
474
+ };
432
475
 
433
476
  /**
434
477
  * Determines the initial mode for starting if a mode is not already
@@ -438,12 +481,11 @@ BookReader.prototype.readQueryString = function() {
438
481
  */
439
482
  BookReader.prototype.getInitialMode = function(params) {
440
483
  // Use params or browser width to set view mode
441
- var windowWidth = $(window).width();
442
- var nextMode;
484
+ const windowWidth = $(window).width();
485
+ let nextMode;
443
486
  if ('undefined' != typeof(params.mode)) {
444
487
  nextMode = params.mode;
445
488
  } else if (this.ui == 'full'
446
- && this.enableMobileNav
447
489
  && this.isFullscreenActive
448
490
  && windowWidth <= this.onePageMinBreakpoint
449
491
  ) {
@@ -467,7 +509,7 @@ BookReader.prototype.init = function() {
467
509
  this.init.initComplete = false;
468
510
  this.pageScale = this.reduce; // preserve current reduce
469
511
 
470
- var params = this.initParams();
512
+ const params = this.initParams();
471
513
 
472
514
  this.firstIndex = params.index ? params.index : 0;
473
515
 
@@ -497,15 +539,12 @@ BookReader.prototype.init = function() {
497
539
  // Explicitly ensure this.mode exists for initNavbar() below
498
540
  this.mode = params.mode;
499
541
 
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
- }
542
+ // Display Navigation
543
+ if (this.options.showToolbar) {
544
+ this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
545
+ }
546
+ if (this.options.showNavbar) { // default navigation
547
+ this.initNavbar();
509
548
  }
510
549
 
511
550
  // Switch navbar controls on mobile/desktop
@@ -521,17 +560,17 @@ BookReader.prototype.init = function() {
521
560
  this.setupKeyListeners();
522
561
 
523
562
  this.lastScroll = (new Date().getTime());
524
- this.refs.$brContainer.bind('scroll', this, function(e) {
563
+ this.refs.$brContainer.on('scroll', this, function(e) {
525
564
  // Note, this scroll event fires for both user, and js generated calls
526
565
  // It is functioning in some cases as the primary triggerer for rendering
527
566
  e.data.lastScroll = (new Date().getTime());
528
- if (e.data.constMode2up != e.data.mode) {
567
+ if (e.data.constModeThumb == e.data.mode) {
529
568
  e.data.drawLeafsThrottled();
530
569
  }
531
570
  });
532
571
 
533
572
  if (this.options.autoResize) {
534
- $(window).bind('resize', this, function(e) {
573
+ $(window).on('resize', this, function(e) {
535
574
  e.data.resize();
536
575
  });
537
576
  $(window).on("orientationchange", this, function(e) {
@@ -548,15 +587,17 @@ BookReader.prototype.init = function() {
548
587
  this.suppressFragmentChange = false;
549
588
  }
550
589
 
590
+ if (this.options.startFullscreen) {
591
+ this.enterFullscreen(true);
592
+ }
593
+
551
594
  this.init.initComplete = true;
552
595
  this.trigger(BookReader.eventNames.PostInit);
553
596
 
554
597
  // Must be called after this.init.initComplete set to true to allow
555
598
  // BookReader.prototype.resize to run.
556
- if (this.options.startFullscreen) {
557
- this.toggleFullscreen();
558
- }
559
- }
599
+
600
+ };
560
601
 
561
602
  /**
562
603
  * @param {EVENTS} name
@@ -564,7 +605,6 @@ BookReader.prototype.init = function() {
564
605
  */
565
606
  BookReader.prototype.trigger = function(name, props = this) {
566
607
  const eventName = 'BookReader:' + name;
567
- $(document).trigger(eventName, props);
568
608
 
569
609
  utils.polyfillCustomEvent(window);
570
610
  window.dispatchEvent(new CustomEvent(eventName, {
@@ -572,14 +612,15 @@ BookReader.prototype.trigger = function(name, props = this) {
572
612
  composed: true,
573
613
  detail: { props },
574
614
  }));
615
+ $(document).trigger(eventName, props);
575
616
  };
576
617
 
577
618
  BookReader.prototype.bind = function(name, callback) {
578
- $(document).bind('BookReader:' + name, callback);
619
+ $(document).on('BookReader:' + name, callback);
579
620
  };
580
621
 
581
622
  BookReader.prototype.unbind = function(name, callback) {
582
- $(document).unbind('BookReader:' + name, callback);
623
+ $(document).off('BookReader:' + name, callback);
583
624
  };
584
625
 
585
626
  /**
@@ -597,11 +638,9 @@ BookReader.prototype.resize = function() {
597
638
  if (this.onePage.autofit != 'none') {
598
639
  this.resizePageView1up();
599
640
  this.centerPageView();
600
- if (this.enableSearch) this.updateSearchHilites(); //deletes highlights but does not call remove()
601
641
  } else {
602
642
  this.centerPageView();
603
643
  this.displayedIndices = [];
604
- if (this.enableSearch) this.updateSearchHilites(); //deletes highlights but does not call remove()
605
644
  this.drawLeafsThrottled();
606
645
  }
607
646
  } else if (this.constModeThumb == this.mode) {
@@ -614,8 +653,8 @@ BookReader.prototype.resize = function() {
614
653
  } else {
615
654
  // used when zoomed in
616
655
  // Re-center if the scrollbars have disappeared
617
- var center = this.twoPageGetViewCenter();
618
- var doRecenter = false;
656
+ const center = this.twoPageGetViewCenter();
657
+ let doRecenter = false;
619
658
  if (this.twoPage.totalWidth < this.refs.$brContainer.prop('clientWidth')) {
620
659
  center.percentageX = 0.5;
621
660
  doRecenter = true;
@@ -633,89 +672,124 @@ BookReader.prototype.resize = function() {
633
672
  };
634
673
 
635
674
  /**
636
- * Binds keyboard event listeners
637
- */
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();
675
+ * Binds keyboard and keyboard focus event listeners
676
+ */
677
+ BookReader.prototype.setupKeyListeners = function () {
678
+
679
+ // Keyboard focus by BookReader in viewport
680
+ //
681
+ // Intersection observer and callback sets BookReader keyboard
682
+ // "focus" flag off when the BookReader is not in the viewport.
683
+ if (window.IntersectionObserver) {
684
+ const observer = new IntersectionObserver((entries) => {
685
+ entries.forEach((entry) => {
686
+ if (entry.intersectionRatio === 0) {
687
+ this.hasKeyFocus = false;
688
+ } else {
689
+ this.hasKeyFocus = true;
677
690
  }
678
- break;
679
- case KEY_END:
691
+ });
692
+ }, {
693
+ root: null,
694
+ rootMargin: '0px',
695
+ threshold: [0, 0.05, 1],
696
+ });
697
+ observer.observe(this.refs.$br[0]);
698
+ }
699
+
700
+ // Keyboard listeners
701
+ document.addEventListener('keydown', (e) => {
702
+
703
+ // Ignore if BookReader "focus" flag not set
704
+ if (!this.hasKeyFocus) {
705
+ return;
706
+ }
707
+
708
+ // Ignore if modifiers are active.
709
+ if (e.getModifierState('Control') ||
710
+ e.getModifierState('Alt') ||
711
+ e.getModifierState('Meta') ||
712
+ e.getModifierState('Win') /* hack for IE */) {
713
+ return;
714
+ }
715
+
716
+ // Ignore in input elements
717
+ if (utils.isInputActive()) {
718
+ return;
719
+ }
720
+
721
+ // KeyboardEvent code values:
722
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
723
+ switch (e.key) {
724
+
725
+ // Page navigation
726
+ case "Home":
727
+ e.preventDefault();
728
+ this.first();
729
+ break;
730
+ case "End":
731
+ e.preventDefault();
732
+ this.last();
733
+ break;
734
+ case "ArrowDown":
735
+ case "PageDown":
736
+ case "Down": // hack for IE and old Gecko
737
+ // In 1up and thumb mode page scrolling handled by browser
738
+ if (this.constMode2up === this.mode) {
680
739
  e.preventDefault();
681
- self.last();
682
- break;
683
- case KEY_HOME:
740
+ this.next();
741
+ }
742
+ break;
743
+ case "ArrowUp":
744
+ case "PageUp":
745
+ case "Up": // hack for IE and old Gecko
746
+ // In 1up and thumb mode page scrolling handled by browser
747
+ if (this.constMode2up === this.mode) {
684
748
  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:
749
+ this.prev();
750
+ }
751
+ break;
752
+ case "ArrowLeft":
753
+ case "Left": // hack for IE and old Gecko
754
+ // No y-scrolling in thumb mode
755
+ if (this.constModeThumb != this.mode) {
702
756
  e.preventDefault();
703
- self.zoom(-1);
704
- break;
705
- case KEY_EQUAL:
706
- case KEY_EQUAL_F:
707
- case KEY_NUMPAD_ADD:
757
+ this.left();
758
+ }
759
+ break;
760
+ case "ArrowRight":
761
+ case "Right": // hack for IE and old Gecko
762
+ // No y-scrolling in thumb mode
763
+ if (this.constModeThumb != this.mode) {
708
764
  e.preventDefault();
709
- self.zoom(+1);
710
- break;
765
+ this.right();
711
766
  }
767
+ break;
768
+ // Zoom
769
+ case '-':
770
+ case 'Subtract':
771
+ e.preventDefault();
772
+ this.zoom(-1);
773
+ break;
774
+ case '+':
775
+ case '=':
776
+ case 'Add':
777
+ e.preventDefault();
778
+ this.zoom(1);
779
+ break;
780
+ // Fullscreen
781
+ case 'F':
782
+ case 'f':
783
+ e.preventDefault();
784
+ this.toggleFullscreen();
785
+ break;
712
786
  }
713
787
  });
714
788
  };
715
789
 
716
790
  BookReader.prototype.drawLeafs = function() {
717
791
  if (this.constMode1up == this.mode) {
718
- this.drawLeafsOnePage();
792
+ // Not needed for Mode1Up anymore
719
793
  } else if (this.constModeThumb == this.mode) {
720
794
  this.drawLeafsThumbnail();
721
795
  } else {
@@ -742,8 +816,8 @@ BookReader.prototype.bindGestures = function(jElement) {
742
816
  // when you move the book with one finger and then add another
743
817
  // finger to pinch. Gestures are aware of scroll state.
744
818
 
745
- var self = this;
746
- var numTouches = 1;
819
+ const self = this;
820
+ let numTouches = 1;
747
821
 
748
822
  jElement.unbind('touchmove').bind('touchmove', function(e) {
749
823
  if (e.originalEvent.cancelable) numTouches = e.originalEvent.touches.length;
@@ -794,29 +868,11 @@ BookReader.prototype.drawLeafsThrottled = utils.throttle(
794
868
  * @param {number} direction Pass 1 to zoom in, anything else to zoom out
795
869
  */
796
870
  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
871
+ if (direction == 1) {
872
+ this.activeMode.zoom('in');
873
+ } else {
874
+ this.activeMode.zoom('out');
818
875
  }
819
-
820
876
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
821
877
  return;
822
878
  };
@@ -842,11 +898,11 @@ BookReader.prototype.resizeBRcontainer = function(animate) {
842
898
  bottom: this.getFooterHeight()
843
899
  });
844
900
  }
845
- }
901
+ };
846
902
 
847
903
  BookReader.prototype.centerPageView = function() {
848
- var scrollWidth = this.refs.$brContainer.prop('scrollWidth');
849
- var clientWidth = this.refs.$brContainer.prop('clientWidth');
904
+ const scrollWidth = this.refs.$brContainer.prop('scrollWidth');
905
+ const clientWidth = this.refs.$brContainer.prop('clientWidth');
850
906
  if (scrollWidth > clientWidth) {
851
907
  this.refs.$brContainer.prop('scrollLeft', (scrollWidth - clientWidth) / 2);
852
908
  }
@@ -934,7 +990,7 @@ BookReader.prototype._reduceSort = (a, b) => a.reduce - b.reduce;
934
990
  * @return {boolean} Returns true if page could be found, false otherwise.
935
991
  */
936
992
  BookReader.prototype.jumpToPage = function(pageNum) {
937
- var pageIndex = this._models.book.parsePageString(pageNum);
993
+ const pageIndex = this._models.book.parsePageString(pageNum);
938
994
 
939
995
  if ('undefined' != typeof(pageIndex)) {
940
996
  this.jumpToIndex(pageIndex);
@@ -954,7 +1010,7 @@ BookReader.prototype._isIndexDisplayed = function(index) {
954
1010
  return this.constMode1up == this.mode ? this.displayedIndices.slice(1, -1).includes(index) :
955
1011
  this.displayedIndices ? this.displayedIndices.includes(index) :
956
1012
  this.currentIndex() == index;
957
- }
1013
+ };
958
1014
 
959
1015
  /**
960
1016
  * Changes the current page
@@ -996,7 +1052,7 @@ BookReader.prototype.getPrevReadMode = function(mode) {
996
1052
  // Initial thumb, return 1up
997
1053
  return BookReader.constMode1up;
998
1054
  }
999
- }
1055
+ };
1000
1056
 
1001
1057
  /**
1002
1058
  * Switches the mode (eg 1up 2up thumb)
@@ -1024,10 +1080,13 @@ BookReader.prototype.switchMode = function(
1024
1080
  }
1025
1081
 
1026
1082
  this.trigger(BookReader.eventNames.stop);
1027
- if (this.enableSearch) this.removeSearchHilites();
1028
1083
 
1029
1084
  this.prevReadMode = this.getPrevReadMode(this.mode);
1030
1085
 
1086
+ if (this.mode != mode) {
1087
+ this.activeMode.unprepare?.();
1088
+ }
1089
+
1031
1090
  this.mode = mode;
1032
1091
 
1033
1092
  // reinstate scale if moving from thumbnail view
@@ -1040,8 +1099,6 @@ BookReader.prototype.switchMode = function(
1040
1099
 
1041
1100
  // XXX maybe better to preserve zoom in each mode
1042
1101
  if (this.constMode1up == mode) {
1043
- this.onePageCalculateReductionFactors();
1044
- this.reduce = this.quantizeReduce(this.reduce, this.onePage.reductionFactors);
1045
1102
  this.prepareOnePageView();
1046
1103
  } else if (this.constModeThumb == mode) {
1047
1104
  this.reduce = this.quantizeReduce(this.reduce, this.reductionFactors);
@@ -1062,14 +1119,14 @@ BookReader.prototype.switchMode = function(
1062
1119
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1063
1120
  this.trigger(BookReader.eventNames.fragmentChange);
1064
1121
  }
1065
- var eventName = mode + 'PageViewSelected';
1122
+ const eventName = mode + 'PageViewSelected';
1066
1123
  this.trigger(BookReader.eventNames[eventName]);
1067
1124
 
1068
1125
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1069
1126
  };
1070
1127
 
1071
1128
  BookReader.prototype.updateBrClasses = function() {
1072
- var modeToClass = {};
1129
+ const modeToClass = {};
1073
1130
  modeToClass[this.constMode1up] = 'BRmode1up';
1074
1131
  modeToClass[this.constMode2up] = 'BRmode2Up';
1075
1132
  modeToClass[this.constModeThumb] = 'BRmodeThumb';
@@ -1095,11 +1152,11 @@ BookReader.prototype.isFullscreen = function() {
1095
1152
  * Toggles fullscreen
1096
1153
  * @param { boolean } bindKeyboardControls
1097
1154
  */
1098
- BookReader.prototype.toggleFullscreen = function(bindKeyboardControls = true) {
1155
+ BookReader.prototype.toggleFullscreen = async function(bindKeyboardControls = true) {
1099
1156
  if (this.isFullscreen()) {
1100
- this.exitFullScreen();
1157
+ await this.exitFullScreen();
1101
1158
  } else {
1102
- this.enterFullscreen(bindKeyboardControls);
1159
+ await this.enterFullscreen(bindKeyboardControls);
1103
1160
  }
1104
1161
  };
1105
1162
 
@@ -1111,7 +1168,7 @@ BookReader.prototype.toggleFullscreen = function(bindKeyboardControls = true) {
1111
1168
  * - fires custom event
1112
1169
  * @param { boolean } bindKeyboardControls
1113
1170
  */
1114
- BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1171
+ BookReader.prototype.enterFullscreen = async function(bindKeyboardControls = true) {
1115
1172
  const currentIndex = this.currentIndex();
1116
1173
  this.refs.$brContainer.css('opacity', 0);
1117
1174
 
@@ -1119,7 +1176,7 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1119
1176
  this._fullscreenCloseHandler = (e) => {
1120
1177
  if (e.keyCode === 27) this.toggleFullscreen();
1121
1178
  };
1122
- $(document).keyup(this._fullscreenCloseHandler);
1179
+ $(document).on("keyup", this._fullscreenCloseHandler);
1123
1180
  }
1124
1181
 
1125
1182
  const windowWidth = $(window).width();
@@ -1128,14 +1185,30 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1128
1185
  }
1129
1186
 
1130
1187
  this.isFullscreenActive = true;
1131
-
1132
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear',() => {
1133
- this.resize();
1134
- this.jumpToIndex(currentIndex);
1135
- });
1188
+ // prioritize class updates so CSS can propagate
1189
+ this.updateBrClasses();
1190
+ this.animating = true;
1191
+ await new Promise(res => this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', res));
1192
+ if (this.activeMode instanceof Mode1Up) {
1193
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this._models.book.getPage(currentIndex));
1194
+ // Need the new scale to be applied before calling jumpToIndex
1195
+ this.activeMode.mode1UpLit.requestUpdate();
1196
+ await this.activeMode.mode1UpLit.updateComplete;
1197
+ }
1198
+ this.jumpToIndex(currentIndex);
1199
+ this.animating = false;
1136
1200
 
1137
1201
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1202
+ // Add "?view=theater"
1203
+ this.trigger(BookReader.eventNames.fragmentChange);
1204
+ // trigger event here, so that animations,
1205
+ // class updates happen before book-nav relays to web components
1138
1206
  this.trigger(BookReader.eventNames.fullscreenToggled);
1207
+
1208
+ setTimeout(() => {
1209
+ // resize book after all events & css updates
1210
+ this.resize();
1211
+ }, 0);
1139
1212
  };
1140
1213
 
1141
1214
  /**
@@ -1145,12 +1218,12 @@ BookReader.prototype.enterFullscreen = function(bindKeyboardControls = true) {
1145
1218
  * - fires custom event
1146
1219
  * @param { boolean } bindKeyboardControls
1147
1220
  */
1148
- BookReader.prototype.exitFullScreen = function() {
1221
+ BookReader.prototype.exitFullScreen = async function () {
1149
1222
  this.refs.$brContainer.css('opacity', 0);
1150
1223
 
1151
- $(document).unbind('keyup', this._fullscreenCloseHandler);
1224
+ $(document).off('keyup', this._fullscreenCloseHandler);
1152
1225
 
1153
- var windowWidth = $(window).width();
1226
+ const windowWidth = $(window).width();
1154
1227
 
1155
1228
  const canShow2up = this.options.controls.twoPage.visible;
1156
1229
  if (canShow2up && (windowWidth <= this.onePageMinBreakpoint)) {
@@ -1158,13 +1231,26 @@ BookReader.prototype.exitFullScreen = function() {
1158
1231
  }
1159
1232
 
1160
1233
  this.isFullscreenActive = false;
1234
+ // Trigger fullscreen event immediately
1235
+ // so that book-nav can relay to web components
1236
+ this.trigger(BookReader.eventNames.fullscreenToggled);
1237
+
1161
1238
  this.updateBrClasses();
1239
+ this.animating = true;
1240
+ await new Promise((res => this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', res)));
1241
+ this.resize();
1242
+
1243
+ if (this.activeMode instanceof Mode1Up) {
1244
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this._models.book.getPage(this.currentIndex()));
1245
+ this.activeMode.mode1UpLit.requestUpdate();
1246
+ await this.activeMode.mode1UpLit.updateComplete;
1247
+ }
1248
+
1249
+ this.animating = false;
1162
1250
 
1163
- this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', () => {
1164
- this.resize();
1165
- });
1166
1251
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1167
- this.trigger(BookReader.eventNames.fullscreenToggled);
1252
+ // Remove "?view=theater"
1253
+ this.trigger(BookReader.eventNames.fragmentChange);
1168
1254
  };
1169
1255
 
1170
1256
  /**
@@ -1195,11 +1281,9 @@ BookReader.prototype.updateFirstIndex = function(
1195
1281
  index,
1196
1282
  { suppressFragmentChange = false } = {}
1197
1283
  ) {
1198
- // Called multiple times when defaults contains "mode/1up",
1199
- // including after init(). Skip fragment change if no index change
1200
- if (this.firstIndex === index) {
1201
- suppressFragmentChange = true;
1202
- }
1284
+ // If there's no change, do nothing
1285
+ if (this.firstIndex === index) return;
1286
+
1203
1287
  this.firstIndex = index;
1204
1288
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1205
1289
  this.trigger(BookReader.eventNames.fragmentChange);
@@ -1364,35 +1448,14 @@ BookReader.prototype.pruneUnusedImgs = function() {
1364
1448
  BookReader.prototype.prepareOnePageView = Mode1Up.prototype.prepare;
1365
1449
  exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'prepare', 'prepareOnePageView');
1366
1450
  /** @deprecated not used outside BookReader */
1367
- BookReader.prototype.drawLeafsOnePage = Mode1Up.prototype.drawLeafs;
1368
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'drawLeafs', 'drawLeafsOnePage');
1369
- /** @deprecated not used outside BookReader */
1370
1451
  BookReader.prototype.zoom1up = Mode1Up.prototype.zoom;
1371
1452
  exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'zoom', 'zoom1up');
1372
- /** @deprecated not used outside Mode1Up */
1373
- BookReader.prototype.onePageGetAutofitWidth = Mode1Up.prototype.getAutofitWidth;
1374
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitWidth', 'onePageGetAutofitWidth');
1375
- /** @deprecated not used outside Mode1Up, BookReader */
1376
- BookReader.prototype.onePageGetAutofitHeight = Mode1Up.prototype.getAutofitHeight;
1377
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getAutofitHeight', 'onePageGetAutofitHeight');
1378
- /** @deprecated not used outside Mode1Up, BookReader */
1379
- BookReader.prototype.onePageGetPageTop = Mode1Up.prototype.getPageTop;
1380
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'getPageTop', 'onePageGetPageTop');
1381
- /** @deprecated not used outside Mode1Up, BookReader */
1382
- BookReader.prototype.onePageCalculateReductionFactors = Mode1Up.prototype.calculateReductionFactors;
1383
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateReductionFactors', 'onePageCalculateReductionFactors');
1384
1453
  /** @deprecated not used outside Mode1Up, BookReader */
1385
1454
  BookReader.prototype.resizePageView1up = Mode1Up.prototype.resizePageView;
1386
1455
  exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'resizePageView', 'resizePageView1up');
1387
1456
  /** @deprecated not used outside Mode1Up */
1388
1457
  BookReader.prototype.onePageCalculateViewDimensions = Mode1Up.prototype.calculateViewDimensions;
1389
1458
  exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateViewDimensions', 'onePageCalculateViewDimensions');
1390
- /** @deprecated not used outside Mode1Up */
1391
- BookReader.prototype.centerX1up = Mode1Up.prototype.centerX;
1392
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerX', 'centerX1up');
1393
- /** @deprecated not used outside Mode1Up */
1394
- BookReader.prototype.centerY1up = Mode1Up.prototype.centerY;
1395
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'centerY', 'centerY1up');
1396
1459
 
1397
1460
  /************************/
1398
1461
  /** Mode2Up extensions **/
@@ -1409,9 +1472,6 @@ exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipFwdToIndex', 'flipFwdTo
1409
1472
  BookReader.prototype.setHilightCss2UP = Mode2Up.prototype.setHilightCss;
1410
1473
  exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setHilightCss', 'setHilightCss2UP');
1411
1474
  /** @deprecated not used outside Mode2Up */
1412
- BookReader.prototype.setClickHandler2UP = Mode2Up.prototype.setClickHandler;
1413
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setClickHandler', 'setClickHandler2UP');
1414
- /** @deprecated not used outside Mode2Up */
1415
1475
  BookReader.prototype.drawLeafsTwoPage = Mode2Up.prototype.drawLeafs;
1416
1476
  exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'drawLeafs', 'drawLeafsTwoPage');
1417
1477
  /** @deprecated not used outside BookReader */
@@ -1444,9 +1504,6 @@ exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipLeftToRight', 'flipLeft
1444
1504
  /** @deprecated unused outside BookReader, Mode2Up */
1445
1505
  BookReader.prototype.flipRightToLeft = Mode2Up.prototype.flipRightToLeft;
1446
1506
  exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipRightToLeft', 'flipRightToLeft');
1447
- /** @deprecated unused outside Mode2Up */
1448
- BookReader.prototype.setMouseHandlers2UP = Mode2Up.prototype.setMouseHandlers;
1449
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setMouseHandlers', 'setMouseHandlers2UP');
1450
1507
  /** @deprecated unused outside BookReader, Mode2Up */
1451
1508
  BookReader.prototype.prepareFlipLeftToRight = Mode2Up.prototype.prepareFlipLeftToRight;
1452
1509
  exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipLeftToRight', 'prepareFlipLeftToRight');
@@ -1527,15 +1584,6 @@ BookReader.prototype.stopFlipAnimations = function() {
1527
1584
  });
1528
1585
  };
1529
1586
 
1530
- /**
1531
- * Returns true if keyboard navigation should be disabled for the event
1532
- * @param {Event}
1533
- * @return {boolean}
1534
- */
1535
- BookReader.prototype.keyboardNavigationIsDisabled = function(event) {
1536
- return event.target.tagName == "INPUT";
1537
- };
1538
-
1539
1587
  /**
1540
1588
  * @template TClass extends { br: BookReader }
1541
1589
  * Helper method to expose a method onto BookReader from a composed class.
@@ -1566,9 +1614,6 @@ BookReader.prototype.updateViewModeButton = Navbar.prototype.updateViewModeButto
1566
1614
  exposeOverrideableMethod(Navbar, '_components.navbar', 'updateViewModeButton');
1567
1615
  BookReader.prototype.getNavPageNumString = Navbar.prototype.getNavPageNumString;
1568
1616
  exposeOverrideableMethod(Navbar, '_components.navbar', 'getNavPageNumString');
1569
- /** @deprecated */
1570
- BookReader.prototype.initEmbedNavbar = Navbar.prototype.initEmbed;
1571
- exposeOverrideableMethod(Navbar, '_components.navbar', 'initEmbed', 'initEmbedNavbar');
1572
1617
  /** @deprecated unused */
1573
1618
  BookReader.prototype.getNavPageNumHtml = getNavPageNumHtml;
1574
1619
  /** @deprecated unused outside this file */
@@ -1663,7 +1708,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1663
1708
  },
1664
1709
  full: () => {
1665
1710
  if (this.ui == 'embed') {
1666
- var url = this.$('.BRembedreturn a').attr('href');
1711
+ const url = this.$('.BRembedreturn a').attr('href');
1667
1712
  window.open(url);
1668
1713
  } else {
1669
1714
  this.toggleFullscreen();
@@ -1677,17 +1722,17 @@ BookReader.prototype.bindNavigationHandlers = function() {
1677
1722
 
1678
1723
  for (const control in navigationControls) {
1679
1724
  jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
1680
- navigationControls[control]()
1725
+ navigationControls[control]();
1681
1726
  return false;
1682
1727
  });
1683
1728
  }
1684
1729
 
1685
- var $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1686
- var $brNavCntlTopEl = this.$('.BRnavCntlTop');
1730
+ const $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1731
+ const $brNavCntlTopEl = this.$('.BRnavCntlTop');
1687
1732
 
1688
1733
  this.$('.BRnavCntl').click(
1689
1734
  function() {
1690
- var promises = [];
1735
+ const promises = [];
1691
1736
  // TODO don't use magic constants
1692
1737
  // TODO move this to a function
1693
1738
  if ($brNavCntlBtmEl.hasClass('BRdn')) {
@@ -1707,7 +1752,7 @@ BookReader.prototype.bindNavigationHandlers = function() {
1707
1752
  $brNavCntlBtmEl.addClass('BRdn').removeClass('BRup');
1708
1753
  $brNavCntlTopEl.addClass('BRup').removeClass('BRdn');
1709
1754
  self.$('.BRnavCntlBtm.BRnavCntl').animate({height:'30px'});
1710
- self.$('.BRvavCntl').animate({opacity:1})
1755
+ self.$('.BRvavCntl').animate({opacity:1});
1711
1756
  }
1712
1757
  $.when.apply($, promises).done(function() {
1713
1758
  // Only do full resize in auto mode and need to recalc. size
@@ -1725,24 +1770,28 @@ BookReader.prototype.bindNavigationHandlers = function() {
1725
1770
  });
1726
1771
  }
1727
1772
  );
1728
- $brNavCntlBtmEl.mouseover(function() {
1729
- if ($(this).hasClass('BRup')) {
1730
- self.$('.BRnavCntl').animate({opacity:1},250);
1731
- }
1732
- }).mouseleave(function() {
1733
- if ($(this).hasClass('BRup')) {
1734
- self.$('.BRnavCntl').animate({opacity:.75},250);
1735
- }
1736
- });
1737
- $brNavCntlTopEl.mouseover(function() {
1738
- if ($(this).hasClass('BRdn')) {
1739
- self.$('.BRnavCntl').animate({opacity:1},250);
1740
- }
1741
- }).mouseleave(function() {
1742
- if ($(this).hasClass('BRdn')) {
1743
- self.$('.BRnavCntl').animate({opacity:.75},250);
1744
- }
1745
- });
1773
+ $brNavCntlBtmEl
1774
+ .on("mouseover", function() {
1775
+ if ($(this).hasClass('BRup')) {
1776
+ self.$('.BRnavCntl').animate({opacity:1},250);
1777
+ }
1778
+ })
1779
+ .on("mouseleave", function() {
1780
+ if ($(this).hasClass('BRup')) {
1781
+ self.$('.BRnavCntl').animate({opacity:.75},250);
1782
+ }
1783
+ });
1784
+ $brNavCntlTopEl
1785
+ .on("mouseover", function() {
1786
+ if ($(this).hasClass('BRdn')) {
1787
+ self.$('.BRnavCntl').animate({opacity:1},250);
1788
+ }
1789
+ })
1790
+ .on("mouseleave", function() {
1791
+ if ($(this).hasClass('BRdn')) {
1792
+ self.$('.BRnavCntl').animate({opacity:.75},250);
1793
+ }
1794
+ });
1746
1795
 
1747
1796
  this.initSwipeData();
1748
1797
 
@@ -1780,7 +1829,7 @@ BookReader.prototype.navigationMousemoveHandler = function(event) {
1780
1829
  if (event.data['br'].uiAutoHide) {
1781
1830
  // 77px is an approximate height of the Internet Archive Top Nav
1782
1831
  // 75 & 76 (pixels) provide used in this context is checked against the IA top nav height
1783
- var navkey = $(document).height() - 75;
1832
+ const navkey = $(document).height() - 75;
1784
1833
  if ((event.pageY < 76) || (event.pageY > navkey)) {
1785
1834
  // inside or near navigation elements
1786
1835
  event.data['br'].hideNavigation();
@@ -1807,11 +1856,11 @@ BookReader.prototype.initSwipeData = function(clientX, clientY) {
1807
1856
  deltaX: 0,
1808
1857
  deltaY: 0,
1809
1858
  deltaT: 0
1810
- }
1859
+ };
1811
1860
  };
1812
1861
 
1813
1862
  BookReader.prototype.swipeMousedownHandler = function(event) {
1814
- var self = event.data['br'];
1863
+ const self = event.data['br'];
1815
1864
 
1816
1865
  // We should be the last bubble point for the page images
1817
1866
  // Disable image drag and select, but keep right-click
@@ -1819,13 +1868,13 @@ BookReader.prototype.swipeMousedownHandler = function(event) {
1819
1868
  return !self.protected;
1820
1869
  }
1821
1870
 
1822
- $(event.target).bind('mouseout.swipe',
1871
+ $(event.target).on('mouseout.swipe',
1823
1872
  { 'br': self},
1824
1873
  self.swipeMouseupHandler
1825
- ).bind('mouseup.swipe',
1874
+ ).on('mouseup.swipe',
1826
1875
  { 'br': self},
1827
1876
  self.swipeMouseupHandler
1828
- ).bind('mousemove.swipe',
1877
+ ).on('mousemove.swipe',
1829
1878
  { 'br': self },
1830
1879
  self.swipeMousemoveHandler
1831
1880
  );
@@ -1841,8 +1890,8 @@ BookReader.prototype.swipeMousedownHandler = function(event) {
1841
1890
  };
1842
1891
 
1843
1892
  BookReader.prototype.swipeMousemoveHandler = function(event) {
1844
- var self = event.data['br'];
1845
- var _swipe = self._swipe;
1893
+ const self = event.data['br'];
1894
+ const _swipe = self._swipe;
1846
1895
  if (! _swipe.mightBeSwiping) {
1847
1896
  return;
1848
1897
  }
@@ -1852,12 +1901,12 @@ BookReader.prototype.swipeMousemoveHandler = function(event) {
1852
1901
  _swipe.deltaY = event.clientY - _swipe.startY;
1853
1902
  _swipe.deltaT = (new Date).getTime() - _swipe.startTime;
1854
1903
 
1855
- var absX = Math.abs(_swipe.deltaX);
1856
- var absY = Math.abs(_swipe.deltaY);
1904
+ const absX = Math.abs(_swipe.deltaX);
1905
+ const absY = Math.abs(_swipe.deltaY);
1857
1906
 
1858
1907
  // Minimum distance in the amount of tim to trigger the swipe
1859
- var minSwipeLength = Math.min(self.refs.$br.width() / 5, 80);
1860
- var maxSwipeTime = 400;
1908
+ const minSwipeLength = Math.min(self.refs.$br.width() / 5, 80);
1909
+ const maxSwipeTime = 400;
1861
1910
 
1862
1911
  // Check for horizontal swipe
1863
1912
  if (absX > absY && (absX > minSwipeLength) && _swipe.deltaT < maxSwipeTime) {
@@ -1891,11 +1940,11 @@ BookReader.prototype.swipeMousemoveHandler = function(event) {
1891
1940
  };
1892
1941
 
1893
1942
  BookReader.prototype.swipeMouseupHandler = function(event) {
1894
- var _swipe = event.data['br']._swipe;
1943
+ const _swipe = event.data['br']._swipe;
1895
1944
  _swipe.mightBeSwiping = false;
1896
1945
  _swipe.mightBeDragging = false;
1897
1946
 
1898
- $(event.target).unbind('mouseout.swipe').unbind('mouseup.swipe').unbind('mousemove.swipe');
1947
+ $(event.target).off('mouseout.swipe').off('mouseup.swipe').off('mousemove.swipe');
1899
1948
 
1900
1949
  if (_swipe.didSwipe || _swipe.didDrag) {
1901
1950
  // Swallow event if completed swipe gesture
@@ -1908,20 +1957,21 @@ BookReader.prototype.swipeMouseupHandler = function(event) {
1908
1957
  };
1909
1958
 
1910
1959
  BookReader.prototype.bindMozTouchHandlers = function() {
1911
- var self = this;
1960
+ const self = this;
1912
1961
 
1913
1962
  // Currently only want touch handlers in 2up
1914
- this.refs.$br.bind('MozTouchDown', function(event) {
1915
- if (this.mode == self.constMode2up) {
1916
- event.preventDefault();
1917
- }
1918
- })
1919
- .bind('MozTouchMove', function(event) {
1963
+ this.refs.$br
1964
+ .on('MozTouchDown', function(event) {
1920
1965
  if (this.mode == self.constMode2up) {
1921
1966
  event.preventDefault();
1922
1967
  }
1923
1968
  })
1924
- .bind('MozTouchUp', function(event) {
1969
+ .on('MozTouchMove', function(event) {
1970
+ if (this.mode == self.constMode2up) {
1971
+ event.preventDefault();
1972
+ }
1973
+ })
1974
+ .on('MozTouchUp', function(event) {
1925
1975
  if (this.mode == self.constMode2up) {
1926
1976
  event.preventDefault();
1927
1977
  }
@@ -1934,8 +1984,8 @@ BookReader.prototype.bindMozTouchHandlers = function() {
1934
1984
  */
1935
1985
  BookReader.prototype.navigationIsVisible = function() {
1936
1986
  // $$$ doesn't account for transitioning states, nav must be fully visible to return true
1937
- var toolpos = this.refs.$BRtoolbar.position();
1938
- var tooltop = toolpos.top;
1987
+ const toolpos = this.refs.$BRtoolbar.position();
1988
+ const tooltop = toolpos.top;
1939
1989
  return tooltop == 0;
1940
1990
  };
1941
1991
 
@@ -1944,19 +1994,19 @@ BookReader.prototype.navigationIsVisible = function() {
1944
1994
  * Defaults to SHOW the navigation chrome
1945
1995
  */
1946
1996
  BookReader.prototype.setNavigationView = function brSetNavigationView(hide) {
1947
- var animationLength = this.constNavAnimationDuration;
1948
- var animationType = 'linear';
1949
- var resizePageContainer = function resizePageContainer () {
1997
+ const animationLength = this.constNavAnimationDuration;
1998
+ const animationType = 'linear';
1999
+ const resizePageContainer = function resizePageContainer () {
1950
2000
  /* main page container fills whole container */
1951
2001
  if (this.constMode2up !== this.mode) {
1952
- var animate = true;
2002
+ const animate = true;
1953
2003
  this.resizeBRcontainer(animate);
1954
2004
  }
1955
2005
  this.trigger(BookReader.eventNames.navToggled);
1956
2006
  }.bind(this);
1957
2007
 
1958
- var toolbarHeight = 0;
1959
- var navbarHeight = 0;
2008
+ let toolbarHeight = 0;
2009
+ let navbarHeight = 0;
1960
2010
  if (hide) {
1961
2011
  toolbarHeight = this.getToolBarHeight() * -1;
1962
2012
  navbarHeight = this.getFooterHeight() * -1;
@@ -1987,7 +2037,7 @@ BookReader.prototype.setNavigationView = function brSetNavigationView(hide) {
1987
2037
  BookReader.prototype.hideNavigation = function() {
1988
2038
  // Check if navigation is showing
1989
2039
  if (this.navigationIsVisible()) {
1990
- var hide = true;
2040
+ const hide = true;
1991
2041
  this.setNavigationView(hide);
1992
2042
  }
1993
2043
  };
@@ -2038,7 +2088,7 @@ BookReader.prototype.firstDisplayableIndex = function() {
2038
2088
  */
2039
2089
  BookReader.prototype.lastDisplayableIndex = function() {
2040
2090
 
2041
- var lastIndex = this._models.book.getNumLeafs() - 1;
2091
+ const lastIndex = this._models.book.getNumLeafs() - 1;
2042
2092
 
2043
2093
  if (this.mode != this.constMode2up) {
2044
2094
  return lastIndex;
@@ -2199,7 +2249,7 @@ BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2199
2249
  }
2200
2250
 
2201
2251
  return page.getURISrcSet(reduce, rotate);
2202
- }
2252
+ };
2203
2253
 
2204
2254
 
2205
2255
  /**
@@ -2225,21 +2275,37 @@ BookReader.prototype._getPageURI = function(index, reduce, rotate) {
2225
2275
  };
2226
2276
 
2227
2277
  /**
2228
- * @param {string}
2278
+ * @param {string} msg
2279
+ * @param {function|undefined} onCloseCallback
2229
2280
  */
2230
- BookReader.prototype.showProgressPopup = function(msg) {
2281
+ BookReader.prototype.showProgressPopup = function(msg, onCloseCallback) {
2231
2282
  if (this.popup) return;
2232
2283
 
2233
2284
  this.popup = document.createElement("div");
2234
2285
  $(this.popup).prop('className', 'BRprogresspopup');
2235
- var bar = document.createElement("div");
2286
+
2287
+ if (typeof(onCloseCallback) === 'function') {
2288
+ const closeButton = document.createElement('button');
2289
+ closeButton.setAttribute('title', 'close');
2290
+ closeButton.setAttribute('class', 'close-popup');
2291
+ const icon = document.createElement('span');
2292
+ icon.setAttribute('class', 'icon icon-close-dark');
2293
+ $(closeButton).append(icon);
2294
+ closeButton.addEventListener('click', () => {
2295
+ onCloseCallback();
2296
+ this.removeProgressPopup();
2297
+ });
2298
+ $(this.popup).append(closeButton);
2299
+ }
2300
+
2301
+ const bar = document.createElement("div");
2236
2302
  $(bar).css({
2237
2303
  height: '20px'
2238
2304
  }).prop('className', 'BRprogressbar');
2239
2305
  $(this.popup).append(bar);
2240
2306
 
2241
2307
  if (msg) {
2242
- var msgdiv = document.createElement("div");
2308
+ const msgdiv = document.createElement("div");
2243
2309
  msgdiv.innerHTML = msg;
2244
2310
  $(this.popup).append(msgdiv);
2245
2311
  }
@@ -2261,7 +2327,7 @@ BookReader.prototype.initUIStrings = function() {
2261
2327
  // the toolbar and nav bar easier
2262
2328
 
2263
2329
  // Setup tooltips -- later we could load these from a file for i18n
2264
- var titles = {
2330
+ const titles = {
2265
2331
  '.logo': 'Go to Archive.org', // $$$ update after getting OL record
2266
2332
  '.zoom_in': 'Zoom in',
2267
2333
  '.zoom_out': 'Zoom out',
@@ -2293,10 +2359,10 @@ BookReader.prototype.initUIStrings = function() {
2293
2359
  titles['.book_rightmost'] = 'First page';
2294
2360
  }
2295
2361
 
2296
- for (var icon in titles) {
2362
+ for (const icon in titles) {
2297
2363
  this.$(icon).prop('title', titles[icon]);
2298
2364
  }
2299
- }
2365
+ };
2300
2366
 
2301
2367
  /**
2302
2368
  * Reloads images. Useful when some images might have failed.
@@ -2304,7 +2370,7 @@ BookReader.prototype.initUIStrings = function() {
2304
2370
  BookReader.prototype.reloadImages = function() {
2305
2371
  this.refs.$brContainer.find('img').each(function(index, elem) {
2306
2372
  if (!elem.complete || elem.naturalHeight === 0) {
2307
- var src = elem.src;
2373
+ const src = elem.src;
2308
2374
  elem.src = '';
2309
2375
  setTimeout(function() {
2310
2376
  elem.src = src;
@@ -2318,16 +2384,16 @@ BookReader.prototype.reloadImages = function() {
2318
2384
  * @return {number}
2319
2385
  */
2320
2386
  BookReader.prototype.getFooterHeight = function() {
2321
- var $heightEl = this.mode == this.constMode2up ? this.refs.$BRfooter : this.refs.$BRnav;
2387
+ const $heightEl = this.mode == this.constMode2up ? this.refs.$BRfooter : this.refs.$BRnav;
2322
2388
  if ($heightEl && this.refs.$BRfooter) {
2323
- var outerHeight = $heightEl.outerHeight();
2324
- var bottom = parseInt(this.refs.$BRfooter.css('bottom'));
2389
+ const outerHeight = $heightEl.outerHeight();
2390
+ const bottom = parseInt(this.refs.$BRfooter.css('bottom'));
2325
2391
  if (!isNaN(outerHeight) && !isNaN(bottom)) {
2326
2392
  return outerHeight + bottom;
2327
2393
  }
2328
2394
  }
2329
2395
  return 0;
2330
- }
2396
+ };
2331
2397
 
2332
2398
  // Basic Usage built-in Methods (can be overridden through options)
2333
2399
  // This implementation uses options.data value for populating BookReader
@@ -2337,10 +2403,11 @@ BookReader.prototype.getFooterHeight = function() {
2337
2403
  * @return {Object}
2338
2404
  */
2339
2405
  BookReader.prototype.paramsFromCurrent = function() {
2340
- var params = {};
2406
+ const params = {};
2341
2407
 
2342
- var index = this.currentIndex();
2343
- var pageNum = this._models.book.getPageNum(index);
2408
+ // Path params
2409
+ const index = this.currentIndex();
2410
+ const pageNum = this._models.book.getPageNum(index);
2344
2411
  if ((pageNum === 0) || pageNum) {
2345
2412
  params.page = pageNum;
2346
2413
  }
@@ -2348,10 +2415,17 @@ BookReader.prototype.paramsFromCurrent = function() {
2348
2415
  params.index = index;
2349
2416
  params.mode = this.mode;
2350
2417
 
2418
+ // Unused params
2351
2419
  // $$$ highlight
2352
2420
  // $$$ region
2353
2421
 
2354
- // search
2422
+ // Querystring params
2423
+ // View
2424
+ const fullscreenView = 'theater';
2425
+ if (this.isFullscreenActive) {
2426
+ params.view = fullscreenView;
2427
+ }
2428
+ // Search
2355
2429
  if (this.enableSearch) {
2356
2430
  params.search = this.searchTerm;
2357
2431
  }
@@ -2372,7 +2446,7 @@ BookReader.prototype.paramsFromCurrent = function() {
2372
2446
  * @return {Object}
2373
2447
  */
2374
2448
  BookReader.prototype.paramsFromFragment = function(fragment) {
2375
- var params = {};
2449
+ const params = {};
2376
2450
 
2377
2451
  // For backwards compatibility we allow an initial # character
2378
2452
  // (as from window.location.hash) but don't require it
@@ -2381,7 +2455,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2381
2455
  }
2382
2456
 
2383
2457
  // Simple #nn syntax
2384
- var oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
2458
+ const oldStyleLeafNum = parseInt( /^\d+$/.exec(fragment) );
2385
2459
  if ( !isNaN(oldStyleLeafNum) ) {
2386
2460
  params.index = oldStyleLeafNum;
2387
2461
 
@@ -2390,9 +2464,9 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2390
2464
  }
2391
2465
 
2392
2466
  // Split into key-value pairs
2393
- var urlArray = fragment.split('/');
2394
- var urlHash = {};
2395
- for (var i = 0; i < urlArray.length; i += 2) {
2467
+ const urlArray = fragment.split('/');
2468
+ const urlHash = {};
2469
+ for (let i = 0; i < urlArray.length; i += 2) {
2396
2470
  urlHash[urlArray[i]] = urlArray[i + 1];
2397
2471
  }
2398
2472
 
@@ -2422,7 +2496,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
2422
2496
 
2423
2497
  // $$$ process /theme
2424
2498
  if (urlHash['theme'] != undefined) {
2425
- params.theme = urlHash['theme']
2499
+ params.theme = urlHash['theme'];
2426
2500
  }
2427
2501
  return params;
2428
2502
  };
@@ -2479,6 +2553,9 @@ BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
2479
2553
  /**
2480
2554
  * Create, update querystring from the params object
2481
2555
  *
2556
+ * Handles:
2557
+ * view=
2558
+ * q=
2482
2559
  * @param {Object} params
2483
2560
  * @param {string} currQueryString
2484
2561
  * @param {string} [urlMode]
@@ -2490,21 +2567,30 @@ BookReader.prototype.queryStringFromParams = function(
2490
2567
  urlMode = 'hash'
2491
2568
  ) {
2492
2569
  const newParams = new URLSearchParams(currQueryString);
2570
+
2571
+ if (params.view) {
2572
+ // Set ?view=theater when fullscreen
2573
+ newParams.set('view', params.view);
2574
+ } else {
2575
+ // Remove
2576
+ newParams.delete('view');
2577
+ }
2578
+
2493
2579
  if (params.search && urlMode === 'history') {
2494
- newParams.set('q', params.search)
2580
+ newParams.set('q', params.search);
2495
2581
  }
2496
2582
  // https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
2497
2583
  // Note: This method returns the query string without the question mark.
2498
2584
  const result = newParams.toString();
2499
2585
  return result ? '?' + result : '';
2500
- }
2586
+ };
2501
2587
 
2502
2588
  /**
2503
2589
  * Helper to select within instance's elements
2504
2590
  */
2505
2591
  BookReader.prototype.$ = function(selector) {
2506
2592
  return this.refs.$br.find(selector);
2507
- }
2593
+ };
2508
2594
 
2509
2595
  /**
2510
2596
  * Polyfill for deprecated method