@internetarchive/bookreader 5.0.0-58 → 5.0.0-59

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 (50) hide show
  1. package/BookReader/BookReader.css +110 -39
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.LICENSE.txt +0 -20
  4. package/BookReader/BookReader.js.map +1 -1
  5. package/BookReader/ia-bookreader-bundle.js +1 -1
  6. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  7. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  8. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  9. package/BookReader/plugins/plugin.autoplay.js +1 -1
  10. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  11. package/BookReader/plugins/plugin.resume.js +1 -1
  12. package/BookReader/plugins/plugin.resume.js.map +1 -1
  13. package/BookReader/plugins/plugin.tts.js +1 -1
  14. package/BookReader/plugins/plugin.tts.js.map +1 -1
  15. package/BookReader/plugins/plugin.url.js +1 -1
  16. package/BookReader/plugins/plugin.url.js.map +1 -1
  17. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  18. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  19. package/BookReaderDemo/IADemoBr.js +1 -2
  20. package/CHANGELOG.md +4 -0
  21. package/package.json +1 -1
  22. package/src/BookReader/BookModel.js +59 -1
  23. package/src/BookReader/Mode1UpLit.js +13 -70
  24. package/src/BookReader/Mode2Up.js +72 -1332
  25. package/src/BookReader/Mode2UpLit.js +774 -0
  26. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  27. package/src/BookReader/ModeSmoothZoom.js +32 -0
  28. package/src/BookReader/options.js +8 -2
  29. package/src/BookReader/utils.js +16 -0
  30. package/src/BookReader.js +24 -217
  31. package/src/css/_BRBookmarks.scss +1 -1
  32. package/src/css/_BRmain.scss +14 -0
  33. package/src/css/_BRpages.scss +113 -41
  34. package/src/plugins/plugin.autoplay.js +1 -6
  35. package/src/plugins/tts/WebTTSEngine.js +2 -2
  36. package/src/plugins/tts/plugin.tts.js +3 -17
  37. package/src/plugins/tts/utils.js +0 -16
  38. package/tests/e2e/helpers/base.js +20 -20
  39. package/tests/e2e/helpers/rightToLeft.js +4 -10
  40. package/tests/e2e/viewmode.test.js +10 -8
  41. package/tests/jest/BookReader/BookModel.test.js +25 -0
  42. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +28 -11
  43. package/tests/jest/BookReader/Mode1UpLit.test.js +0 -19
  44. package/tests/jest/BookReader/Mode2Up.test.js +55 -225
  45. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  46. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  47. package/tests/jest/BookReader/ModeSmoothZoom.test.js +26 -0
  48. package/tests/jest/BookReader/Navbar/Navbar.test.js +3 -3
  49. package/tests/jest/BookReader/utils.test.js +32 -1
  50. package/tests/jest/plugins/tts/utils.test.js +0 -34
@@ -23,6 +23,8 @@ export class BookModel {
23
23
  this.br = br;
24
24
  this.reduceSet = br.reduceSet;
25
25
  this.ppi = br.options?.ppi ?? DEFAULT_OPTIONS.ppi;
26
+ /** @type {'lr' | 'rl'} Page progression */
27
+ this.pageProgression = br.options?.pageProgression ?? DEFAULT_OPTIONS.pageProgression;
26
28
 
27
29
  /** @type {{width: number, height: number}} memoize storage */
28
30
  this._medianPageSize = null;
@@ -197,7 +199,7 @@ export class BookModel {
197
199
  * @return {[PageIndex, PageIndex]} eg [0, 1]
198
200
  */
199
201
  getSpreadIndices(pindex) {
200
- if (this.br.pageProgression == 'rl') {
202
+ if (this.pageProgression == 'rl') {
201
203
  return this.getPageSide(pindex) == 'R' ? [pindex + 1, pindex] : [pindex, pindex - 1];
202
204
  } else {
203
205
  return this.getPageSide(pindex) == 'L' ? [pindex, pindex + 1] : [pindex - 1, pindex];
@@ -408,6 +410,42 @@ export class PageModel {
408
410
  return this.findNext();
409
411
  }
410
412
 
413
+ /** @type {PageModel | null} */
414
+ get left() {
415
+ return this.book.pageProgression === 'lr' ? this.prev : this.next;
416
+ }
417
+
418
+ /** @type {PageModel | null} */
419
+ get right() {
420
+ return this.book.pageProgression === 'lr' ? this.next : this.prev;
421
+ }
422
+
423
+ /**
424
+ * @type {{left: PageModel | null, right: PageModel | null}}
425
+ */
426
+ get spread() {
427
+ return {
428
+ left: this.pageSide === 'L' ? this : this.left,
429
+ right: this.pageSide === 'R' ? this : this.right,
430
+ };
431
+ }
432
+
433
+ /**
434
+ * @param {number} pages
435
+ */
436
+ goLeft(pages) {
437
+ const newIndex = this.book.pageProgression === 'lr' ? this.index - pages : this.index + pages;
438
+ return this.book.getPage(newIndex);
439
+ }
440
+
441
+ /**
442
+ * @param {number} pages
443
+ */
444
+ goRight(pages) {
445
+ const newIndex = this.book.pageProgression === 'lr' ? this.index + pages : this.index - pages;
446
+ return this.book.getPage(newIndex);
447
+ }
448
+
411
449
  /**
412
450
  * @param {number} reduce
413
451
  * @param {number} rotate
@@ -469,6 +507,26 @@ export class PageModel {
469
507
  return new PageModel(this.book, this.index - 1);
470
508
  }
471
509
  }
510
+
511
+ /**
512
+ * @param {object} [arg0]
513
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
514
+ * of a series of unviewable pages instead of each page
515
+ * @return {PageModel|void}
516
+ */
517
+ findLeft({ combineConsecutiveUnviewables = false } = {}) {
518
+ return this.book.pageProgression === 'lr' ? this.findPrev({ combineConsecutiveUnviewables }) : this.findNext({ combineConsecutiveUnviewables });
519
+ }
520
+
521
+ /**
522
+ * @param {object} [arg0]
523
+ * @param {boolean} [arg0.combineConsecutiveUnviewables] Whether to only yield the first page
524
+ * of a series of unviewable pages instead of each page
525
+ * @return {PageModel|void}
526
+ */
527
+ findRight({ combineConsecutiveUnviewables = false } = {}) {
528
+ return this.book.pageProgression === 'lr' ? this.findNext({ combineConsecutiveUnviewables }) : this.findPrev({ combineConsecutiveUnviewables });
529
+ }
472
530
  }
473
531
 
474
532
  // There are a few main ways we can reference a specific page in a book:
@@ -3,9 +3,10 @@ import { customElement, property, query } from 'lit/decorators.js';
3
3
  import {LitElement, html} from 'lit';
4
4
  import { styleMap } from 'lit/directives/style-map.js';
5
5
  import { ModeSmoothZoom } from './ModeSmoothZoom';
6
- import { arrChanged, calcScreenDPI, genToArray, sum, throttle } from './utils';
6
+ import { arrChanged, genToArray, sum, throttle } from './utils';
7
7
  import { HTMLDimensionsCacher } from "./utils/HTMLDimensionsCacher";
8
8
  import { ScrollClassAdder } from './utils/ScrollClassAdder';
9
+ import { ModeCoordinateSpace } from './ModeCoordinateSpace';
9
10
  /** @typedef {import('./BookModel').BookModel} BookModel */
10
11
  /** @typedef {import('./BookModel').PageIndex} PageIndex */
11
12
  /** @typedef {import('./BookModel').PageModel} PageModel */
@@ -41,17 +42,8 @@ export class Mode1UpLit extends LitElement {
41
42
 
42
43
  /************** SCALE-RELATED PROPERTIES **************/
43
44
 
44
- /** @private */
45
- screenDPI = calcScreenDPI();
46
-
47
- /**
48
- * How much smaller the rendered pages are than the real-world item
49
- *
50
- * Mode1Up doesn't use the br.reduce because it is DPI aware. The reduction factor
51
- * of a given leaf can change (since leaves can have different DPIs), but the real-world
52
- * reduction is constant throughout.
53
- */
54
- realWorldReduce = 1;
45
+ /** @type {ModeCoordinateSpace} Manage conversion between coordinates */
46
+ coordSpace = new ModeCoordinateSpace(this);
55
47
 
56
48
  @property({ type: Number })
57
49
  scale = 1;
@@ -95,7 +87,7 @@ export class Mode1UpLit extends LitElement {
95
87
  worldDimensions = { width: 100, height: 100 };
96
88
 
97
89
  get worldStyle() {
98
- const wToR = this.worldUnitsToRenderedPixels;
90
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
99
91
  return {
100
92
  width: wToR(this.worldDimensions.width) + "px",
101
93
  height: wToR(this.worldDimensions.height) + "px",
@@ -139,7 +131,7 @@ export class Mode1UpLit extends LitElement {
139
131
  if (smooth) {
140
132
  this.style.scrollBehavior = 'smooth';
141
133
  }
142
- this.scrollTop = this.worldUnitsToVisiblePixels(this.pageTops[index] - this.SPACING_IN / 2);
134
+ this.scrollTop = this.coordSpace.worldUnitsToVisiblePixels(this.pageTops[index] - this.SPACING_IN / 2);
143
135
  // TODO: Also h center?
144
136
  if (smooth) {
145
137
  setTimeout(() => this.style.scrollBehavior = '', 100);
@@ -214,7 +206,8 @@ export class Mode1UpLit extends LitElement {
214
206
  const oldVal = changedProps.get('scale');
215
207
  // Need to set this scale to actually scale the pages
216
208
  this.$visibleWorld.style.transform = `scale(${this.scale})`;
217
- this.updateViewportOnZoom(this.scale, oldVal);
209
+ this.smoothZoomer.updateViewportOnZoom(this.scale, oldVal);
210
+ this.updateVisibleRegion();
218
211
  // Need to set this scale to update the world size, so the scrollbar gets the correct size
219
212
  this.$world.style.transform = `scale(${this.scale})`;
220
213
  }
@@ -244,25 +237,6 @@ export class Mode1UpLit extends LitElement {
244
237
  return this;
245
238
  }
246
239
 
247
- /************** COORDINATE SPACE CONVERTERS **************/
248
- /**
249
- * There are a few different "coordinate spaces" at play in BR:
250
- * (1) World units: i.e. inches. Unless otherwise stated, all computations
251
- * are done in world units.
252
- * (2) Rendered Pixels: i.e. img.width = '300'. Note this does _not_ take
253
- * into account zoom scaling.
254
- * (3) Visible Pixels: Just rendered pixels, but taking into account scaling.
255
- */
256
-
257
- worldUnitsToRenderedPixels = (/** @type {number} */inches) => inches * this.screenDPI / this.realWorldReduce;
258
- renderedPixelsToWorldUnits = (/** @type {number} */px) => px * this.realWorldReduce / this.screenDPI;
259
-
260
- renderedPixelsToVisiblePixels = (/** @type {number} */px) => px * this.scale;
261
- visiblePixelsToRenderedPixels = (/** @type {number} */px) => px / this.scale;
262
-
263
- worldUnitsToVisiblePixels = (/** @type {number} */px) => this.renderedPixelsToVisiblePixels(this.worldUnitsToRenderedPixels(px));
264
- visiblePixelsToWorldUnits = (/** @type {number} */px) => this.renderedPixelsToWorldUnits(this.visiblePixelsToRenderedPixels(px));
265
-
266
240
  /************** RENDERING **************/
267
241
 
268
242
  /** @override */
@@ -286,9 +260,9 @@ export class Mode1UpLit extends LitElement {
286
260
 
287
261
  /** @param {PageModel} page */
288
262
  renderPage = (page) => {
289
- const wToR = this.worldUnitsToRenderedPixels;
290
- const wToV = this.worldUnitsToVisiblePixels;
291
- const containerWidth = this.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
263
+ const wToR = this.coordSpace.worldUnitsToRenderedPixels;
264
+ const wToV = this.coordSpace.worldUnitsToVisiblePixels;
265
+ const containerWidth = this.coordSpace.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
292
266
 
293
267
  const width = wToR(page.widthInches);
294
268
  const height = wToR(page.heightInches);
@@ -323,7 +297,7 @@ export class Mode1UpLit extends LitElement {
323
297
  // Note: scrollTop, and clientWidth all are in visible space;
324
298
  // i.e. they are affects by the CSS transforms.
325
299
 
326
- const vToW = this.visiblePixelsToWorldUnits;
300
+ const vToW = this.coordSpace.visiblePixelsToWorldUnits;
327
301
  this.visibleRegion = {
328
302
  top: vToW(scrollTop),
329
303
  height: vToW(clientHeight),
@@ -375,7 +349,7 @@ export class Mode1UpLit extends LitElement {
375
349
  */
376
350
  computeDefaultScale(page) {
377
351
  // Default to real size if it fits, otherwise default to full width
378
- const containerWidthIn = this.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
352
+ const containerWidthIn = this.coordSpace.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
379
353
  return Math.min(1, containerWidthIn / (page.widthInches + 2 * this.SPACING_IN)) || 1;
380
354
  }
381
355
 
@@ -399,37 +373,6 @@ export class Mode1UpLit extends LitElement {
399
373
  });
400
374
  }
401
375
 
402
- /************** ZOOMING LOGIC **************/
403
-
404
- /**
405
- * @param {number} newScale
406
- * @param {number} oldScale
407
- */
408
- updateViewportOnZoom(newScale, oldScale) {
409
- const container = this;
410
- const { scrollTop: T, scrollLeft: L } = container;
411
- const W = this.htmlDimensionsCacher.clientWidth;
412
- const H = this.htmlDimensionsCacher.clientHeight;
413
-
414
- // Scale factor change
415
- const F = newScale / oldScale;
416
-
417
- // Where in the viewport the zoom is centered on
418
- const XPOS = this.scaleCenter.x;
419
- const YPOS = this.scaleCenter.y;
420
- const oldCenter = {
421
- x: L + XPOS * W,
422
- y: T + YPOS * H,
423
- };
424
- const newCenter = {
425
- x: F * oldCenter.x,
426
- y: F * oldCenter.y,
427
- };
428
- container.scrollTop = newCenter.y - YPOS * H;
429
- container.scrollLeft = newCenter.x - XPOS * W;
430
- this.updateVisibleRegion();
431
- }
432
-
433
376
  /************** INPUT HANDLERS **************/
434
377
 
435
378
  attachScrollListeners = () => {