@internetarchive/bookreader 5.0.0-50 → 5.0.0-52
Sign up to get free protection for your applications and to get access to all the features.
- 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', () => {
|