@internetarchive/bookreader 5.0.0-115 → 5.0.0-116
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.js +1 -43
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +49 -7
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +2 -2
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +43 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.translate.js +45 -3
- package/BookReader/plugins/plugin.translate.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/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/jsconfig.json +2 -3
- package/package.json +7 -4
- package/src/BookReader.js +8 -20
- package/src/plugins/plugin.text_selection.js +4 -90
- package/src/plugins/search/plugin.search.js +2 -0
- package/src/plugins/url/UrlPlugin.js +12 -0
- package/src/util/TextSelectionManager.js +168 -146
- package/src/util/generators.js +89 -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-116",
|
|
4
4
|
"description": "The Internet Archive BookReader.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -132,14 +132,17 @@
|
|
|
132
132
|
"test:e2e": "npm run build && npx testcafe",
|
|
133
133
|
"test:e2e:dev": "npx testcafe --live --dev",
|
|
134
134
|
"DOCS:update:test-deps": "If CI succeeds, these should be good to update",
|
|
135
|
-
"update:test-deps": "npm i @babel/eslint-parser@latest @open-wc/testing-helpers@latest @types/jest@latest eslint@7 eslint-plugin-testcafe@latest jest@latest jest-environment-jsdom@latest sinon@latest testcafe@latest",
|
|
135
|
+
"update:test-deps": "npm i @babel/eslint-parser@latest @open-wc/testing-helpers@latest @types/jest@latest eslint@7 eslint-plugin-no-jquery@latest eslint-plugin-testcafe@latest jest@latest jest-environment-jsdom@latest sinon@latest testcafe@latest",
|
|
136
136
|
"update:test-deps:test": "npm run lint && npm run test && npm run test:e2e",
|
|
137
137
|
"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",
|
|
138
138
|
"update:build-deps": "npm i @babel/core@latest @babel/preset-env@latest @babel/plugin-proposal-class-properties@latest @babel/plugin-proposal-decorators@latest babel-loader@latest core-js@latest regenerator-runtime@latest sass@latest svgo@latest webpack@latest webpack-cli@latest",
|
|
139
139
|
"update:build-deps:test": "npm run build",
|
|
140
140
|
"DOCS:update:dev-deps": "Packages used for development",
|
|
141
|
-
"update:dev-deps": "npm i @iiif/presentation-2@latest @iiif/presentation-3@latest concurrently@latest cpx2@latest http-server@latest live-server@latest",
|
|
141
|
+
"update:dev-deps": "npm i @iiif/presentation-2@latest @iiif/presentation-3@latest concurrently@latest cpx2@latest http-server@latest hypothesis@latest live-server@latest testcafe-browser-provider-browserstack@latest",
|
|
142
|
+
"DOCS:update:runtime-deps": "Core runtime dependencies; do an npm run build + visual check after updating",
|
|
143
|
+
"update:runtime-deps": "npm i @webcomponents/webcomponentsjs@latest interactjs@latest iso-language-codes@latest jquery@latest jquery-colorbox@latest jquery-ui@latest jquery-ui-touch-punch@latest jquery.browser@latest lit@latest soundmanager2@latest",
|
|
144
|
+
"update:runtime-deps:test": "npm run build",
|
|
142
145
|
"DOCS:update:ia-deps": "Packages by @internetarchive",
|
|
143
|
-
"update:ia-deps": "npm i @internetarchive/ia-activity-indicator@latest @internetarchive/ia-item-navigator@latest @internetarchive/icon-bookmark@latest @internetarchive/icon-close@latest @internetarchive/icon-dl@latest @internetarchive/icon-edit-pencil@latest @internetarchive/icon-ia-logo@latest @internetarchive/icon-magnify-minus@latest @internetarchive/icon-magnify-plus@latest @internetarchive/icon-search@latest @internetarchive/icon-share@latest @internetarchive/icon-toc@latest @internetarchive/icon-visual-adjustment@latest @internetarchive/modal-manager@latest @internetarchive/shared-resize-observer@latest"
|
|
146
|
+
"update:ia-deps": "npm i @internetarchive/bergamot-translator@latest @internetarchive/ia-activity-indicator@latest @internetarchive/ia-item-navigator@latest @internetarchive/icon-bookmark@latest @internetarchive/icon-close@latest @internetarchive/icon-dl@latest @internetarchive/icon-edit-pencil@latest @internetarchive/icon-ia-logo@latest @internetarchive/icon-magnify-minus@latest @internetarchive/icon-magnify-plus@latest @internetarchive/icon-search@latest @internetarchive/icon-share@latest @internetarchive/icon-toc@latest @internetarchive/icon-visual-adjustment@latest @internetarchive/modal-manager@latest @internetarchive/shared-resize-observer@latest"
|
|
144
147
|
}
|
|
145
148
|
}
|
package/src/BookReader.js
CHANGED
|
@@ -41,7 +41,6 @@ import { ModeThumb } from './BookReader/ModeThumb.js';
|
|
|
41
41
|
import { ImageCache } from './BookReader/ImageCache.js';
|
|
42
42
|
import { PageContainer } from './BookReader/PageContainer.js';
|
|
43
43
|
import { NAMED_REDUCE_SETS } from './BookReader/ReduceSet.js';
|
|
44
|
-
import {BookReaderTextFragment} from './util/TextSelectionManager.js';
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
46
|
* BookReader
|
|
@@ -156,6 +155,7 @@ BookReader.optionOverrides = BookReader.optionOverrides || {};
|
|
|
156
155
|
/**
|
|
157
156
|
* Setup
|
|
158
157
|
* It is separate from the constructor, so plugins can extend.
|
|
158
|
+
* @constructor
|
|
159
159
|
* @param {BookReaderOptions} options
|
|
160
160
|
*/
|
|
161
161
|
BookReader.prototype.setup = function(options) {
|
|
@@ -645,6 +645,7 @@ BookReader.prototype.init = function() {
|
|
|
645
645
|
this.pageScale = this.reduce; // preserve current reduce
|
|
646
646
|
|
|
647
647
|
const params = this.initParams();
|
|
648
|
+
this.urlPlugin?.pullFromAddressBar();
|
|
648
649
|
this.firstIndex = params.index ? params.index : 0;
|
|
649
650
|
|
|
650
651
|
// Setup Navbars and other UI
|
|
@@ -1960,6 +1961,10 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1960
1961
|
) {
|
|
1961
1962
|
const newParams = new URLSearchParams(currQueryString);
|
|
1962
1963
|
|
|
1964
|
+
// Never write back UI-only params that are consumed on load
|
|
1965
|
+
// TODO: Should ideally stick around until next URL change
|
|
1966
|
+
newParams.delete('focus');
|
|
1967
|
+
|
|
1963
1968
|
if (params.view) {
|
|
1964
1969
|
// Set ?view=theater when fullscreen
|
|
1965
1970
|
newParams.set('view', params.view);
|
|
@@ -1972,25 +1977,8 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1972
1977
|
newParams.set('q', params.search);
|
|
1973
1978
|
}
|
|
1974
1979
|
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
// Need to pull out text separately to avoid the spaces becoming encoded as +, which
|
|
1978
|
-
// the browser seems not to handle with the text fragment
|
|
1979
|
-
if (newParams.get('text')) {
|
|
1980
|
-
newParams.delete('text');
|
|
1981
|
-
textFragmentParam = BookReaderTextFragment.fromUrl(currQueryString, this.book, this.firstIndex);
|
|
1982
|
-
}
|
|
1983
|
-
|
|
1984
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
|
|
1985
|
-
// Note: This method returns the query string without the question mark.
|
|
1986
|
-
let result = newParams.toString();
|
|
1987
|
-
if (textFragmentParam) {
|
|
1988
|
-
if (result) result += '&';
|
|
1989
|
-
result += `text=${textFragmentParam.toUrlString()}`;
|
|
1990
|
-
}
|
|
1991
|
-
if (result) result = '?' + result;
|
|
1992
|
-
|
|
1993
|
-
return result;
|
|
1980
|
+
const result = newParams.toString();
|
|
1981
|
+
return result ? `?${result}` : '';
|
|
1994
1982
|
};
|
|
1995
1983
|
|
|
1996
1984
|
/**
|
|
@@ -5,6 +5,7 @@ import { applyVariables } from '../util/strings.js';
|
|
|
5
5
|
import { Cache } from '../util/cache.js';
|
|
6
6
|
import { toISO6391 } from './tts/utils.js';
|
|
7
7
|
import { BookReaderTextFragment, renderHighlight, TextSelectionManager } from '../util/TextSelectionManager.js';
|
|
8
|
+
import { genMap, lookAroundWindow, zip } from '../util/generators.js';
|
|
8
9
|
/** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */
|
|
9
10
|
/** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */
|
|
10
11
|
|
|
@@ -66,8 +67,9 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
66
67
|
this.textSelectionManager.init();
|
|
67
68
|
|
|
68
69
|
// Init text fragment
|
|
69
|
-
|
|
70
|
-
if (
|
|
70
|
+
const textParam = new URLSearchParams(location.search).get('text');
|
|
71
|
+
if (textParam) {
|
|
72
|
+
this.targetTextFragment = BookReaderTextFragment.fromString(textParam, this.br.book, this.br.firstIndex);
|
|
71
73
|
const targetTextFragment = this.targetTextFragment;
|
|
72
74
|
this.br.on('textLayerVisible', async (_, {pageContainerEl, textLayer}) => {
|
|
73
75
|
const pageIndex = targetTextFragment.pageIndex;
|
|
@@ -428,94 +430,6 @@ function augmentLine(line) {
|
|
|
428
430
|
};
|
|
429
431
|
}
|
|
430
432
|
|
|
431
|
-
/**
|
|
432
|
-
* @template T
|
|
433
|
-
* Get the i-th element of an iterable
|
|
434
|
-
* @param {Iterable<T>} iterable
|
|
435
|
-
* @param {number} index
|
|
436
|
-
*/
|
|
437
|
-
export function genAt(iterable, index) {
|
|
438
|
-
let i = 0;
|
|
439
|
-
for (const x of iterable) {
|
|
440
|
-
if (i == index) return x;
|
|
441
|
-
i++;
|
|
442
|
-
}
|
|
443
|
-
return undefined;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* @template T
|
|
448
|
-
* Generator version of filter
|
|
449
|
-
* @param {Iterable<T>} iterable
|
|
450
|
-
* @param {function(T): boolean} fn
|
|
451
|
-
*/
|
|
452
|
-
export function* genFilter(iterable, fn) {
|
|
453
|
-
for (const x of iterable) {
|
|
454
|
-
if (fn(x)) yield x;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* @template TFrom, TTo
|
|
460
|
-
* Generator version of map
|
|
461
|
-
* @param {Iterable<TFrom>} gen
|
|
462
|
-
* @param {function(TFrom): TTo} fn
|
|
463
|
-
* @returns {Iterable<TTo>}
|
|
464
|
-
*/
|
|
465
|
-
export function* genMap(gen, fn) {
|
|
466
|
-
for (const x of gen) yield fn(x);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* @template T
|
|
471
|
-
* Generator that provides a sliding window of 3 elements,
|
|
472
|
-
* prev, current, and next.
|
|
473
|
-
* @param {Iterable<T>} gen
|
|
474
|
-
* @returns {Iterable<[T | undefined, T, T | undefined]>}
|
|
475
|
-
*/
|
|
476
|
-
export function* lookAroundWindow(gen) {
|
|
477
|
-
let prev = undefined;
|
|
478
|
-
let cur = undefined;
|
|
479
|
-
let next = undefined;
|
|
480
|
-
for (const x of gen) {
|
|
481
|
-
if (typeof cur !== 'undefined') {
|
|
482
|
-
next = x;
|
|
483
|
-
yield [prev, cur, next];
|
|
484
|
-
}
|
|
485
|
-
prev = cur;
|
|
486
|
-
cur = x;
|
|
487
|
-
next = undefined;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
if (typeof cur !== 'undefined') {
|
|
491
|
-
yield [prev, cur, next];
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* @template T1, T2
|
|
497
|
-
* Lazy zip implementation to avoid importing lodash
|
|
498
|
-
* Expects iterators to be of the same length
|
|
499
|
-
* @param {Iterable<T1>} gen1
|
|
500
|
-
* @param {Iterable<T2>} gen2
|
|
501
|
-
* @returns {Iterable<[T1, T2]>}
|
|
502
|
-
*/
|
|
503
|
-
export function* zip(gen1, gen2) {
|
|
504
|
-
const it1 = gen1[Symbol.iterator]();
|
|
505
|
-
const it2 = gen2[Symbol.iterator]();
|
|
506
|
-
while (true) {
|
|
507
|
-
const r1 = it1.next();
|
|
508
|
-
const r2 = it2.next();
|
|
509
|
-
if (r1.done && r2.done) {
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
if (r1.done || r2.done) {
|
|
513
|
-
throw new Error('zip: one of the iterators is done');
|
|
514
|
-
}
|
|
515
|
-
yield [r1.value, r2.value];
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
433
|
/**
|
|
520
434
|
* [left, bottom, right, top]
|
|
521
435
|
* @param {Array<[number, number, number, number]>} bounds
|
|
@@ -104,6 +104,8 @@ export class SearchPlugin extends BookReaderPlugin {
|
|
|
104
104
|
this.options.initialSearchTerm,
|
|
105
105
|
{ goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false },
|
|
106
106
|
);
|
|
107
|
+
} else if (this.br.urlPlugin?.getUrlParam('focus') === 'search') {
|
|
108
|
+
this.searchView.toggleSidebar();
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} UrlSchemaEntry
|
|
3
|
+
* @property {string} name
|
|
4
|
+
* @property {'path' | 'query_param'} position
|
|
5
|
+
* @property {string} [default]
|
|
6
|
+
* @property {string} [deprecated_for]
|
|
7
|
+
* @property {boolean} [readOnly] - If true, the param is read from the URL but never written back
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
export class UrlPlugin {
|
|
2
11
|
constructor(options = {}) {
|
|
3
12
|
this.bookReaderOptions = options;
|
|
4
13
|
|
|
5
14
|
// the canonical order of elements is important in the path and query string
|
|
15
|
+
/** @type {UrlSchemaEntry[]} */
|
|
6
16
|
this.urlSchema = [
|
|
7
17
|
{ name: 'page', position: 'path', default: 'n0' },
|
|
8
18
|
{ name: 'mode', position: 'path', default: '2up' },
|
|
@@ -11,6 +21,7 @@ export class UrlPlugin {
|
|
|
11
21
|
{ name: 'sort', position: 'query_param' },
|
|
12
22
|
{ name: 'view', position: 'query_param' },
|
|
13
23
|
{ name: 'admin', position: 'query_param' },
|
|
24
|
+
{ name: 'focus', position: 'query_param', readOnly: true },
|
|
14
25
|
];
|
|
15
26
|
|
|
16
27
|
this.urlState = {};
|
|
@@ -36,6 +47,7 @@ export class UrlPlugin {
|
|
|
36
47
|
if (schema?.deprecated_for) {
|
|
37
48
|
schema = this.urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
|
|
38
49
|
}
|
|
50
|
+
if (schema?.readOnly) return;
|
|
39
51
|
if (schema?.position == 'path') {
|
|
40
52
|
pathParams[schema?.name] = urlState[key];
|
|
41
53
|
} else {
|