@internetarchive/bookreader 5.0.0-57 → 5.0.0-59
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.css +110 -39
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +0 -20
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1 -1
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
- package/BookReaderDemo/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +1 -2
- package/CHANGELOG.md +8 -0
- package/babel.config.js +5 -2
- package/package.json +10 -9
- package/src/BookReader/BookModel.js +59 -1
- package/src/BookReader/Mode1Up.js +5 -0
- package/src/BookReader/Mode1UpLit.js +19 -73
- package/src/BookReader/Mode2Up.js +72 -1332
- package/src/BookReader/Mode2UpLit.js +774 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +32 -0
- package/src/BookReader/options.js +8 -2
- package/src/BookReader/utils.js +16 -0
- package/src/BookReader.js +24 -217
- package/src/css/_BRBookmarks.scss +1 -1
- package/src/css/_BRmain.scss +14 -0
- package/src/css/_BRpages.scss +113 -41
- package/src/plugins/plugin.autoplay.js +1 -6
- package/src/plugins/tts/WebTTSEngine.js +2 -2
- package/src/plugins/tts/plugin.tts.js +3 -17
- package/src/plugins/tts/utils.js +0 -16
- package/tests/e2e/helpers/base.js +20 -20
- package/tests/e2e/helpers/rightToLeft.js +4 -10
- package/tests/e2e/viewmode.test.js +10 -8
- package/tests/jest/BookReader/BookModel.test.js +25 -0
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +28 -11
- package/tests/jest/BookReader/Mode1UpLit.test.js +0 -19
- package/tests/jest/BookReader/Mode2Up.test.js +55 -225
- package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
- package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +26 -0
- package/tests/jest/BookReader/Navbar/Navbar.test.js +3 -3
- package/tests/jest/BookReader/utils.test.js +32 -1
- package/tests/jest/plugins/tts/utils.test.js +0 -34
- package/tests/jest/setup.js +3 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@internetarchive/bookreader",
|
3
|
-
"version": "5.0.0-
|
3
|
+
"version": "5.0.0-59",
|
4
4
|
"description": "The Internet Archive BookReader.",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -42,12 +42,12 @@
|
|
42
42
|
},
|
43
43
|
"devDependencies": {
|
44
44
|
"@babel/core": "7.17.9",
|
45
|
-
"@babel/eslint-parser": "7.
|
45
|
+
"@babel/eslint-parser": "7.21.3",
|
46
46
|
"@babel/plugin-proposal-class-properties": "7.16.7",
|
47
47
|
"@babel/plugin-proposal-decorators": "7.17.9",
|
48
48
|
"@babel/preset-env": "7.16.11",
|
49
|
-
"@open-wc/testing-helpers": "^2.
|
50
|
-
"@types/jest": "^29.
|
49
|
+
"@open-wc/testing-helpers": "^2.2.0",
|
50
|
+
"@types/jest": "^29.5.0",
|
51
51
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
52
52
|
"babel-loader": "8.2.5",
|
53
53
|
"codecov": "^3.8.3",
|
@@ -60,7 +60,7 @@
|
|
60
60
|
"hammerjs": "^2.0.8",
|
61
61
|
"http-server": "14.1.1",
|
62
62
|
"iso-language-codes": "1.1.0",
|
63
|
-
"jest": "
|
63
|
+
"jest": "29.5.0",
|
64
64
|
"jest-environment-jsdom": "^29.4.3",
|
65
65
|
"jquery": "3.6.1",
|
66
66
|
"jquery-colorbox": "1.6.4",
|
@@ -72,10 +72,10 @@
|
|
72
72
|
"node-fetch": "3.2.10",
|
73
73
|
"regenerator-runtime": "0.13.9",
|
74
74
|
"sass": "1.52.1",
|
75
|
-
"sinon": "
|
75
|
+
"sinon": "15.0.3",
|
76
76
|
"soundmanager2": "2.97.20170602",
|
77
77
|
"svgo": "2.8.0",
|
78
|
-
"testcafe": "
|
78
|
+
"testcafe": "2.4.0",
|
79
79
|
"testcafe-browser-provider-browserstack": "^1.13.2-alpha.1",
|
80
80
|
"webpack": "5.51.1",
|
81
81
|
"webpack-cli": "4.9.2"
|
@@ -89,7 +89,8 @@
|
|
89
89
|
"^@/(.*)$": "<rootDir>/$1"
|
90
90
|
},
|
91
91
|
"setupFiles": [
|
92
|
-
"./src/jquery-wrapper.js"
|
92
|
+
"./src/jquery-wrapper.js",
|
93
|
+
"./tests/jest/setup.js"
|
93
94
|
],
|
94
95
|
"roots": [
|
95
96
|
"<rootDir>/src/",
|
@@ -118,7 +119,7 @@
|
|
118
119
|
"test:e2e": "npm run build && npx testcafe",
|
119
120
|
"test:e2e:dev": "npx testcafe --live --dev",
|
120
121
|
"DOCS:update:test-deps": "If CI succeeds, these should be good to update",
|
121
|
-
"update:test-deps": "npm i @babel/eslint-parser@latest @open-wc/testing-helpers@latest @types/jest@latest codecov@latest eslint@
|
122
|
+
"update:test-deps": "npm i @babel/eslint-parser@latest @open-wc/testing-helpers@latest @types/jest@latest codecov@latest eslint@7 eslint-plugin-testcafe@latest jest@latest sinon@latest testcafe@latest",
|
122
123
|
"DOCS:update:build-deps": "These can cause strange changes, so do an npm run build + check file size (git diff --stat), and check the site is as expected",
|
123
124
|
"update:build-deps": "npm i @babel/core@latest @babel/preset-env@latest babel-loader@latest core-js@latest regenerator-runtime@latest sass@latest svgo@latest webpack@latest webpack-cli@latest",
|
124
125
|
"codecov": "npx codecov"
|
@@ -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.
|
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:
|
@@ -58,6 +58,11 @@ export class Mode1Up {
|
|
58
58
|
});
|
59
59
|
}
|
60
60
|
this.mode1UpLit.jumpToIndex(startLeaf);
|
61
|
+
setTimeout(() => {
|
62
|
+
// Must explicitly call updateVisibleRegion, since no
|
63
|
+
// scroll event seems to fire.
|
64
|
+
this.mode1UpLit.updateVisibleRegion();
|
65
|
+
});
|
61
66
|
});
|
62
67
|
this.br.updateBrClasses();
|
63
68
|
}
|
@@ -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,
|
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
|
-
/** @
|
45
|
-
|
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);
|
@@ -203,15 +195,19 @@ export class Mode1UpLit extends LitElement {
|
|
203
195
|
}
|
204
196
|
if (changedProps.has('visiblePages')) {
|
205
197
|
this.throttledUpdateRenderedPages();
|
206
|
-
|
207
|
-
|
208
|
-
|
198
|
+
if (this.visiblePages.length) {
|
199
|
+
// unclear why this is ever really happening
|
200
|
+
this.br.displayedIndices = this.visiblePages.map(p => p.index);
|
201
|
+
this.br.updateFirstIndex(this.br.displayedIndices[0]);
|
202
|
+
this.br._components.navbar.updateNavIndexThrottled();
|
203
|
+
}
|
209
204
|
}
|
210
205
|
if (changedProps.has('scale')) {
|
211
206
|
const oldVal = changedProps.get('scale');
|
212
207
|
// Need to set this scale to actually scale the pages
|
213
208
|
this.$visibleWorld.style.transform = `scale(${this.scale})`;
|
214
|
-
this.updateViewportOnZoom(this.scale, oldVal);
|
209
|
+
this.smoothZoomer.updateViewportOnZoom(this.scale, oldVal);
|
210
|
+
this.updateVisibleRegion();
|
215
211
|
// Need to set this scale to update the world size, so the scrollbar gets the correct size
|
216
212
|
this.$world.style.transform = `scale(${this.scale})`;
|
217
213
|
}
|
@@ -241,25 +237,6 @@ export class Mode1UpLit extends LitElement {
|
|
241
237
|
return this;
|
242
238
|
}
|
243
239
|
|
244
|
-
/************** COORDINATE SPACE CONVERTERS **************/
|
245
|
-
/**
|
246
|
-
* There are a few different "coordinate spaces" at play in BR:
|
247
|
-
* (1) World units: i.e. inches. Unless otherwise stated, all computations
|
248
|
-
* are done in world units.
|
249
|
-
* (2) Rendered Pixels: i.e. img.width = '300'. Note this does _not_ take
|
250
|
-
* into account zoom scaling.
|
251
|
-
* (3) Visible Pixels: Just rendered pixels, but taking into account scaling.
|
252
|
-
*/
|
253
|
-
|
254
|
-
worldUnitsToRenderedPixels = (/** @type {number} */inches) => inches * this.screenDPI / this.realWorldReduce;
|
255
|
-
renderedPixelsToWorldUnits = (/** @type {number} */px) => px * this.realWorldReduce / this.screenDPI;
|
256
|
-
|
257
|
-
renderedPixelsToVisiblePixels = (/** @type {number} */px) => px * this.scale;
|
258
|
-
visiblePixelsToRenderedPixels = (/** @type {number} */px) => px / this.scale;
|
259
|
-
|
260
|
-
worldUnitsToVisiblePixels = (/** @type {number} */px) => this.renderedPixelsToVisiblePixels(this.worldUnitsToRenderedPixels(px));
|
261
|
-
visiblePixelsToWorldUnits = (/** @type {number} */px) => this.renderedPixelsToWorldUnits(this.visiblePixelsToRenderedPixels(px));
|
262
|
-
|
263
240
|
/************** RENDERING **************/
|
264
241
|
|
265
242
|
/** @override */
|
@@ -283,9 +260,9 @@ export class Mode1UpLit extends LitElement {
|
|
283
260
|
|
284
261
|
/** @param {PageModel} page */
|
285
262
|
renderPage = (page) => {
|
286
|
-
const wToR = this.worldUnitsToRenderedPixels;
|
287
|
-
const wToV = this.worldUnitsToVisiblePixels;
|
288
|
-
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);
|
289
266
|
|
290
267
|
const width = wToR(page.widthInches);
|
291
268
|
const height = wToR(page.heightInches);
|
@@ -320,7 +297,7 @@ export class Mode1UpLit extends LitElement {
|
|
320
297
|
// Note: scrollTop, and clientWidth all are in visible space;
|
321
298
|
// i.e. they are affects by the CSS transforms.
|
322
299
|
|
323
|
-
const vToW = this.visiblePixelsToWorldUnits;
|
300
|
+
const vToW = this.coordSpace.visiblePixelsToWorldUnits;
|
324
301
|
this.visibleRegion = {
|
325
302
|
top: vToW(scrollTop),
|
326
303
|
height: vToW(clientHeight),
|
@@ -372,7 +349,7 @@ export class Mode1UpLit extends LitElement {
|
|
372
349
|
*/
|
373
350
|
computeDefaultScale(page) {
|
374
351
|
// Default to real size if it fits, otherwise default to full width
|
375
|
-
const containerWidthIn = this.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
|
352
|
+
const containerWidthIn = this.coordSpace.visiblePixelsToWorldUnits(this.htmlDimensionsCacher.clientWidth);
|
376
353
|
return Math.min(1, containerWidthIn / (page.widthInches + 2 * this.SPACING_IN)) || 1;
|
377
354
|
}
|
378
355
|
|
@@ -396,37 +373,6 @@ export class Mode1UpLit extends LitElement {
|
|
396
373
|
});
|
397
374
|
}
|
398
375
|
|
399
|
-
/************** ZOOMING LOGIC **************/
|
400
|
-
|
401
|
-
/**
|
402
|
-
* @param {number} newScale
|
403
|
-
* @param {number} oldScale
|
404
|
-
*/
|
405
|
-
updateViewportOnZoom(newScale, oldScale) {
|
406
|
-
const container = this;
|
407
|
-
const { scrollTop: T, scrollLeft: L } = container;
|
408
|
-
const W = this.htmlDimensionsCacher.clientWidth;
|
409
|
-
const H = this.htmlDimensionsCacher.clientHeight;
|
410
|
-
|
411
|
-
// Scale factor change
|
412
|
-
const F = newScale / oldScale;
|
413
|
-
|
414
|
-
// Where in the viewport the zoom is centered on
|
415
|
-
const XPOS = this.scaleCenter.x;
|
416
|
-
const YPOS = this.scaleCenter.y;
|
417
|
-
const oldCenter = {
|
418
|
-
x: L + XPOS * W,
|
419
|
-
y: T + YPOS * H,
|
420
|
-
};
|
421
|
-
const newCenter = {
|
422
|
-
x: F * oldCenter.x,
|
423
|
-
y: F * oldCenter.y,
|
424
|
-
};
|
425
|
-
container.scrollTop = newCenter.y - YPOS * H;
|
426
|
-
container.scrollLeft = newCenter.x - XPOS * W;
|
427
|
-
this.updateVisibleRegion();
|
428
|
-
}
|
429
|
-
|
430
376
|
/************** INPUT HANDLERS **************/
|
431
377
|
|
432
378
|
attachScrollListeners = () => {
|