@internetarchive/bookreader 5.0.0-48-alpha2 → 5.0.0-49-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 (35) hide show
  1. package/BookReader/BookReader.js +1 -1
  2. package/BookReader/BookReader.js.map +1 -1
  3. package/BookReader/ia-bookreader-bundle.js +89 -89
  4. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  5. package/BookReaderDemo/IADemoBr.js +2 -0
  6. package/CHANGELOG.md +4 -0
  7. package/package.json +2 -2
  8. package/src/BookNavigator/book-navigator.js +2 -2
  9. package/src/BookNavigator/bookmarks/ia-bookmarks.js +4 -4
  10. package/src/BookNavigator/downloads/downloads-provider.js +42 -10
  11. package/src/BookNavigator/downloads/downloads.js +47 -83
  12. package/src/BookNavigator/volumes/volumes-provider.js +1 -1
  13. package/src/BookReader/BookModel.js +0 -29
  14. package/src/BookReader/Mode1UpLit.js +1 -1
  15. package/src/BookReader/Mode2Up.js +9 -34
  16. package/src/BookReader/ModeThumb.js +1 -3
  17. package/src/BookReader/Navbar/Navbar.js +8 -5
  18. package/src/BookReader/Toolbar/Toolbar.js +3 -30
  19. package/src/BookReader.js +65 -338
  20. package/src/plugins/plugin.autoplay.js +4 -4
  21. package/src/plugins/plugin.chapters.js +2 -2
  22. package/src/plugins/search/plugin.search.js +6 -6
  23. package/src/plugins/search/view.js +2 -2
  24. package/src/plugins/tts/plugin.tts.js +2 -2
  25. package/src/util/manifestGenerator.js +0 -0
  26. package/tests/e2e/models/Navigation.js +1 -1
  27. package/tests/jest/BookNavigator/book-navigator.test.js +19 -15
  28. package/tests/jest/BookReader/BookModel.test.js +31 -11
  29. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +4 -4
  30. package/tests/jest/BookReader/Mode1UpLit.test.js +5 -1
  31. package/tests/jest/BookReader/Mode2Up.test.js +8 -8
  32. package/tests/jest/BookReader.test.js +0 -35
  33. package/tests/jest/plugins/plugin.autoplay.test.js +2 -2
  34. package/tests/jest/plugins/plugin.chapters.test.js +2 -3
  35. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
package/src/BookReader.js CHANGED
@@ -30,19 +30,14 @@ import 'jquery-ui-touch-punch';
30
30
  import PACKAGE_JSON from '../package.json';
31
31
  import * as utils from './BookReader/utils.js';
32
32
  import { exposeOverrideable } from './BookReader/utils/classes.js';
33
- import { Navbar, getNavPageNumHtml } from './BookReader/Navbar/Navbar.js';
33
+ import { Navbar } from './BookReader/Navbar/Navbar.js';
34
34
  import { DEFAULT_OPTIONS } from './BookReader/options.js';
35
35
  /** @typedef {import('./BookReader/options.js').BookReaderOptions} BookReaderOptions */
36
36
  /** @typedef {import('./BookReader/options.js').ReductionFactor} ReductionFactor */
37
37
  /** @typedef {import('./BookReader/BookModel.js').PageIndex} PageIndex */
38
38
  import { EVENTS } from './BookReader/events.js';
39
39
  import { DebugConsole } from './BookReader/DebugConsole.js';
40
- import {
41
- Toolbar,
42
- blankInfoDiv,
43
- blankShareDiv,
44
- createPopup,
45
- } from './BookReader/Toolbar/Toolbar.js';
40
+ import { Toolbar } from './BookReader/Toolbar/Toolbar.js';
46
41
  import { BookModel } from './BookReader/BookModel.js';
47
42
  import { Mode1Up } from './BookReader/Mode1Up.js';
48
43
  import { Mode2Up } from './BookReader/Mode2Up.js';
@@ -151,18 +146,13 @@ BookReader.prototype.setup = function(options) {
151
146
  this.ui = options.ui;
152
147
  this.uiAutoHide = options.uiAutoHide;
153
148
 
154
- this.thumbWidth = 100; // will be overridden during prepareThumbnailView
149
+ this.thumbWidth = 100; // will be overridden during this._modes.modeThumb.prepare();
155
150
  this.thumbRowBuffer = options.thumbRowBuffer;
156
151
  this.thumbColumns = options.thumbColumns;
157
152
  this.thumbMaxLoading = options.thumbMaxLoading;
158
153
  this.thumbPadding = options.thumbPadding;
159
154
  this.displayedRows = [];
160
-
161
155
  this.displayedIndices = [];
162
- /** @deprecated Unused; will be remove in v5 */
163
- this.imgs = {};
164
- /** @deprecated No longer used; will be remove in v5 */
165
- this.prefetchedImgs = {}; //an object with numeric keys corresponding to page index, reduce
166
156
 
167
157
  this.animating = false;
168
158
  this.flipSpeed = options.flipSpeed;
@@ -211,26 +201,22 @@ BookReader.prototype.setup = function(options) {
211
201
 
212
202
  // Assign the data methods
213
203
  this.data = options.data;
214
- if (options.getNumLeafs) BookReader.prototype.getNumLeafs = options.getNumLeafs;
215
- if (options.getPageWidth) BookReader.prototype.getPageWidth = options.getPageWidth;
216
- if (options.getPageHeight) BookReader.prototype.getPageHeight = options.getPageHeight;
217
- if (options.getPageURI) BookReader.prototype.getPageURI = options.getPageURI;
218
- if (options.getPageSide) BookReader.prototype.getPageSide = options.getPageSide;
219
- if (options.getPageNum) BookReader.prototype.getPageNum = options.getPageNum;
220
- if (options.getPageProp) BookReader.prototype.getPageProp = options.getPageProp;
221
- if (options.getSpreadIndices) BookReader.prototype.getSpreadIndices = options.getSpreadIndices;
222
- if (options.leafNumToIndex) BookReader.prototype.leafNumToIndex = options.leafNumToIndex;
223
204
 
224
205
  /** @type {{[name: string]: JQuery}} */
225
206
  this.refs = {};
226
207
 
227
- /**
228
- * @private (for now) Models are largely state storing classes. This might be too much
229
- * granularity, but time will tell!
230
- */
231
- this._models = {
232
- book: new BookModel(this),
233
- };
208
+ /** The book being displayed in BookReader*/
209
+ this.book = new BookModel(this);
210
+
211
+ if (options.getNumLeafs) this.book.getNumLeafs = options.getNumLeafs.bind(this);
212
+ if (options.getPageWidth) this.book.getPageWidth = options.getPageWidth.bind(this);
213
+ if (options.getPageHeight) this.book.getPageHeight = options.getPageHeight.bind(this);
214
+ if (options.getPageURI) this.book.getPageURI = options.getPageURI.bind(this);
215
+ if (options.getPageSide) this.book.getPageSide = options.getPageSide.bind(this);
216
+ if (options.getPageNum) this.book.getPageNum = options.getPageNum.bind(this);
217
+ if (options.getPageProp) this.book.getPageProp = options.getPageProp.bind(this);
218
+ if (options.getSpreadIndices) this.book.getSpreadIndices = options.getSpreadIndices.bind(this);
219
+ if (options.leafNumToIndex) this.book.leafNumToIndex = options.leafNumToIndex.bind(this);
234
220
 
235
221
  /**
236
222
  * @private Components are 'subchunks' of bookreader functionality, usually UI related
@@ -244,14 +230,14 @@ BookReader.prototype.setup = function(options) {
244
230
  };
245
231
 
246
232
  this._modes = {
247
- mode1Up: new Mode1Up(this, this._models.book),
248
- mode2Up: new Mode2Up(this, this._models.book),
249
- modeThumb: new ModeThumb(this, this._models.book),
233
+ mode1Up: new Mode1Up(this, this.book),
234
+ mode2Up: new Mode2Up(this, this.book),
235
+ modeThumb: new ModeThumb(this, this.book),
250
236
  };
251
237
 
252
238
  /** Stores classes which we want to expose (selectively) some methods as overridable */
253
239
  this._overrideable = {
254
- '_models.book': this._models.book,
240
+ 'book': this.book,
255
241
  '_components.navbar': this._components.navbar,
256
242
  '_components.toolbar': this._components.toolbar,
257
243
  '_modes.mode1Up': this._modes.mode1Up,
@@ -260,7 +246,7 @@ BookReader.prototype.setup = function(options) {
260
246
  };
261
247
 
262
248
  /** Image cache for general image fetching */
263
- this.imageCache = new ImageCache(this._models.book, {
249
+ this.imageCache = new ImageCache(this.book, {
264
250
  useSrcSet: this.options.useSrcSet,
265
251
  reduceSet: this.reduceSet,
266
252
  });
@@ -310,17 +296,6 @@ Object.defineProperty(BookReader.prototype, 'activeMode', {
310
296
  }[this.mode]; },
311
297
  });
312
298
 
313
- /** @deprecated unused outside Mode2Up */
314
- Object.defineProperty(BookReader.prototype, 'leafEdgeL', {
315
- get() { return this._modes.mode2Up.leafEdgeL; },
316
- set(newVal) { this._modes.mode2Up.leafEdgeL = newVal; }
317
- });
318
- /** @deprecated unused outside Mode2Up */
319
- Object.defineProperty(BookReader.prototype, 'leafEdgeR', {
320
- get() { return this._modes.mode2Up.leafEdgeR; },
321
- set(newVal) { this._modes.mode2Up.leafEdgeR = newVal; }
322
- });
323
-
324
299
  /**
325
300
  * BookReader.util are static library functions
326
301
  * At top of file so they can be used below
@@ -335,7 +310,7 @@ BookReader.util = utils;
335
310
  BookReader.prototype.extendParams = function(params, newParams) {
336
311
  const modifiedNewParams = $.extend({}, newParams);
337
312
  if ('undefined' != typeof(modifiedNewParams.page)) {
338
- const pageIndex = this._models.book.parsePageString(modifiedNewParams.page);
313
+ const pageIndex = this.book.parsePageString(modifiedNewParams.page);
339
314
  if (!isNaN(pageIndex))
340
315
  modifiedNewParams.index = pageIndex;
341
316
  delete modifiedNewParams.page;
@@ -366,8 +341,8 @@ BookReader.prototype.initParams = function() {
366
341
 
367
342
  // If we have a title leaf, use that as the default instead of index 0,
368
343
  // but only use as default if book has a few pages
369
- if ('undefined' != typeof(this.titleLeaf) && this._models.book.getNumLeafs() > 2) {
370
- params.index = this._models.book.leafNumToIndex(this.titleLeaf);
344
+ if ('undefined' != typeof(this.titleLeaf) && this.book.getNumLeafs() > 2) {
345
+ params.index = this.book.leafNumToIndex(this.titleLeaf);
371
346
  } else {
372
347
  params.index = 0;
373
348
  }
@@ -548,7 +523,7 @@ BookReader.prototype.init = function() {
548
523
  }
549
524
 
550
525
  // Switch navbar controls on mobile/desktop
551
- this.switchNavbarControls();
526
+ this._components.navbar.switchNavbarControls();
552
527
 
553
528
  this.resizeBRcontainer();
554
529
  this.updateFromParams(params);
@@ -632,11 +607,11 @@ BookReader.prototype.resize = function() {
632
607
  this.resizeBRcontainer();
633
608
 
634
609
  // Switch navbar controls on mobile/desktop
635
- this.switchNavbarControls();
610
+ this._components.navbar.switchNavbarControls();
636
611
 
637
612
  if (this.constMode1up == this.mode) {
638
613
  if (this.onePage.autofit != 'none') {
639
- this.resizePageView1up();
614
+ this._modes.mode1Up.resizePageView();
640
615
  this.centerPageView();
641
616
  } else {
642
617
  this.centerPageView();
@@ -644,12 +619,12 @@ BookReader.prototype.resize = function() {
644
619
  this.drawLeafsThrottled();
645
620
  }
646
621
  } else if (this.constModeThumb == this.mode) {
647
- this.prepareThumbnailView();
622
+ this._modes.modeThumb.prepare();
648
623
  } else {
649
624
  // We only need to prepare again in autofit (size of spread changes)
650
625
  if (this.twoPage.autofit) {
651
626
  // most common path, esp. for archive.org books
652
- this.prepareTwoPageView();
627
+ this._modes.mode2Up.prepare();
653
628
  } else {
654
629
  // used when zoomed in
655
630
  // Re-center if the scrollbars have disappeared
@@ -664,7 +639,7 @@ BookReader.prototype.resize = function() {
664
639
  doRecenter = true;
665
640
  }
666
641
  if (doRecenter) {
667
- this.twoPageCenterView(center.percentageX, center.percentageY);
642
+ this._modes.mode2Up.centerView(center.percentageX, center.percentageY);
668
643
  }
669
644
  }
670
645
  }
@@ -790,10 +765,9 @@ BookReader.prototype.setupKeyListeners = function () {
790
765
  BookReader.prototype.drawLeafs = function() {
791
766
  if (this.constMode1up == this.mode) {
792
767
  // Not needed for Mode1Up anymore
793
- } else if (this.constModeThumb == this.mode) {
794
- this.drawLeafsThumbnail();
768
+ return;
795
769
  } else {
796
- this.drawLeafsTwoPage();
770
+ this.activeMode.drawLeafs();
797
771
  }
798
772
  };
799
773
 
@@ -802,7 +776,7 @@ BookReader.prototype.drawLeafs = function() {
802
776
  * @param {PageIndex} index
803
777
  */
804
778
  BookReader.prototype._createPageContainer = function(index) {
805
- return new PageContainer(this._models.book.getPage(index, false), {
779
+ return new PageContainer(this.book.getPage(index, false), {
806
780
  isProtected: this.protected,
807
781
  imageCache: this.imageCache,
808
782
  loadingImage: this.imagesBaseURL + 'loading.gif',
@@ -838,24 +812,6 @@ BookReader.prototype.bindGestures = function(jElement) {
838
812
  });
839
813
  };
840
814
 
841
- /** @deprecated Not used outside ModeThumb */
842
- BookReader.prototype.drawLeafsThumbnail = ModeThumb.prototype.drawLeafs;
843
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'drawLeafs', 'drawLeafsThumbnail');
844
- /** @deprecated Not used outside ModeThumb */
845
- BookReader.prototype.lazyLoadThumbnails = ModeThumb.prototype.lazyLoadThumbnails;
846
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'lazyLoadThumbnails', 'lazyLoadThumbnails');
847
- BookReader.prototype.lazyLoadImage = ModeThumb.prototype.lazyLoadImage;
848
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'lazyLoadImage', 'lazyLoadImage');
849
- /** @deprecated Internal use only */
850
- BookReader.prototype.zoomThumb = ModeThumb.prototype.zoom;
851
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'zoom', 'zoomThumb');
852
- /** @deprecated Not used outside ModeThumb */
853
- BookReader.prototype.getThumbnailWidth = ModeThumb.prototype.getThumbnailWidth;
854
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'getThumbnailWidth', 'getThumbnailWidth');
855
- /** @deprecated Not used outside ModeThumb */
856
- BookReader.prototype.prepareThumbnailView = ModeThumb.prototype.prepare;
857
- exposeOverrideableMethod(ModeThumb, '_modes.modeThumb', 'prepare', 'prepareThumbnailView');
858
-
859
815
  /**
860
816
  * A throttled version of drawLeafs
861
817
  */
@@ -990,7 +946,7 @@ BookReader.prototype._reduceSort = (a, b) => a.reduce - b.reduce;
990
946
  * @return {boolean} Returns true if page could be found, false otherwise.
991
947
  */
992
948
  BookReader.prototype.jumpToPage = function(pageNum) {
993
- const pageIndex = this._models.book.parsePageString(pageNum);
949
+ const pageIndex = this.book.parsePageString(pageNum);
994
950
 
995
951
  if ('undefined' != typeof(pageIndex)) {
996
952
  this.jumpToIndex(pageIndex);
@@ -1019,7 +975,7 @@ BookReader.prototype._isIndexDisplayed = function(index) {
1019
975
  */
1020
976
  BookReader.prototype.jumpToIndex = function(index, pageX, pageY, noAnimate) {
1021
977
  // Don't jump into specific unviewable page
1022
- const page = this._models.book.getPage(index);
978
+ const page = this.book.getPage(index);
1023
979
  if (!page.isViewable && page.unviewablesStart != page.index) {
1024
980
  // If already in unviewable range, jump to end of that range
1025
981
  const alreadyInPreview = this._isIndexDisplayed(page.unviewablesStart);
@@ -1041,7 +997,6 @@ BookReader.prototype.jumpToIndex = function(index, pageX, pageY, noAnimate) {
1041
997
  /**
1042
998
  * Return mode or 1up if initial thumb
1043
999
  * @param {number}
1044
- * @see BookReader.prototype.drawLeafsThumbnail
1045
1000
  */
1046
1001
  BookReader.prototype.getPrevReadMode = function(mode) {
1047
1002
  if (mode === BookReader.constMode1up || mode === BookReader.constMode2up) {
@@ -1097,21 +1052,21 @@ BookReader.prototype.switchMode = function(
1097
1052
 
1098
1053
  // XXX maybe better to preserve zoom in each mode
1099
1054
  if (this.constMode1up == mode) {
1100
- this.prepareOnePageView();
1055
+ this._modes.mode1Up.prepare();
1101
1056
  } else if (this.constModeThumb == mode) {
1102
1057
  this.reduce = this.quantizeReduce(this.reduce, this.reductionFactors);
1103
- this.prepareThumbnailView();
1058
+ this._modes.modeThumb.prepare();
1104
1059
  } else {
1105
1060
  // $$$ why don't we save autofit?
1106
1061
  // this.twoPage.autofit = null; // Take zoom level from other mode
1107
1062
  // spread indices not set, so let's set them
1108
1063
  if (init || !pageFound) {
1109
- this.setSpreadIndices();
1064
+ this._modes.mode2Up.setSpreadIndices();
1110
1065
  }
1111
1066
 
1112
- this.twoPageCalculateReductionFactors(); // this sets this.twoPage && this.reduce
1113
- this.prepareTwoPageView();
1114
- this.twoPageCenterView(0.5, 0.5); // $$$ TODO preserve center
1067
+ this._modes.mode2Up.calculateReductionFactors(); // this sets this.twoPage && this.reduce
1068
+ this._modes.mode2Up.prepare();
1069
+ this._modes.mode2Up.centerView(0.5, 0.5); // $$$ TODO preserve center
1115
1070
  }
1116
1071
 
1117
1072
  if (!(this.suppressFragmentChange || suppressFragmentChange)) {
@@ -1188,7 +1143,7 @@ BookReader.prototype.enterFullscreen = async function(bindKeyboardControls = tru
1188
1143
  this.animating = true;
1189
1144
  await new Promise(res => this.refs.$brContainer.animate({opacity: 1}, 'fast', 'linear', res));
1190
1145
  if (this.activeMode instanceof Mode1Up) {
1191
- this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this._models.book.getPage(currentIndex));
1146
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(currentIndex));
1192
1147
  // Need the new scale to be applied before calling jumpToIndex
1193
1148
  this.activeMode.mode1UpLit.requestUpdate();
1194
1149
  await this.activeMode.mode1UpLit.updateComplete;
@@ -1239,7 +1194,7 @@ BookReader.prototype.exitFullScreen = async function () {
1239
1194
  this.resize();
1240
1195
 
1241
1196
  if (this.activeMode instanceof Mode1Up) {
1242
- this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this._models.book.getPage(this.currentIndex()));
1197
+ this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(this.currentIndex()));
1243
1198
  this.activeMode.mode1UpLit.requestUpdate();
1244
1199
  await this.activeMode.mode1UpLit.updateComplete;
1245
1200
  }
@@ -1262,7 +1217,7 @@ BookReader.prototype.currentIndex = function() {
1262
1217
  return this.firstIndex; // $$$ TODO page in center of view would be better
1263
1218
  } else if (this.mode == this.constMode2up) {
1264
1219
  // Only allow indices that are actually present in book
1265
- return utils.clamp(this.firstIndex, 0, this._models.book.getNumLeafs() - 1);
1220
+ return utils.clamp(this.firstIndex, 0, this.book.getNumLeafs() - 1);
1266
1221
  } else {
1267
1222
  throw 'currentIndex called for unimplemented mode ' + this.mode;
1268
1223
  }
@@ -1293,7 +1248,7 @@ BookReader.prototype.updateFirstIndex = function(
1293
1248
  this.suppressFragmentChange = false;
1294
1249
  }
1295
1250
  this.trigger('pageChanged');
1296
- this.updateNavIndexThrottled(index);
1251
+ this._components.navbar.updateNavIndexThrottled(index);
1297
1252
  };
1298
1253
 
1299
1254
  /**
@@ -1340,10 +1295,10 @@ BookReader.prototype.leftmost = function() {
1340
1295
  }
1341
1296
  };
1342
1297
 
1343
- BookReader.prototype.next = function() {
1298
+ BookReader.prototype.next = function({triggerStop = true} = {}) {
1344
1299
  if (this.constMode2up == this.mode) {
1345
- this.trigger(BookReader.eventNames.stop);
1346
- this.flipFwdToIndex(null);
1300
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1301
+ this._modes.mode2Up.flipFwdToIndex(null);
1347
1302
  } else {
1348
1303
  if (this.firstIndex < this.lastDisplayableIndex()) {
1349
1304
  this.jumpToIndex(this.firstIndex + 1);
@@ -1351,13 +1306,13 @@ BookReader.prototype.next = function() {
1351
1306
  }
1352
1307
  };
1353
1308
 
1354
- BookReader.prototype.prev = function() {
1309
+ BookReader.prototype.prev = function({triggerStop = true} = {}) {
1355
1310
  const isOnFrontPage = this.firstIndex < 1;
1356
1311
  if (isOnFrontPage) return;
1357
1312
 
1358
1313
  if (this.constMode2up == this.mode) {
1359
- this.trigger(BookReader.eventNames.stop);
1360
- this.flipBackToIndex(null);
1314
+ if (triggerStop) this.trigger(BookReader.eventNames.stop);
1315
+ this._modes.mode2Up.flipBackToIndex(null);
1361
1316
  } else {
1362
1317
  if (this.firstIndex >= 1) {
1363
1318
  this.jumpToIndex(this.firstIndex - 1);
@@ -1419,146 +1374,12 @@ BookReader.prototype.scrollUp = function() {
1419
1374
  BookReader.prototype._scrollAmount = function() {
1420
1375
  if (this.constMode1up == this.mode) {
1421
1376
  // Overlap by % of page size
1422
- return parseInt(this.refs.$brContainer.prop('clientHeight') - this._models.book.getPageHeight(this.currentIndex()) / this.reduce * 0.03);
1377
+ return parseInt(this.refs.$brContainer.prop('clientHeight') - this.book.getPageHeight(this.currentIndex()) / this.reduce * 0.03);
1423
1378
  }
1424
1379
 
1425
1380
  return parseInt(0.9 * this.refs.$brContainer.prop('clientHeight'));
1426
1381
  };
1427
1382
 
1428
- /**
1429
- * @deprecated No longer used; will be remove in v5
1430
- */
1431
- BookReader.prototype.prefetchImg = async function(index, fetchNow = false) {
1432
- console.warn('Call to deprecated function: BookReader.prefetchImg. No-op.');
1433
- };
1434
-
1435
- /**
1436
- * @deprecated No longer used; will be remove in v5
1437
- */
1438
- BookReader.prototype.pruneUnusedImgs = function() {
1439
- console.warn('Call to deprecated function: BookReader.pruneUnused. No-op.');
1440
- };
1441
-
1442
- /************************/
1443
- /** Mode1Up extensions **/
1444
- /************************/
1445
- /** @deprecated not used outside BookReader */
1446
- BookReader.prototype.prepareOnePageView = Mode1Up.prototype.prepare;
1447
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'prepare', 'prepareOnePageView');
1448
- /** @deprecated not used outside BookReader */
1449
- BookReader.prototype.zoom1up = Mode1Up.prototype.zoom;
1450
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'zoom', 'zoom1up');
1451
- /** @deprecated not used outside Mode1Up, BookReader */
1452
- BookReader.prototype.resizePageView1up = Mode1Up.prototype.resizePageView;
1453
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'resizePageView', 'resizePageView1up');
1454
- /** @deprecated not used outside Mode1Up */
1455
- BookReader.prototype.onePageCalculateViewDimensions = Mode1Up.prototype.calculateViewDimensions;
1456
- exposeOverrideableMethod(Mode1Up, '_modes.mode1Up', 'calculateViewDimensions', 'onePageCalculateViewDimensions');
1457
-
1458
- /************************/
1459
- /** Mode2Up extensions **/
1460
- /************************/
1461
- /** @deprecated not used outside Mode2Up */
1462
- BookReader.prototype.zoom2up = Mode2Up.prototype.zoom;
1463
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'zoom', 'zoom2up');
1464
- BookReader.prototype.twoPageGetAutofitReduce = Mode2Up.prototype.getAutofitReduce;
1465
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getAutofitReduce', 'twoPageGetAutofitReduce');
1466
- BookReader.prototype.flipBackToIndex = Mode2Up.prototype.flipBackToIndex;
1467
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipBackToIndex', 'flipBackToIndex');
1468
- BookReader.prototype.flipFwdToIndex = Mode2Up.prototype.flipFwdToIndex;
1469
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipFwdToIndex', 'flipFwdToIndex');
1470
- BookReader.prototype.setHilightCss2UP = Mode2Up.prototype.setHilightCss;
1471
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setHilightCss', 'setHilightCss2UP');
1472
- /** @deprecated not used outside Mode2Up */
1473
- BookReader.prototype.drawLeafsTwoPage = Mode2Up.prototype.drawLeafs;
1474
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'drawLeafs', 'drawLeafsTwoPage');
1475
- /** @deprecated not used outside BookReader */
1476
- BookReader.prototype.prepareTwoPageView = Mode2Up.prototype.prepareTwoPageView;
1477
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareTwoPageView', 'prepareTwoPageView');
1478
- /** @deprecated not used outside Mode2Up */
1479
- BookReader.prototype.prepareTwoPagePopUp = Mode2Up.prototype.preparePopUp;
1480
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'preparePopUp', 'prepareTwoPagePopUp');
1481
- /** @deprecated not used outside BookReader, Mode2Up */
1482
- BookReader.prototype.calculateSpreadSize = Mode2Up.prototype.calculateSpreadSize;
1483
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateSpreadSize', 'calculateSpreadSize');
1484
- /** @deprecated not used outside BookReader, Mode2Up */
1485
- BookReader.prototype.getIdealSpreadSize = Mode2Up.prototype.getIdealSpreadSize;
1486
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getIdealSpreadSize', 'getIdealSpreadSize');
1487
- /** @deprecated not used outside BookReader, Mode2Up */
1488
- BookReader.prototype.getSpreadSizeFromReduce = Mode2Up.prototype.getSpreadSizeFromReduce;
1489
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getSpreadSizeFromReduce', 'getSpreadSizeFromReduce');
1490
- /** @deprecated unused */
1491
- BookReader.prototype.twoPageIsZoomedIn = Mode2Up.prototype.isZoomedIn;
1492
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'isZoomedIn', 'twoPageIsZoomedIn');
1493
- /** @deprecated not used outside BookReader */
1494
- BookReader.prototype.twoPageCalculateReductionFactors = Mode2Up.prototype.calculateReductionFactors;
1495
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'calculateReductionFactors', 'twoPageCalculateReductionFactors');
1496
- /** @deprecated unused */
1497
- BookReader.prototype.twoPageSetCursor = Mode2Up.prototype.setCursor;
1498
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setCursor', 'twoPageSetCursor');
1499
- /** @deprecated unused outside BookReader, Mode2Up */
1500
- BookReader.prototype.flipLeftToRight = Mode2Up.prototype.flipLeftToRight;
1501
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipLeftToRight', 'flipLeftToRight');
1502
- /** @deprecated unused outside BookReader, Mode2Up */
1503
- BookReader.prototype.flipRightToLeft = Mode2Up.prototype.flipRightToLeft;
1504
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipRightToLeft', 'flipRightToLeft');
1505
- /** @deprecated unused outside BookReader, Mode2Up */
1506
- BookReader.prototype.prepareFlipLeftToRight = Mode2Up.prototype.prepareFlipLeftToRight;
1507
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipLeftToRight', 'prepareFlipLeftToRight');
1508
- /** @deprecated unused outside BookReader, Mode2Up */
1509
- BookReader.prototype.prepareFlipRightToLeft = Mode2Up.prototype.prepareFlipRightToLeft;
1510
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prepareFlipRightToLeft', 'prepareFlipRightToLeft');
1511
- /** @deprecated unused outside Mode2Up */
1512
- BookReader.prototype.getPageWidth2UP = Mode2Up.prototype.getPageWidth;
1513
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getPageWidth', 'getPageWidth2UP');
1514
- /** @deprecated unused outside Mode2Up */
1515
- BookReader.prototype.twoPageGutter = Mode2Up.prototype.gutter;
1516
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutter', 'twoPageGutter');
1517
- /** @deprecated unused outside Mode2Up */
1518
- BookReader.prototype.twoPageTop = Mode2Up.prototype.top;
1519
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'top', 'twoPageTop');
1520
- /** @deprecated unused outside Mode2Up */
1521
- BookReader.prototype.twoPageCoverWidth = Mode2Up.prototype.coverWidth;
1522
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'coverWidth', 'twoPageCoverWidth');
1523
- /** @deprecated unused outside Mode2Up */
1524
- BookReader.prototype.twoPageGetViewCenter = Mode2Up.prototype.getViewCenter;
1525
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'getViewCenter', 'twoPageGetViewCenter');
1526
- /** @deprecated unused outside BookReader, Mode2Up */
1527
- BookReader.prototype.twoPageCenterView = Mode2Up.prototype.centerView;
1528
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'centerView', 'twoPageCenterView');
1529
- /** @deprecated unused outside Mode2Up */
1530
- BookReader.prototype.twoPageFlipAreaHeight = Mode2Up.prototype.flipAreaHeight;
1531
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaHeight', 'twoPageFlipAreaHeight');
1532
- /** @deprecated unused outside Mode2Up */
1533
- BookReader.prototype.twoPageFlipAreaWidth = Mode2Up.prototype.flipAreaWidth;
1534
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaWidth', 'twoPageFlipAreaWidth');
1535
- /** @deprecated unused outside BookReader, Mode2Up */
1536
- BookReader.prototype.twoPageFlipAreaTop = Mode2Up.prototype.flipAreaTop;
1537
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'flipAreaTop', 'twoPageFlipAreaTop');
1538
- /** @deprecated unused outside Mode2Up */
1539
- BookReader.prototype.twoPageLeftFlipAreaLeft = Mode2Up.prototype.leftFlipAreaLeft;
1540
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leftFlipAreaLeft', 'twoPageLeftFlipAreaLeft');
1541
- /** @deprecated unused outside Mode2Up */
1542
- BookReader.prototype.twoPageRightFlipAreaLeft = Mode2Up.prototype.rightFlipAreaLeft;
1543
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'rightFlipAreaLeft', 'twoPageRightFlipAreaLeft');
1544
- /** @deprecated unused outside BookReader, Mode2Up */
1545
- BookReader.prototype.gutterOffsetForIndex = Mode2Up.prototype.gutterOffsetForIndex;
1546
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'gutterOffsetForIndex', 'gutterOffsetForIndex');
1547
- /** @deprecated unused outside BookReader, Mode2Up */
1548
- BookReader.prototype.leafEdgeWidth = Mode2Up.prototype.leafEdgeWidth;
1549
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'leafEdgeWidth', 'leafEdgeWidth');
1550
- /** @deprecated unused outside BookReader, Mode2Up */
1551
- BookReader.prototype.jumpIndexForLeftEdgePageX = Mode2Up.prototype.jumpIndexForLeftEdgePageX;
1552
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForLeftEdgePageX', 'jumpIndexForLeftEdgePageX');
1553
- /** @deprecated unused outside BookReader, Mode2Up */
1554
- BookReader.prototype.jumpIndexForRightEdgePageX = Mode2Up.prototype.jumpIndexForRightEdgePageX;
1555
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'jumpIndexForRightEdgePageX', 'jumpIndexForRightEdgePageX');
1556
- /** @deprecated unused outside Mode2Up */
1557
- BookReader.prototype.prefetch = Mode2Up.prototype.prefetch;
1558
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'prefetch', 'prefetch');
1559
- /** @deprecated unused outside Mode2Up */
1560
- BookReader.prototype.setSpreadIndices = Mode2Up.prototype.setSpreadIndices;
1561
- exposeOverrideableMethod(Mode2Up, '_modes.mode2Up', 'setSpreadIndices', 'setSpreadIndices');
1562
1383
  /**
1563
1384
  * Immediately stop flip animations. Callbacks are triggered.
1564
1385
  */
@@ -1604,27 +1425,9 @@ function exposeOverrideableMethod(Class, classKey, method, brMethod = method) {
1604
1425
  /***********************/
1605
1426
  /** Navbar extensions **/
1606
1427
  /***********************/
1428
+ /** This cannot be removed yet because plugin.tts.js overrides it */
1607
1429
  BookReader.prototype.initNavbar = Navbar.prototype.init;
1608
1430
  exposeOverrideableMethod(Navbar, '_components.navbar', 'init', 'initNavbar');
1609
- BookReader.prototype.switchNavbarControls = Navbar.prototype.switchNavbarControls;
1610
- exposeOverrideableMethod(Navbar, '_components.navbar', 'switchNavbarControls');
1611
- BookReader.prototype.updateViewModeButton = Navbar.prototype.updateViewModeButton;
1612
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateViewModeButton');
1613
- BookReader.prototype.getNavPageNumString = Navbar.prototype.getNavPageNumString;
1614
- exposeOverrideableMethod(Navbar, '_components.navbar', 'getNavPageNumString');
1615
- /** @deprecated unused */
1616
- BookReader.prototype.getNavPageNumHtml = getNavPageNumHtml;
1617
- /** @deprecated unused outside this file */
1618
- BookReader.prototype.updateNavPageNum = Navbar.prototype.updateNavPageNum;
1619
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavPageNum');
1620
- /** @deprecated unused outside this file */
1621
- BookReader.prototype.updateNavIndex = Navbar.prototype.updateNavIndex;
1622
- exposeOverrideableMethod(Navbar, '_components.navbar', 'updateNavIndex');
1623
- /** @deprecated unused outside this file */
1624
- BookReader.prototype.updateNavIndexThrottled = utils.throttle(BookReader.prototype.updateNavIndex, 250, false);
1625
- /** @deprecated unused */
1626
- BookReader.prototype.updateNavIndexDebounced = utils.debounce(BookReader.prototype.updateNavIndex, 500, false);
1627
-
1628
1431
 
1629
1432
  /************************/
1630
1433
  /** Toolbar extensions **/
@@ -1639,15 +1442,6 @@ BookReader.prototype.buildInfoDiv = Toolbar.prototype.buildInfoDiv;
1639
1442
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildInfoDiv');
1640
1443
  BookReader.prototype.getToolBarHeight = Toolbar.prototype.getToolBarHeight;
1641
1444
  exposeOverrideableMethod(Toolbar, '_components.toolbar', 'getToolBarHeight');
1642
- /** @deprecated zoom no longer in toolbar */
1643
- BookReader.prototype.updateToolbarZoom = Toolbar.prototype.updateToolbarZoom;
1644
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'updateToolbarZoom');
1645
- /** @deprecated unused */
1646
- BookReader.prototype.blankInfoDiv = blankInfoDiv;
1647
- /** @deprecated unused */
1648
- BookReader.prototype.blankShareDiv = blankShareDiv;
1649
- /** @deprecated unused */
1650
- BookReader.prototype.createPopup = createPopup;
1651
1445
 
1652
1446
  /**
1653
1447
  * Bind navigation handlers
@@ -2063,14 +1857,14 @@ BookReader.prototype.firstDisplayableIndex = function() {
2063
1857
 
2064
1858
  if ('rl' != this.pageProgression) {
2065
1859
  // LTR
2066
- if (this._models.book.getPageSide(0) == 'L') {
1860
+ if (this.book.getPageSide(0) == 'L') {
2067
1861
  return 0;
2068
1862
  } else {
2069
1863
  return -1;
2070
1864
  }
2071
1865
  } else {
2072
1866
  // RTL
2073
- if (this._models.book.getPageSide(0) == 'R') {
1867
+ if (this.book.getPageSide(0) == 'R') {
2074
1868
  return 0;
2075
1869
  } else {
2076
1870
  return -1;
@@ -2086,7 +1880,7 @@ BookReader.prototype.firstDisplayableIndex = function() {
2086
1880
  */
2087
1881
  BookReader.prototype.lastDisplayableIndex = function() {
2088
1882
 
2089
- const lastIndex = this._models.book.getNumLeafs() - 1;
1883
+ const lastIndex = this.book.getNumLeafs() - 1;
2090
1884
 
2091
1885
  if (this.mode != this.constMode2up) {
2092
1886
  return lastIndex;
@@ -2094,14 +1888,14 @@ BookReader.prototype.lastDisplayableIndex = function() {
2094
1888
 
2095
1889
  if ('rl' != this.pageProgression) {
2096
1890
  // LTR
2097
- if (this._models.book.getPageSide(lastIndex) == 'R') {
1891
+ if (this.book.getPageSide(lastIndex) == 'R') {
2098
1892
  return lastIndex;
2099
1893
  } else {
2100
1894
  return lastIndex + 1;
2101
1895
  }
2102
1896
  } else {
2103
1897
  // RTL
2104
- if (this._models.book.getPageSide(lastIndex) == 'L') {
1898
+ if (this.book.getPageSide(lastIndex) == 'L') {
2105
1899
  return lastIndex;
2106
1900
  } else {
2107
1901
  return lastIndex + 1;
@@ -2113,46 +1907,11 @@ BookReader.prototype.lastDisplayableIndex = function() {
2113
1907
  /**************************/
2114
1908
  /** BookModel extensions **/
2115
1909
  /**************************/
2116
- /** @deprecated not used outside */
2117
- BookReader.prototype.getMedianPageSize = BookModel.prototype.getMedianPageSize;
2118
- exposeOverrideableMethod(BookModel, '_models.book', 'getMedianPageSize');
2119
- BookReader.prototype._getPageWidth = BookModel.prototype._getPageWidth;
2120
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageWidth');
2121
- BookReader.prototype._getPageHeight = BookModel.prototype._getPageHeight;
2122
- exposeOverrideableMethod(BookModel, '_models.book', '_getPageHeight');
2123
- BookReader.prototype.getPageIndex = BookModel.prototype.getPageIndex;
2124
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndex');
2125
- /** @deprecated not used outside */
2126
- BookReader.prototype.getPageIndices = BookModel.prototype.getPageIndices;
2127
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageIndices');
2128
- BookReader.prototype.getPageName = BookModel.prototype.getPageName;
2129
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageName');
2130
- BookReader.prototype.getNumLeafs = BookModel.prototype.getNumLeafs;
2131
- exposeOverrideableMethod(BookModel, '_models.book', 'getNumLeafs');
2132
- BookReader.prototype.getPageWidth = BookModel.prototype.getPageWidth;
2133
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageWidth');
2134
- BookReader.prototype.getPageHeight = BookModel.prototype.getPageHeight;
2135
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageHeight');
1910
+ // Must modify petabox extension, which expects this on the prototype
1911
+ // before removing.
2136
1912
  BookReader.prototype.getPageURI = BookModel.prototype.getPageURI;
2137
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageURI');
2138
- BookReader.prototype.getPageSide = BookModel.prototype.getPageSide;
2139
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageSide');
2140
- BookReader.prototype.getPageNum = BookModel.prototype.getPageNum;
2141
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageNum');
2142
- BookReader.prototype.getPageProp = BookModel.prototype.getPageProp;
2143
- exposeOverrideableMethod(BookModel, '_models.book', 'getPageProp');
2144
- BookReader.prototype.getSpreadIndices = BookModel.prototype.getSpreadIndices;
2145
- exposeOverrideableMethod(BookModel, '_models.book', 'getSpreadIndices');
2146
- BookReader.prototype.leafNumToIndex = BookModel.prototype.leafNumToIndex;
2147
- exposeOverrideableMethod(BookModel, '_models.book', 'leafNumToIndex');
2148
- BookReader.prototype.parsePageString = BookModel.prototype.parsePageString;
2149
- exposeOverrideableMethod(BookModel, '_models.book', 'parsePageString');
2150
- /** @deprecated unused */
2151
- BookReader.prototype._getDataFlattened = BookModel.prototype._getDataFlattened;
2152
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataFlattened');
2153
- /** @deprecated unused */
2154
- BookReader.prototype._getDataProp = BookModel.prototype._getDataProp;
2155
- exposeOverrideableMethod(BookModel, '_models.book', '_getDataProp');
1913
+ exposeOverrideableMethod(BookModel, 'book', 'getPageURI');
1914
+
2156
1915
 
2157
1916
  // Parameter related functions
2158
1917
 
@@ -2183,7 +1942,7 @@ BookReader.prototype.updateFromParams = function(params) {
2183
1942
  }
2184
1943
  } else if ('undefined' != typeof(params.page)) {
2185
1944
  // $$$ this assumes page numbers are unique
2186
- if (params.page != this._models.book.getPageNum(this.currentIndex())) {
1945
+ if (params.page != this.book.getPageNum(this.currentIndex())) {
2187
1946
  this.jumpToPage(params.page);
2188
1947
  }
2189
1948
  }
@@ -2217,7 +1976,7 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2217
1976
  // check there are enough pages to display
2218
1977
  // $$$ this is a workaround for the mis-feature that we can't display
2219
1978
  // short books in 2up mode
2220
- if (this._models.book.getNumLeafs() < 2) {
1979
+ if (this.book.getNumLeafs() < 2) {
2221
1980
  return false;
2222
1981
  }
2223
1982
  }
@@ -2225,31 +1984,6 @@ BookReader.prototype.canSwitchToMode = function(mode) {
2225
1984
  return true;
2226
1985
  };
2227
1986
 
2228
-
2229
- /**
2230
- * @deprecated. Use PageModel.getURISrcSet. Slated for removal in v5.
2231
- * Returns the srcset with correct URIs or void string if out of range
2232
- * Also makes the reduce argument optional
2233
- * @param {number} index
2234
- * @param {number} [reduce]
2235
- * @param {number} [rotate]
2236
- * @return {string}
2237
- */
2238
- BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2239
- const page = this._models.book.getPage(index, false);
2240
- // Synthesize page
2241
- if (!page) return "";
2242
-
2243
- // reduce not passed in
2244
- // $$$ this probably won't work for thumbnail mode
2245
- if ('undefined' == typeof(reduce)) {
2246
- reduce = page.height / this.twoPage.height;
2247
- }
2248
-
2249
- return page.getURISrcSet(reduce, rotate);
2250
- };
2251
-
2252
-
2253
1987
  /**
2254
1988
  * Returns the page URI or transparent image if out of range
2255
1989
  * Also makes the reduce argument optional
@@ -2259,7 +1993,7 @@ BookReader.prototype._getPageURISrcset = function(index, reduce, rotate) {
2259
1993
  * @return {string}
2260
1994
  */
2261
1995
  BookReader.prototype._getPageURI = function(index, reduce, rotate) {
2262
- const page = this._models.book.getPage(index, false);
1996
+ const page = this.book.getPage(index, false);
2263
1997
  // Synthesize page
2264
1998
  if (!page) return this.imagesBaseURL + "transparent.png";
2265
1999
 
@@ -2405,7 +2139,7 @@ BookReader.prototype.paramsFromCurrent = function() {
2405
2139
 
2406
2140
  // Path params
2407
2141
  const index = this.currentIndex();
2408
- const pageNum = this._models.book.getPageNum(index);
2142
+ const pageNum = this.book.getPageNum(index);
2409
2143
  if ((pageNum === 0) || pageNum) {
2410
2144
  params.page = pageNum;
2411
2145
  }
@@ -2590,11 +2324,4 @@ BookReader.prototype.$ = function(selector) {
2590
2324
  return this.refs.$br.find(selector);
2591
2325
  };
2592
2326
 
2593
- /**
2594
- * Polyfill for deprecated method
2595
- */
2596
- jQuery.curCSS = function(element, prop, val) {
2597
- return jQuery(element).css(prop, val);
2598
- };
2599
-
2600
2327
  window.BookReader = BookReader;