@internetarchive/bookreader 5.0.0-114 → 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/474.js.map +1 -1
- package/BookReader/BookReader.css +27 -10
- package/BookReader/BookReader.js +1 -43
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +63 -39
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.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.experiments.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.iiif.js.map +1 -1
- package/BookReader/plugins/plugin.resume.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/BookReader/plugins/translator-worker.js.map +1 -1
- package/BookReader/webcomponents-bundle.js.map +1 -1
- package/jsconfig.json +2 -3
- package/package.json +41 -32
- package/src/BookReader/utils/SelectionObserver.js +4 -2
- package/src/BookReader.js +10 -21
- package/src/css/_TextSelection.scss +25 -10
- package/src/plugins/plugin.iiif.js +7 -1
- package/src/plugins/plugin.text_selection.js +4 -90
- package/src/plugins/search/plugin.search.js +2 -0
- package/src/plugins/tts/WebTTSEngine.js +2 -2
- package/src/plugins/tts/utils.js +0 -9
- package/src/plugins/url/UrlPlugin.js +12 -0
- package/src/util/TextSelectionManager.js +246 -173
- package/src/util/browserSniffing.js +9 -0
- package/src/util/generators.js +89 -0
package/jsconfig.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "es6",
|
|
4
|
-
"moduleResolution": "
|
|
4
|
+
"moduleResolution": "bundler",
|
|
5
5
|
"experimentalDecorators": true,
|
|
6
|
-
"baseUrl": ".",
|
|
7
6
|
"paths": {
|
|
8
7
|
"@/*": ["./*"]
|
|
9
8
|
}
|
|
10
9
|
},
|
|
11
10
|
"include": [
|
|
12
11
|
"src/**/*.js",
|
|
13
|
-
"tests/**/*.js",
|
|
12
|
+
"tests/jest/**/*.js",
|
|
14
13
|
],
|
|
15
14
|
"exclude": [
|
|
16
15
|
"node_modules",
|
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": [
|
|
@@ -32,21 +32,21 @@
|
|
|
32
32
|
"private": false,
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@internetarchive/bergamot-translator": "^0.4.9-ia.1",
|
|
35
|
-
"@internetarchive/ia-activity-indicator": "0.0
|
|
36
|
-
"@internetarchive/ia-item-navigator": "2.2.
|
|
37
|
-
"@internetarchive/icon-bookmark": "
|
|
38
|
-
"@internetarchive/icon-close": "1.4.
|
|
39
|
-
"@internetarchive/icon-dl": "
|
|
40
|
-
"@internetarchive/icon-edit-pencil": "
|
|
41
|
-
"@internetarchive/icon-ia-logo": "1.4.
|
|
42
|
-
"@internetarchive/icon-magnify-minus": "
|
|
43
|
-
"@internetarchive/icon-magnify-plus": "
|
|
44
|
-
"@internetarchive/icon-search": "
|
|
45
|
-
"@internetarchive/icon-share": "1.4.
|
|
46
|
-
"@internetarchive/icon-toc": "
|
|
47
|
-
"@internetarchive/icon-visual-adjustment": "
|
|
48
|
-
"@internetarchive/modal-manager": "2.0.
|
|
49
|
-
"@internetarchive/shared-resize-observer": "
|
|
35
|
+
"@internetarchive/ia-activity-indicator": "1.0.0",
|
|
36
|
+
"@internetarchive/ia-item-navigator": "2.2.3",
|
|
37
|
+
"@internetarchive/icon-bookmark": "1.4.1",
|
|
38
|
+
"@internetarchive/icon-close": "1.4.1",
|
|
39
|
+
"@internetarchive/icon-dl": "1.4.1",
|
|
40
|
+
"@internetarchive/icon-edit-pencil": "1.4.1",
|
|
41
|
+
"@internetarchive/icon-ia-logo": "1.4.1",
|
|
42
|
+
"@internetarchive/icon-magnify-minus": "1.4.1",
|
|
43
|
+
"@internetarchive/icon-magnify-plus": "1.4.1",
|
|
44
|
+
"@internetarchive/icon-search": "1.4.1",
|
|
45
|
+
"@internetarchive/icon-share": "1.4.1",
|
|
46
|
+
"@internetarchive/icon-toc": "1.4.1",
|
|
47
|
+
"@internetarchive/icon-visual-adjustment": "1.4.1",
|
|
48
|
+
"@internetarchive/modal-manager": "2.0.6",
|
|
49
|
+
"@internetarchive/shared-resize-observer": "0.2.0",
|
|
50
50
|
"interactjs": "^1.10.18",
|
|
51
51
|
"iso-language-codes": "2.0.0",
|
|
52
52
|
"jquery": "3.6.1",
|
|
@@ -58,36 +58,36 @@
|
|
|
58
58
|
"soundmanager2": "2.97.20170602"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@babel/core": "7.29.
|
|
62
|
-
"@babel/eslint-parser": "7.
|
|
61
|
+
"@babel/core": "7.29.7",
|
|
62
|
+
"@babel/eslint-parser": "7.29.7",
|
|
63
63
|
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
64
|
-
"@babel/plugin-proposal-decorators": "7.29.
|
|
65
|
-
"@babel/preset-env": "7.29.
|
|
66
|
-
"@iiif/presentation-2": "
|
|
67
|
-
"@iiif/presentation-3": "
|
|
64
|
+
"@babel/plugin-proposal-decorators": "7.29.7",
|
|
65
|
+
"@babel/preset-env": "7.29.7",
|
|
66
|
+
"@iiif/presentation-2": "1.0.4",
|
|
67
|
+
"@iiif/presentation-3": "2.2.3",
|
|
68
68
|
"@open-wc/testing-helpers": "3.0.1",
|
|
69
69
|
"@types/jest": "30.0.0",
|
|
70
70
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
|
71
71
|
"babel-loader": "10.1.1",
|
|
72
|
-
"concurrently": "
|
|
72
|
+
"concurrently": "10.0.3",
|
|
73
73
|
"core-js": "3.49.0",
|
|
74
|
-
"cpx2": "
|
|
74
|
+
"cpx2": "9.0.0",
|
|
75
75
|
"eslint": "7.32.0",
|
|
76
76
|
"eslint-plugin-no-jquery": "^2.7.0",
|
|
77
77
|
"eslint-plugin-testcafe": "0.2.1",
|
|
78
78
|
"http-server": "14.1.1",
|
|
79
79
|
"hypothesis": "^1.1627.0",
|
|
80
|
-
"jest": "30.
|
|
81
|
-
"jest-environment-jsdom": "30.
|
|
80
|
+
"jest": "30.4.2",
|
|
81
|
+
"jest-environment-jsdom": "30.4.1",
|
|
82
82
|
"live-server": "1.2.2",
|
|
83
83
|
"regenerator-runtime": "0.14.1",
|
|
84
|
-
"sass": "1.
|
|
85
|
-
"sinon": "
|
|
84
|
+
"sass": "1.100.0",
|
|
85
|
+
"sinon": "22.0.0",
|
|
86
86
|
"svgo": "4.0.1",
|
|
87
87
|
"testcafe": "3.7.4",
|
|
88
88
|
"testcafe-browser-provider-browserstack": "1.15.2",
|
|
89
|
-
"webpack": "5.
|
|
90
|
-
"webpack-cli": "7.0.
|
|
89
|
+
"webpack": "5.107.2",
|
|
90
|
+
"webpack-cli": "7.0.3"
|
|
91
91
|
},
|
|
92
92
|
"jest": {
|
|
93
93
|
"testEnvironment": "jsdom",
|
|
@@ -132,8 +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
|
+
"update:test-deps:test": "npm run lint && npm run test && npm run test:e2e",
|
|
136
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",
|
|
137
|
-
"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"
|
|
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
|
+
"update:build-deps:test": "npm run build",
|
|
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 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",
|
|
145
|
+
"DOCS:update:ia-deps": "Packages by @internetarchive",
|
|
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"
|
|
138
147
|
}
|
|
139
148
|
}
|
|
@@ -4,7 +4,7 @@ export class SelectionObserver {
|
|
|
4
4
|
startedInSelector = false;
|
|
5
5
|
/** @type {HTMLElement} */
|
|
6
6
|
target = null;
|
|
7
|
-
/** @type {Node} */
|
|
7
|
+
/** @type {Node | null} */
|
|
8
8
|
lastKnownFocusNode = null;
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -30,6 +30,7 @@ export class SelectionObserver {
|
|
|
30
30
|
|
|
31
31
|
_onSelectionChange = () => {
|
|
32
32
|
const sel = window.getSelection();
|
|
33
|
+
if (!sel) return;
|
|
33
34
|
|
|
34
35
|
if (!this.selecting && sel.toString()) {
|
|
35
36
|
const target = $(sel.anchorNode).closest(this.selector)[0];
|
|
@@ -40,13 +41,14 @@ export class SelectionObserver {
|
|
|
40
41
|
this.handler('started', this.target);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
if (this.selecting &&
|
|
44
|
+
if (this.selecting && this.lastKnownFocusNode != sel.focusNode && sel.toString() && !sel.isCollapsed) {
|
|
44
45
|
this.lastKnownFocusNode = sel.focusNode;
|
|
45
46
|
this.handler('changed', this.target);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
if (this.selecting && (sel.isCollapsed || !sel.toString() || !$(sel.anchorNode).closest(this.selector)[0])) {
|
|
49
50
|
this.selecting = false;
|
|
51
|
+
this.lastKnownFocusNode = null;
|
|
50
52
|
this.handler('cleared', this.target);
|
|
51
53
|
}
|
|
52
54
|
};
|
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
|
|
@@ -151,11 +150,12 @@ BookReader.defaultOptions = DEFAULT_OPTIONS;
|
|
|
151
150
|
* @type {BookReaderOptions}
|
|
152
151
|
* This is here, just in case you need to absolutely override an option.
|
|
153
152
|
*/
|
|
154
|
-
BookReader.optionOverrides = {};
|
|
153
|
+
BookReader.optionOverrides = BookReader.optionOverrides || {};
|
|
155
154
|
|
|
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
|
|
@@ -852,6 +853,7 @@ BookReader.prototype.setupKeyListeners = function () {
|
|
|
852
853
|
|
|
853
854
|
// Ignore if modifiers are active.
|
|
854
855
|
if (e.getModifierState('Control') ||
|
|
856
|
+
e.getModifierState('Shift') ||
|
|
855
857
|
e.getModifierState('Alt') ||
|
|
856
858
|
e.getModifierState('Meta') ||
|
|
857
859
|
e.getModifierState('Win') /* hack for IE */) {
|
|
@@ -1959,6 +1961,10 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1959
1961
|
) {
|
|
1960
1962
|
const newParams = new URLSearchParams(currQueryString);
|
|
1961
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
|
+
|
|
1962
1968
|
if (params.view) {
|
|
1963
1969
|
// Set ?view=theater when fullscreen
|
|
1964
1970
|
newParams.set('view', params.view);
|
|
@@ -1971,25 +1977,8 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1971
1977
|
newParams.set('q', params.search);
|
|
1972
1978
|
}
|
|
1973
1979
|
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
// Need to pull out text separately to avoid the spaces becoming encoded as +, which
|
|
1977
|
-
// the browser seems not to handle with the text fragment
|
|
1978
|
-
if (newParams.get('text')) {
|
|
1979
|
-
newParams.delete('text');
|
|
1980
|
-
textFragmentParam = BookReaderTextFragment.fromUrl(currQueryString, this.book, this.firstIndex);
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
|
|
1984
|
-
// Note: This method returns the query string without the question mark.
|
|
1985
|
-
let result = newParams.toString();
|
|
1986
|
-
if (textFragmentParam) {
|
|
1987
|
-
if (result) result += '&';
|
|
1988
|
-
result += `text=${textFragmentParam.toUrlString()}`;
|
|
1989
|
-
}
|
|
1990
|
-
if (result) result = '?' + result;
|
|
1991
|
-
|
|
1992
|
-
return result;
|
|
1980
|
+
const result = newParams.toString();
|
|
1981
|
+
return result ? `?${result}` : '';
|
|
1993
1982
|
};
|
|
1994
1983
|
|
|
1995
1984
|
/**
|
|
@@ -153,7 +153,16 @@
|
|
|
153
153
|
color-scheme: dark;
|
|
154
154
|
padding: 2px;
|
|
155
155
|
overflow: hidden;
|
|
156
|
-
|
|
156
|
+
opacity: 1;
|
|
157
|
+
transition: border-radius 0.2s, opacity 0.2s;
|
|
158
|
+
|
|
159
|
+
@starting-style {
|
|
160
|
+
opacity: 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
.br-select-menu__root--scrolling {
|
|
164
|
+
opacity: 0;
|
|
165
|
+
pointer-events: none;
|
|
157
166
|
}
|
|
158
167
|
.br-select-menu__root:hover {
|
|
159
168
|
border-radius: 8px;
|
|
@@ -172,6 +181,7 @@
|
|
|
172
181
|
align-items: center;
|
|
173
182
|
border-radius: 20px;
|
|
174
183
|
font-family: inherit;
|
|
184
|
+
color: inherit;
|
|
175
185
|
border: 0;
|
|
176
186
|
transition: background-color 0.2s, border-radius 0.2s;
|
|
177
187
|
cursor: pointer;
|
|
@@ -191,18 +201,23 @@
|
|
|
191
201
|
}
|
|
192
202
|
|
|
193
203
|
.br-select-menu__label {
|
|
194
|
-
|
|
195
|
-
opacity: 0;
|
|
196
|
-
interpolate-size: allow-keywords;
|
|
197
|
-
transition: width 0.2s;
|
|
204
|
+
margin-left: 4px;
|
|
198
205
|
font-size: 12px;
|
|
199
206
|
}
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
.br-select-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
208
|
+
@media (hover: hover) {
|
|
209
|
+
.br-select-menu__label {
|
|
210
|
+
width: 0px;
|
|
211
|
+
margin-left: 0;
|
|
212
|
+
opacity: 0;
|
|
213
|
+
interpolate-size: allow-keywords;
|
|
214
|
+
transition: width 0.2s;
|
|
215
|
+
}
|
|
216
|
+
.br-select-menu__root:hover .br-select-menu__label {
|
|
217
|
+
width: auto;
|
|
218
|
+
margin-left: 4px;
|
|
219
|
+
opacity: 1;
|
|
220
|
+
}
|
|
206
221
|
}
|
|
207
222
|
|
|
208
223
|
.BRtextLayer .BRhighlight {
|
|
@@ -3,13 +3,19 @@ import { BookReaderPlugin } from '../BookReaderPlugin.js';
|
|
|
3
3
|
|
|
4
4
|
const BookReader = /** @type {typeof import('../BookReader').default} */(window.BookReader);
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @extends BookReaderPlugin<IiifPlugin['options']>
|
|
8
|
+
*/
|
|
6
9
|
export class IiifPlugin extends BookReaderPlugin {
|
|
7
10
|
options = {
|
|
8
11
|
enabled: true,
|
|
9
|
-
/** @type {import('@iiif/presentation-3').Manifest | import('@iiif/presentation-2').Manifest} */
|
|
12
|
+
/** @type {import('@iiif/presentation-3').Manifest | import('@iiif/presentation-2').Manifest | null} */
|
|
10
13
|
manifest: null,
|
|
11
14
|
}
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @param {IiifPlugin['options']} options
|
|
18
|
+
*/
|
|
13
19
|
setup(options) {
|
|
14
20
|
super.setup(options);
|
|
15
21
|
this.manifest = this.options.manifest;
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
/* global br */
|
|
2
|
-
import { isChrome, isFirefox } from '../../util/browserSniffing.js';
|
|
3
|
-
import {
|
|
2
|
+
import { isChrome, isFirefox, isAndroid } from '../../util/browserSniffing.js';
|
|
3
|
+
import { DEBUG_READ_ALOUD } from './utils.js';
|
|
4
4
|
import { promisifyEvent, sleep } from '../../BookReader/utils.js';
|
|
5
5
|
import AbstractTTSEngine from './AbstractTTSEngine.js';
|
|
6
6
|
/** @typedef {import("./AbstractTTSEngine.js").PageChunk} PageChunk */
|
package/src/plugins/tts/utils.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import langs from 'iso-language-codes';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Checks whether the current browser is on android
|
|
6
|
-
* @param {string} [userAgent]
|
|
7
|
-
* @return {boolean}
|
|
8
|
-
*/
|
|
9
|
-
export function isAndroid(userAgent = navigator.userAgent) {
|
|
10
|
-
return /android/i.test(userAgent);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
4
|
/** @type {{[lang: string]: string}} */
|
|
14
5
|
// Handle odd one-off language pairs that might show up over time
|
|
15
6
|
const specialLangs = {
|
|
@@ -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 {
|