@internetarchive/bookreader 5.0.0-50 → 5.0.0-52
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 -1
- 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.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +14 -1
- package/src/BookReader.js +39 -7
- package/src/plugins/tts/WebTTSEngine.js +21 -2
- package/tests/jest/BookReader.test.js +31 -0
- package/tests/jest/plugins/tts/WebTTSEngine.test.js +47 -1
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -137,7 +137,7 @@ class IABookmarks extends LitElement {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
setup() {
|
|
140
|
-
this.api.identifier = this.
|
|
140
|
+
this.api.identifier = this.getIdentifier();
|
|
141
141
|
if (this.displayMode === 'login') {
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
@@ -145,6 +145,19 @@ class IABookmarks extends LitElement {
|
|
|
145
145
|
this.setBREventListeners();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
/**
|
|
149
|
+
* get identifier for current book including sub-files
|
|
150
|
+
*
|
|
151
|
+
* @returns Identifer
|
|
152
|
+
*/
|
|
153
|
+
getIdentifier() {
|
|
154
|
+
if (this.bookreader.bookId !== this.bookreader.subPrefix) {
|
|
155
|
+
return `${this.bookreader.bookId}/${this.bookreader.subPrefix}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return this.bookreader.bookId;
|
|
159
|
+
}
|
|
160
|
+
|
|
148
161
|
updateDisplay() {
|
|
149
162
|
if (this.displayMode === 'bookmarks') {
|
|
150
163
|
this.fetchUserBookmarks();
|
package/src/BookReader.js
CHANGED
|
@@ -455,16 +455,18 @@ BookReader.prototype.readQueryString = function() {
|
|
|
455
455
|
* @return {number} the mode
|
|
456
456
|
*/
|
|
457
457
|
BookReader.prototype.getInitialMode = function(params) {
|
|
458
|
-
// Use params or browser width to set view mode
|
|
459
|
-
const windowWidth = $(window).width();
|
|
460
458
|
let nextMode;
|
|
459
|
+
|
|
460
|
+
// if mobile breakpoint, we always show this.constMode1up mode
|
|
461
|
+
const ifMobileBreakpoint = () => {
|
|
462
|
+
// Use params or browser width to set view mode
|
|
463
|
+
const windowWidth = $(window).width();
|
|
464
|
+
return windowWidth && windowWidth <= this.onePageMinBreakpoint;
|
|
465
|
+
};
|
|
461
466
|
if ('undefined' != typeof(params.mode)) {
|
|
462
467
|
nextMode = params.mode;
|
|
463
|
-
} else if (this.ui == 'full'
|
|
464
|
-
|
|
465
|
-
&& windowWidth <= this.onePageMinBreakpoint
|
|
466
|
-
) {
|
|
467
|
-
// In full mode, we set the default based on width
|
|
468
|
+
} else if ((this.ui == 'full' && this.isFullscreenActive) || ifMobileBreakpoint()) {
|
|
469
|
+
// In full mode OR device width, we set the default based on width
|
|
468
470
|
nextMode = this.constMode1up;
|
|
469
471
|
} else {
|
|
470
472
|
nextMode = this.constMode2up;
|
|
@@ -473,6 +475,36 @@ BookReader.prototype.getInitialMode = function(params) {
|
|
|
473
475
|
if (!this.canSwitchToMode(nextMode)) {
|
|
474
476
|
nextMode = this.constMode1up;
|
|
475
477
|
}
|
|
478
|
+
|
|
479
|
+
// override defaults mode via `options.defaults` metadata
|
|
480
|
+
if (this.options.defaults) {
|
|
481
|
+
nextMode = this.overridesBookMode();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return nextMode;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Overrides book mode using options.defaults param
|
|
489
|
+
* @return {number} the mode
|
|
490
|
+
*/
|
|
491
|
+
BookReader.prototype.overridesBookMode = function() {
|
|
492
|
+
let nextMode = 2; // set default 2 (mode/2up)
|
|
493
|
+
|
|
494
|
+
switch (this.options.defaults) {
|
|
495
|
+
case 'mode/1up':
|
|
496
|
+
nextMode = this.constMode1up;
|
|
497
|
+
break;
|
|
498
|
+
case 'mode/2up':
|
|
499
|
+
nextMode = this.constMode2up;
|
|
500
|
+
break;
|
|
501
|
+
case 'mode/thumb':
|
|
502
|
+
nextMode = this.constModeThumb;
|
|
503
|
+
break;
|
|
504
|
+
default:
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
|
|
476
508
|
return nextMode;
|
|
477
509
|
};
|
|
478
510
|
|
|
@@ -71,7 +71,22 @@ export default class WebTTSEngine extends AbstractTTSEngine {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/** @override */
|
|
74
|
-
getVoices() {
|
|
74
|
+
getVoices() {
|
|
75
|
+
const voices = speechSynthesis.getVoices();
|
|
76
|
+
if (voices.filter(v => v.default).length != 1) {
|
|
77
|
+
// iOS bug where the default system voice is sometimes
|
|
78
|
+
// missing from the list
|
|
79
|
+
voices.unshift({
|
|
80
|
+
voiceURI: 'bookreader.SystemDefault',
|
|
81
|
+
name: 'System Default',
|
|
82
|
+
// Not necessarily true, but very likely
|
|
83
|
+
lang: navigator.language,
|
|
84
|
+
default: true,
|
|
85
|
+
localService: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return voices;
|
|
89
|
+
}
|
|
75
90
|
|
|
76
91
|
/** @override */
|
|
77
92
|
createSound(chunk) {
|
|
@@ -122,7 +137,11 @@ export class WebTTSSound {
|
|
|
122
137
|
this.started = false;
|
|
123
138
|
|
|
124
139
|
this.utterance = new SpeechSynthesisUtterance(this.text.slice(this._charIndex));
|
|
125
|
-
|
|
140
|
+
// iOS bug where the default system voice is sometimes
|
|
141
|
+
// missing from the list
|
|
142
|
+
if (this.voice?.voiceURI !== 'bookreader.SystemDefault') {
|
|
143
|
+
this.utterance.voice = this.voice;
|
|
144
|
+
}
|
|
126
145
|
// Need to also set lang (for some reason); won't set voice on Chrome@Android otherwise
|
|
127
146
|
if (this.voice) this.utterance.lang = this.voice.lang;
|
|
128
147
|
this.utterance.rate = this.rate;
|
|
@@ -279,4 +279,35 @@ describe('nextReduce', () => {
|
|
|
279
279
|
expect(nextReduce(2, 'auto', SAMPLE_FACTORS).reduce).toBe(0.5);
|
|
280
280
|
});
|
|
281
281
|
});
|
|
282
|
+
|
|
283
|
+
describe('Override book page mode using options.default param', () => {
|
|
284
|
+
test('replace current mode with options.default is set mode/1up', () => {
|
|
285
|
+
br.options.defaults = 'mode/1up';
|
|
286
|
+
|
|
287
|
+
const nextModeNumber = br.overridesBookMode();
|
|
288
|
+
expect(nextModeNumber).toBe(1);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test('replace current mode with options.default is set mode/2up', () => {
|
|
292
|
+
br.options.defaults = 'mode/2up';
|
|
293
|
+
|
|
294
|
+
const nextModeNumber = br.overridesBookMode();
|
|
295
|
+
expect(nextModeNumber).toBe(2);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test('replace current mode with options.default is set mode/thumb', () => {
|
|
299
|
+
br.options.defaults = 'mode/thumb';
|
|
300
|
+
|
|
301
|
+
const nextModeNumber = br.overridesBookMode();
|
|
302
|
+
expect(nextModeNumber).toBe(3);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test('test if options.default is NOT set', () => {
|
|
306
|
+
br.options.defaults = null;
|
|
307
|
+
|
|
308
|
+
// use mode/2up as default when no options.default metadata found
|
|
309
|
+
const nextModeNumber = br.overridesBookMode();
|
|
310
|
+
expect(nextModeNumber).toBe(2);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
282
313
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import sinon from 'sinon';
|
|
2
|
-
import { WebTTSSound } from '@/src/plugins/tts/WebTTSEngine.js';
|
|
2
|
+
import WebTTSEngine, { WebTTSSound } from '@/src/plugins/tts/WebTTSEngine.js';
|
|
3
3
|
import { afterEventLoop, eventTargetMixin } from '../../utils.js';
|
|
4
4
|
|
|
5
5
|
beforeEach(() => {
|
|
@@ -8,6 +8,7 @@ beforeEach(() => {
|
|
|
8
8
|
speak: sinon.stub(),
|
|
9
9
|
pause: sinon.stub(),
|
|
10
10
|
resume: sinon.stub(),
|
|
11
|
+
|
|
11
12
|
...eventTargetMixin(),
|
|
12
13
|
};
|
|
13
14
|
window.SpeechSynthesisUtterance = function (text) {
|
|
@@ -21,6 +22,51 @@ afterEach(() => {
|
|
|
21
22
|
delete window.SpeechSynthesisUtterance;
|
|
22
23
|
});
|
|
23
24
|
|
|
25
|
+
describe('WebTTSEngine', () => {
|
|
26
|
+
test('getVoices should include default voice when no actual default', () => {
|
|
27
|
+
// iOS devices set all the voices to default -_-
|
|
28
|
+
speechSynthesis.getVoices = () => [
|
|
29
|
+
{
|
|
30
|
+
default: true,
|
|
31
|
+
lang: "ar-001",
|
|
32
|
+
localService: true,
|
|
33
|
+
name: "Majed",
|
|
34
|
+
voiceURI: "com.apple.voice.compact.ar-001.Maged",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
default: true,
|
|
38
|
+
lang: "bg-BG",
|
|
39
|
+
localService: true,
|
|
40
|
+
name: "Daria",
|
|
41
|
+
voiceURI: "com.apple.voice.compact.bg-BG.Daria",
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
const voices = WebTTSEngine.prototype.getVoices();
|
|
45
|
+
expect(voices.length).toBe(3);
|
|
46
|
+
expect(voices[0].voiceURI).toBe('bookreader.SystemDefault');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('getVoices should not include default voice when there is a default', () => {
|
|
50
|
+
speechSynthesis.getVoices = () => [
|
|
51
|
+
{
|
|
52
|
+
default: true,
|
|
53
|
+
lang: "ar-001",
|
|
54
|
+
localService: true,
|
|
55
|
+
name: "Majed",
|
|
56
|
+
voiceURI: "com.apple.voice.compact.ar-001.Maged",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
default: false,
|
|
60
|
+
lang: "bg-BG",
|
|
61
|
+
localService: true,
|
|
62
|
+
name: "Daria",
|
|
63
|
+
voiceURI: "com.apple.voice.compact.bg-BG.Daria",
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
const voices = WebTTSEngine.prototype.getVoices();
|
|
67
|
+
expect(voices.length).toBe(2);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
24
70
|
|
|
25
71
|
describe('WebTTSSound', () => {
|
|
26
72
|
describe('setPlaybackRate', () => {
|