@internetarchive/bookreader 5.0.0-57 → 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.
- 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 = () => {
|