@internetarchive/bookreader 5.0.0-70 → 5.0.0-70-a1
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 +572 -293
- 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.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/CHANGELOG.md +0 -4
- package/package.json +2 -4
- package/src/BookNavigator/sharing.js +5 -5
- package/src/BookNavigator/volumes/volumes-provider.js +37 -53
- package/src/BookReader.js +5 -4
- package/src/ia-bookreader/ia-bookreader.js +5 -5
- package/src/plugins/tts/AbstractTTSEngine.js +3 -22
- package/src/plugins/url/UrlPlugin.js +7 -5
- package/tests/e2e/models/Navigation.js +1 -1
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +1 -1
- package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +15 -119
- package/tests/jest/plugins/tts/AbstractTTSEngine.test.js +0 -20
- package/tests/jest/plugins/url/UrlPlugin.test.js +0 -8
- package/src/BookNavigator/assets/icon_sort_asc.js +0 -5
- package/src/BookNavigator/assets/icon_sort_desc.js +0 -5
- package/src/BookNavigator/assets/icon_sort_neutral.js +0 -5
- package/src/BookNavigator/assets/icon_volumes.js +0 -11
- package/src/BookNavigator/volumes/volumes.js +0 -188
- package/tests/jest/BookNavigator/volumes/volumes.test.js +0 -97
@@ -1,13 +1,12 @@
|
|
1
1
|
import { html } from 'lit';
|
2
2
|
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import sortNeutralIcon from '../assets/icon_sort_neutral.js';
|
6
|
-
import volumesIcon from '../assets/icon_volumes.js';
|
3
|
+
import { viewableFilesIcon } from '@internetarchive/ia-item-navigator';
|
4
|
+
import '@internetarchive/ia-item-navigator';
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
/**
|
7
|
+
* * @typedef { 'title_asc' | 'title_desc' | 'default'} SortTypesT
|
8
|
+
*/
|
9
|
+
const sortTypes = {
|
11
10
|
title_asc: 'title_asc',
|
12
11
|
title_desc: 'title_desc',
|
13
12
|
default: 'default'
|
@@ -17,76 +16,61 @@ export default class VolumesProvider {
|
|
17
16
|
* @param {import('../../BookReader').default} bookreader
|
18
17
|
*/
|
19
18
|
constructor({ baseHost, bookreader, onProviderChange }) {
|
19
|
+
/** @type {import('../../BookReader').default} */
|
20
|
+
this.bookreader = bookreader;
|
20
21
|
this.onProviderChange = onProviderChange;
|
21
|
-
this.
|
22
|
+
this.baseHost = baseHost;
|
22
23
|
|
23
24
|
const files = bookreader.options.multipleBooksList.by_subprefix;
|
24
25
|
this.viewableFiles = Object.keys(files).map(item => files[item]);
|
25
26
|
this.volumeCount = Object.keys(files).length;
|
26
27
|
|
27
|
-
/** @type {import('../../BookReader').default} */
|
28
|
-
this.bookreader = bookreader;
|
29
|
-
|
30
|
-
this.component.subPrefix = bookreader.options.subPrefix || "";
|
31
|
-
this.component.hostUrl = baseHost;
|
32
|
-
this.component.viewableFiles = this.viewableFiles;
|
33
|
-
|
34
28
|
this.id = "volumes";
|
35
29
|
this.label = `Viewable files (${this.volumeCount})`;
|
36
|
-
this.icon = html`${
|
30
|
+
this.icon = html`${viewableFilesIcon}`;
|
31
|
+
this.sortOrderBy = sortTypes.default;
|
37
32
|
|
38
|
-
this.
|
33
|
+
this.component = document.createElement("iaux-viewable-files");
|
34
|
+
this.component.addSortToUrl = true;
|
35
|
+
this.component.subPrefix = bookreader.options.subPrefix || "";
|
36
|
+
this.component.baseHost = baseHost;
|
37
|
+
this.component.fileList = [...this.viewableFiles];
|
38
|
+
|
39
|
+
this.sortFilesComponent = document.createElement("iaux-sort-viewable-files");
|
40
|
+
this.sortFilesComponent.fileListRaw = this.viewableFiles;
|
41
|
+
this.sortFilesComponent.addEventListener('fileListSorted', (e) => this.handleFileListSorted(e));
|
42
|
+
this.actionButton = this.sortFilesComponent;
|
39
43
|
|
40
44
|
// get sort state from query param
|
41
45
|
if (this.bookreader.urlPlugin) {
|
42
46
|
this.bookreader.urlPlugin.pullFromAddressBar();
|
43
47
|
|
44
48
|
const urlSortValue = this.bookreader.urlPlugin.getUrlParam('sort');
|
45
|
-
if (urlSortValue ===
|
49
|
+
if (urlSortValue === sortTypes.title_asc || urlSortValue === sortTypes.title_desc) {
|
46
50
|
this.sortOrderBy = urlSortValue;
|
47
51
|
}
|
48
52
|
}
|
49
|
-
this.sortVolumes(this.sortOrderBy);
|
50
|
-
}
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
<button class="sort-by neutral-icon" aria-label="Sort volumes in initial order" @click=${() => this.sortVolumes("title_asc")}>${sortNeutralIcon}</button>
|
56
|
-
`,
|
57
|
-
title_asc: html`
|
58
|
-
<button class="sort-by asc-icon" aria-label="Sort volumes in ascending order" @click=${() => this.sortVolumes("title_desc")}>${sortAscIcon}</button>
|
59
|
-
`,
|
60
|
-
title_desc: html`
|
61
|
-
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("default")}>${sortDescIcon}</button>
|
62
|
-
`,
|
63
|
-
};
|
64
|
-
|
65
|
-
return sortIcons[this.sortOrderBy];
|
54
|
+
this.sortFilesComponent.sortVolumes(this.sortOrderBy);
|
55
|
+
|
56
|
+
this.onProviderChange(this.bookreader);
|
66
57
|
}
|
67
58
|
|
68
|
-
/**
|
69
|
-
|
70
|
-
|
71
|
-
sortVolumes(sortByType) {
|
72
|
-
let sortedFiles = [];
|
59
|
+
/** @param { SortTypesT } sortType */
|
60
|
+
async handleFileListSorted(event) {
|
61
|
+
const { sortType, sortedFiles } = event.detail;
|
73
62
|
|
74
|
-
|
75
|
-
|
76
|
-
if (sortByType === sortType.title_asc) return a.title.localeCompare(b.title);
|
77
|
-
else if (sortByType === sortType.title_desc) return b.title.localeCompare(a.title);
|
78
|
-
else return a.orig_sort - b.orig_sort;
|
79
|
-
});
|
63
|
+
this.viewableFiles = sortedFiles;
|
64
|
+
this.sortOrderBy = sortType;
|
80
65
|
|
81
|
-
|
82
|
-
this.component.
|
83
|
-
this.component.
|
84
|
-
this.actionButton = this.sortButton;
|
66
|
+
// update the component
|
67
|
+
this.component.fileList = [...this.viewableFiles];
|
68
|
+
await this.component.updateComplete;
|
85
69
|
|
86
70
|
if (this.bookreader.urlPlugin) {
|
87
71
|
this.bookreader.urlPlugin.pullFromAddressBar();
|
88
|
-
if (this.sortOrderBy !==
|
89
|
-
this.bookreader.urlPlugin.setUrlParam('sort',
|
72
|
+
if (this.sortOrderBy !== sortTypes.default) {
|
73
|
+
this.bookreader.urlPlugin.setUrlParam('sort', this.sortOrderBy);
|
90
74
|
} else {
|
91
75
|
this.bookreader.urlPlugin.removeUrlParam('sort');
|
92
76
|
}
|
@@ -94,11 +78,11 @@ export default class VolumesProvider {
|
|
94
78
|
|
95
79
|
this.onProviderChange(this.bookreader);
|
96
80
|
|
97
|
-
this.multipleFilesClicked(
|
81
|
+
this.multipleFilesClicked(this.sortOrderBy);
|
98
82
|
}
|
99
83
|
|
100
84
|
/**
|
101
|
-
* @param {
|
85
|
+
* @param { SortTypesT } orderBy
|
102
86
|
*/
|
103
87
|
multipleFilesClicked(orderBy) {
|
104
88
|
window.archive_analytics?.send_event(
|
package/src/BookReader.js
CHANGED
@@ -1788,7 +1788,7 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
|
|
1788
1788
|
// Index and page
|
1789
1789
|
if ('undefined' != typeof(urlHash['page'])) {
|
1790
1790
|
// page was set -- may not be int
|
1791
|
-
params.page =
|
1791
|
+
params.page = urlHash['page'];
|
1792
1792
|
}
|
1793
1793
|
|
1794
1794
|
// $$$ process /region
|
@@ -1820,10 +1820,11 @@ BookReader.prototype.paramsFromFragment = function(fragment) {
|
|
1820
1820
|
* @return {string}
|
1821
1821
|
*/
|
1822
1822
|
BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
|
1823
|
+
const separator = '/';
|
1823
1824
|
const fragments = [];
|
1824
1825
|
|
1825
1826
|
if ('undefined' != typeof(params.page)) {
|
1826
|
-
fragments.push('page',
|
1827
|
+
fragments.push('page', params.page);
|
1827
1828
|
} else {
|
1828
1829
|
if ('undefined' != typeof(params.index)) {
|
1829
1830
|
// Don't have page numbering but we do have the index
|
@@ -1849,10 +1850,10 @@ BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
|
|
1849
1850
|
|
1850
1851
|
// search
|
1851
1852
|
if (params.search && urlMode === 'hash') {
|
1852
|
-
fragments.push('search',
|
1853
|
+
fragments.push('search', params.search);
|
1853
1854
|
}
|
1854
1855
|
|
1855
|
-
return fragments.join('/');
|
1856
|
+
return utils.encodeURIComponentPlus(fragments.join(separator)).replace(/%2F/g, '/');
|
1856
1857
|
};
|
1857
1858
|
|
1858
1859
|
/**
|
@@ -54,7 +54,7 @@ export class IaBookReader extends LitElement {
|
|
54
54
|
}
|
55
55
|
|
56
56
|
get itemNav() {
|
57
|
-
return this.shadowRoot.querySelector('
|
57
|
+
return this.shadowRoot.querySelector('iaux-item-navigator');
|
58
58
|
}
|
59
59
|
|
60
60
|
/** Creates modal DOM & attaches to `<body>` */
|
@@ -111,7 +111,7 @@ export class IaBookReader extends LitElement {
|
|
111
111
|
render() {
|
112
112
|
return html`
|
113
113
|
<div class="main-component">
|
114
|
-
<
|
114
|
+
<iaux-item-navigator
|
115
115
|
?viewportInFullscreen=${this.fullscreen}
|
116
116
|
.basehost=${this.baseHost}
|
117
117
|
.item=${this.item}
|
@@ -145,7 +145,7 @@ export class IaBookReader extends LitElement {
|
|
145
145
|
</div>
|
146
146
|
</book-navigator>
|
147
147
|
</div>
|
148
|
-
</
|
148
|
+
</iaux-item-navigator>
|
149
149
|
</div>
|
150
150
|
`;
|
151
151
|
}
|
@@ -169,7 +169,7 @@ export class IaBookReader extends LitElement {
|
|
169
169
|
}
|
170
170
|
|
171
171
|
:host([fullscreen]),
|
172
|
-
|
172
|
+
iaux-item-navigator[viewportinfullscreen] {
|
173
173
|
position: fixed;
|
174
174
|
inset: 0;
|
175
175
|
height: 100%;
|
@@ -193,7 +193,7 @@ export class IaBookReader extends LitElement {
|
|
193
193
|
flex: 1;
|
194
194
|
}
|
195
195
|
|
196
|
-
|
196
|
+
iaux-item-navigator {
|
197
197
|
min-height: var(--br-height, inherit);
|
198
198
|
height: var(--br-height, inherit);
|
199
199
|
display: block;
|
@@ -142,10 +142,6 @@ export default class AbstractTTSEngine {
|
|
142
142
|
// MS Edge fires voices changed randomly very often
|
143
143
|
this.events.off('voiceschanged', this.updateBestVoice);
|
144
144
|
this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
|
145
|
-
// if the current book has a language set, store the selected voice with the book language as a suffix
|
146
|
-
if (this.opts.bookLanguage) {
|
147
|
-
localStorage.setItem(`BRtts-voice-${this.opts.bookLanguage}`, this.voice.voiceURI);
|
148
|
-
}
|
149
145
|
if (this.activeSound) this.activeSound.setVoice(this.voice);
|
150
146
|
}
|
151
147
|
|
@@ -225,12 +221,10 @@ export default class AbstractTTSEngine {
|
|
225
221
|
// user languages that match the book language
|
226
222
|
const matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));
|
227
223
|
|
228
|
-
//
|
229
|
-
return AbstractTTSEngine.
|
230
|
-
// Try to find voices that intersect these two sets
|
231
|
-
|| AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices)
|
224
|
+
// Try to find voices that intersect these two sets
|
225
|
+
return AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices) ||
|
232
226
|
// no user languages match the books; let's return the best voice for the book language
|
233
|
-
|
227
|
+
(bookLangVoices.find(v => v.default) || bookLangVoices[0])
|
234
228
|
// No voices match the book language? let's find a voice in the user's language
|
235
229
|
// and ignore book lang
|
236
230
|
|| AbstractTTSEngine.getMatchingVoice(userLanguages, voices)
|
@@ -238,19 +232,6 @@ export default class AbstractTTSEngine {
|
|
238
232
|
|| (voices.find(v => v.default) || voices[0]);
|
239
233
|
}
|
240
234
|
|
241
|
-
/**
|
242
|
-
* @private
|
243
|
-
* Get the voice last selected by the user for the book language from localStorage.
|
244
|
-
* Returns undefined if no voice is stored or found.
|
245
|
-
* @param {SpeechSynthesisVoice[]} voices browser voices to choose from
|
246
|
-
* @param {ISO6391} bookLanguage book language to look for
|
247
|
-
* @return {SpeechSynthesisVoice | undefined}
|
248
|
-
*/
|
249
|
-
static getMatchingStoredVoice(voices, bookLanguage) {
|
250
|
-
const storedVoice = localStorage.getItem(`BRtts-voice-${bookLanguage}`);
|
251
|
-
return (storedVoice ? voices.find(v => v.voiceURI === storedVoice) : undefined);
|
252
|
-
}
|
253
|
-
|
254
235
|
/**
|
255
236
|
* @private
|
256
237
|
* Get the best voice that matches one of the BCP47 languages (order by preference)
|
@@ -45,7 +45,7 @@ export class UrlPlugin {
|
|
45
45
|
|
46
46
|
const strPathParams = this.urlSchema
|
47
47
|
.filter(s => s.position == 'path')
|
48
|
-
.map(schema => pathParams[schema.name] ? `${schema.name}/${
|
48
|
+
.map(schema => pathParams[schema.name] ? `${schema.name}/${pathParams[schema.name]}` : '')
|
49
49
|
.join('/');
|
50
50
|
|
51
51
|
// replace consecutive slashes with a single slash + remove trailing slashes
|
@@ -83,13 +83,15 @@ export class UrlPlugin {
|
|
83
83
|
const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
|
84
84
|
const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
|
85
85
|
|
86
|
-
|
87
|
-
|
86
|
+
if (hasDeprecatedKey) {
|
87
|
+
urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];
|
88
88
|
return;
|
89
89
|
}
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
if (hasPropertyKey) {
|
92
|
+
urlState[schema.name] = urlStrSplitSlashObj[schema.name];
|
93
|
+
return;
|
94
|
+
}
|
93
95
|
});
|
94
96
|
|
95
97
|
// Add searchParams to urlState
|
@@ -5,7 +5,7 @@ export default class Navigation {
|
|
5
5
|
constructor() {
|
6
6
|
this.topNavShell = new Selector('.BRtoolbar');
|
7
7
|
this.bottomNavShell = new Selector('.BRfooter');
|
8
|
-
this.itemNav = Selector('ia-bookreader').shadowRoot().find('
|
8
|
+
this.itemNav = Selector('ia-bookreader').shadowRoot().find('iaux-item-navigator').shadowRoot();
|
9
9
|
|
10
10
|
// flipping
|
11
11
|
this.goLeft = this.bottomNavShell.find('.BRicon.book_left');
|
@@ -30,7 +30,7 @@ describe('Sharing Provider', () => {
|
|
30
30
|
expect(provider.id).toEqual('share');
|
31
31
|
expect(provider.icon).toBeDefined();
|
32
32
|
expect(provider.label).toEqual('Share this book');
|
33
|
-
expect(fixtureSync(provider.component).tagName).toContain('
|
33
|
+
expect(fixtureSync(provider.component).tagName).toContain('IAUX-SHARING-OPTIONS');
|
34
34
|
});
|
35
35
|
|
36
36
|
describe('Handles being a sub file/volume', () => {
|
@@ -1,9 +1,10 @@
|
|
1
|
-
import {
|
1
|
+
import { fixtureCleanup, fixtureSync } from '@open-wc/testing-helpers';
|
2
2
|
import sinon from 'sinon';
|
3
3
|
import volumesProvider from '@/src/BookNavigator/volumes/volumes-provider';
|
4
4
|
|
5
5
|
const brOptions = {
|
6
6
|
"options": {
|
7
|
+
"subPrefix": 'special-subprefix',
|
7
8
|
"enableMultipleBooks": true,
|
8
9
|
"multipleBooksList": {
|
9
10
|
"by_subprefix": {
|
@@ -39,8 +40,9 @@ afterEach(() => {
|
|
39
40
|
});
|
40
41
|
|
41
42
|
describe('Volumes Provider', () => {
|
42
|
-
test('
|
43
|
+
test('initiating & sorting', () => {
|
43
44
|
const onProviderChange = sinon.fake();
|
45
|
+
|
44
46
|
const baseHost = "https://archive.org";
|
45
47
|
const provider = new volumesProvider({
|
46
48
|
baseHost,
|
@@ -55,130 +57,24 @@ describe('Volumes Provider', () => {
|
|
55
57
|
expect(provider.id).toEqual('volumes');
|
56
58
|
expect(provider.icon).toBeDefined();
|
57
59
|
expect(fixtureSync(provider.icon).tagName).toEqual('svg');
|
60
|
+
expect(provider.sortOrderBy).toEqual('default');
|
61
|
+
|
58
62
|
expect(provider.label).toEqual(`Viewable files (${volumeCount})`);
|
59
63
|
expect(provider.viewableFiles).toBeDefined();
|
60
64
|
expect(provider.viewableFiles.length).toEqual(3);
|
65
|
+
expect(provider.volumeCount).toEqual(3);
|
61
66
|
|
62
|
-
expect(provider.component.
|
63
|
-
expect(provider.component.
|
64
|
-
expect(provider.component).
|
65
|
-
});
|
66
|
-
|
67
|
-
test('sorting cycles - render sort actionButton', async () => {
|
68
|
-
const onProviderChange = sinon.fake();
|
69
|
-
const baseHost = "https://archive.org";
|
70
|
-
const provider = new volumesProvider({
|
71
|
-
baseHost,
|
72
|
-
bookreader: brOptions,
|
73
|
-
onProviderChange
|
74
|
-
});
|
75
|
-
|
76
|
-
expect(provider.sortOrderBy).toEqual("default");
|
77
|
-
|
78
|
-
provider.sortVolumes("title_asc");
|
79
|
-
expect(provider.sortOrderBy).toEqual("title_asc");
|
80
|
-
expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by asc-icon");
|
81
|
-
|
82
|
-
provider.sortVolumes("title_desc");
|
83
|
-
expect(provider.sortOrderBy).toEqual("title_desc");
|
84
|
-
expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by desc-icon");
|
85
|
-
|
86
|
-
provider.sortVolumes("default");
|
87
|
-
expect(provider.sortOrderBy).toEqual("default");
|
88
|
-
expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by neutral-icon");
|
89
|
-
});
|
67
|
+
expect(provider.component.baseHost).toEqual(baseHost);
|
68
|
+
expect(provider.component.fileList).toEqual(provider.viewableFiles);
|
69
|
+
expect(provider.component.subPrefix).toEqual(brOptions.options.subPrefix);
|
90
70
|
|
91
|
-
test('sort volumes in initial order', async () => {
|
92
|
-
const onProviderChange = sinon.fake();
|
93
|
-
const baseHost = "https://archive.org";
|
94
|
-
const provider = new volumesProvider({
|
95
|
-
baseHost,
|
96
|
-
bookreader: brOptions,
|
97
|
-
onProviderChange
|
98
|
-
});
|
99
|
-
|
100
|
-
const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
|
101
|
-
const files = Object.keys(parsedFiles).map(item => parsedFiles[item]).sort((a, b) => a.orig_sort - b.orig_sort);
|
102
|
-
const origSortTitles = files.map(item => item.title);
|
103
|
-
|
104
|
-
provider.sortVolumes("default");
|
105
|
-
|
106
|
-
expect(provider.sortOrderBy).toEqual("default");
|
107
71
|
expect(provider.actionButton).toBeDefined();
|
72
|
+
expect(provider.actionButton).toEqual(provider.sortFilesComponent);
|
73
|
+
expect(provider.actionButton.fileListRaw).toEqual(provider.viewableFiles);
|
108
74
|
|
109
|
-
const
|
110
|
-
|
111
|
-
expect(providerFileTitles).toEqual([...origSortTitles]);
|
112
|
-
});
|
75
|
+
const callbackSpy = sinon.spy(provider, 'handleFileListSorted');
|
76
|
+
provider.actionButton.sortVolumes('title_asc');
|
113
77
|
|
114
|
-
|
115
|
-
const onProviderChange = sinon.fake();
|
116
|
-
const baseHost = "https://archive.org";
|
117
|
-
const provider = new volumesProvider({
|
118
|
-
baseHost,
|
119
|
-
bookreader: brOptions,
|
120
|
-
onProviderChange
|
121
|
-
});
|
122
|
-
|
123
|
-
const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
|
124
|
-
const files = Object.keys(parsedFiles).map(item => parsedFiles[item]);
|
125
|
-
const ascendingTitles = files.map(item => item.title).sort((a, b) => a.localeCompare(b));
|
126
|
-
|
127
|
-
provider.sortVolumes("title_asc");
|
128
|
-
|
129
|
-
expect(provider.sortOrderBy).toEqual("title_asc");
|
130
|
-
expect(provider.actionButton).toBeDefined();
|
131
|
-
|
132
|
-
const providerFileTitles = provider.viewableFiles.map(item => item.title);
|
133
|
-
// use `.eql` for "lose equality" in order to deeply compare values.
|
134
|
-
expect(providerFileTitles).toEqual([...ascendingTitles]);
|
135
|
-
});
|
136
|
-
|
137
|
-
test('sort volumes in descending title order', async () => {
|
138
|
-
const onProviderChange = sinon.fake();
|
139
|
-
const baseHost = "https://archive.org";
|
140
|
-
const provider = new volumesProvider({
|
141
|
-
baseHost,
|
142
|
-
bookreader: brOptions,
|
143
|
-
onProviderChange
|
144
|
-
});
|
145
|
-
provider.isSortAscending = false;
|
146
|
-
|
147
|
-
const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
|
148
|
-
const files = Object.keys(parsedFiles).map(item => parsedFiles[item]);
|
149
|
-
const descendingTitles = files.map(item => item.title).sort((a, b) => b.localeCompare(a));
|
150
|
-
|
151
|
-
provider.sortVolumes("title_desc");
|
152
|
-
|
153
|
-
expect(provider.sortOrderBy).toEqual("title_desc");
|
154
|
-
expect(provider.actionButton).toBeDefined();
|
155
|
-
|
156
|
-
const providerFileTitles = provider.viewableFiles.map(item => item.title);
|
157
|
-
// use `.eql` for "lose equality" in order to deeply compare values.
|
158
|
-
expect(providerFileTitles).toEqual([...descendingTitles]);
|
159
|
-
});
|
160
|
-
|
161
|
-
describe('Sorting icons', () => {
|
162
|
-
test('has 3 icons', async () => {
|
163
|
-
const onProviderChange = sinon.fake();
|
164
|
-
const baseHost = "https://archive.org";
|
165
|
-
const provider = new volumesProvider({
|
166
|
-
baseHost,
|
167
|
-
bookreader: brOptions,
|
168
|
-
onProviderChange
|
169
|
-
});
|
170
|
-
provider.sortOrderBy = 'default';
|
171
|
-
|
172
|
-
const origSortButton = await fixture(provider.sortButton);
|
173
|
-
expect(origSortButton.classList.contains('neutral-icon')).toBeTruthy();
|
174
|
-
|
175
|
-
provider.sortOrderBy = 'title_asc';
|
176
|
-
const ascButton = await fixture(provider.sortButton);
|
177
|
-
expect(ascButton.classList.contains('asc-icon')).toBeTruthy();
|
178
|
-
|
179
|
-
provider.sortOrderBy = 'title_desc';
|
180
|
-
const descButton = await fixture(provider.sortButton);
|
181
|
-
expect(descButton.classList.contains('desc-icon')).toBeTruthy();
|
182
|
-
});
|
78
|
+
expect(callbackSpy.callCount).toEqual(1);
|
183
79
|
});
|
184
80
|
});
|
@@ -111,26 +111,6 @@ for (const dummyVoice of [dummyVoiceHyphens, dummyVoiceUnderscores]) {
|
|
111
111
|
|
112
112
|
expect(getBestBookVoice(voices, 'en', ['en-CA', 'en'])).toBe(voices[0]);
|
113
113
|
});
|
114
|
-
|
115
|
-
test('choose stored language from localStorage', () => {
|
116
|
-
const voices = [
|
117
|
-
dummyVoice({lang: "en-US", voiceURI: "English US", default: true}),
|
118
|
-
dummyVoice({lang: "en-GB", voiceURI: "English GB"}),
|
119
|
-
dummyVoice({lang: "en-CA", voiceURI: "English CA"}),
|
120
|
-
];
|
121
|
-
class DummyEngine extends AbstractTTSEngine {
|
122
|
-
getVoices() { return voices; }
|
123
|
-
}
|
124
|
-
const ttsEngine = new DummyEngine({...DUMMY_TTS_ENGINE_OPTS, bookLanguage: 'en'});
|
125
|
-
// simulates setting default voice on tts startup
|
126
|
-
ttsEngine.updateBestVoice();
|
127
|
-
// simulates user choosing a voice that matches the bookLanguage
|
128
|
-
// voice will be stored in localStorage
|
129
|
-
ttsEngine.setVoice(voices[2].voiceURI);
|
130
|
-
|
131
|
-
// expecting the voice to be selected by getMatchingStoredVoice and returned as best voice
|
132
|
-
expect(getBestBookVoice(voices, 'en', [])).toBe(voices[2]);
|
133
|
-
});
|
134
114
|
});
|
135
115
|
}
|
136
116
|
|
@@ -19,10 +19,6 @@ describe('UrlPlugin tests', () => {
|
|
19
19
|
expect(urlPlugin.urlStateToUrlString(urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
20
20
|
});
|
21
21
|
|
22
|
-
test('encodes page number', () => {
|
23
|
-
expect(urlPlugin.urlStateToUrlString({ page: '12/46' })).toBe(`page/12%2F46`);
|
24
|
-
});
|
25
|
-
|
26
22
|
test('urlStateToUrlString with unknown states in schema', () => {
|
27
23
|
const urlState = { page: 'n7', mode: '1up' };
|
28
24
|
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', viewer: 'theater', sortBy: 'title_asc' };
|
@@ -51,10 +47,6 @@ describe('UrlPlugin tests', () => {
|
|
51
47
|
expect(urlPlugin.urlStringToUrlState(url1)).toEqual({page: 'n7', mode: '1up'});
|
52
48
|
});
|
53
49
|
|
54
|
-
test('decodes page number', () => {
|
55
|
-
expect(urlPlugin.urlStringToUrlState('/page/12%2F46')).toStrictEqual({ page: '12/46' });
|
56
|
-
});
|
57
|
-
|
58
50
|
test('urlStringToUrlState with deprecated_for', () => {
|
59
51
|
const url = '/page/n7/mode/2up/search/hello';
|
60
52
|
|
@@ -1,5 +0,0 @@
|
|
1
|
-
import { html } from 'lit';
|
2
|
-
|
3
|
-
export default html`
|
4
|
-
<svg name="sort-asc" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill="#fff" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill="#fff" fill-rule="nonzero"/><path d="m10.3846154 11.0769231 2.7692308 5.5384615 2.7692307-5.5384615m-2.7692307 4.1538461v-13.15384612" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.661538" transform="matrix(1 0 0 -1 0 18.692308)"/></g></svg>
|
5
|
-
`;
|
@@ -1,5 +0,0 @@
|
|
1
|
-
import { html } from 'lit';
|
2
|
-
|
3
|
-
export default html`
|
4
|
-
<svg name="sort-desc" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill="#fff" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill="#fff" fill-rule="nonzero"/><path d="m10.3846154 11.0769231 2.7692308 5.5384615 2.7692307-5.5384615m-2.7692307 4.1538461v-13.15384612" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.661538"/></g></svg>
|
5
|
-
`;
|
@@ -1,5 +0,0 @@
|
|
1
|
-
import { html } from 'lit';
|
2
|
-
|
3
|
-
export default html`
|
4
|
-
<svg name="sort-neutral" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill-rule="nonzero"/><circle cx="13" cy="9" r="2"/></g></svg>
|
5
|
-
`;
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import { html } from 'lit';
|
2
|
-
|
3
|
-
export default html`
|
4
|
-
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" aria-labelledby="volumesTitleID volumesDescID">
|
5
|
-
<title id="volumesTitleID">Volumes icon</title>
|
6
|
-
<desc id="volumesDescID">Three books stacked on each other</desc>
|
7
|
-
<g fill="#ffffff">
|
8
|
-
<path fill="#ffffff" d="m9.83536396 0h10.07241114c.1725502.47117517.3378411.76385809.4958725.87804878.1295523.11419069.3199719.1998337.5712586.25692905.2512868.05709534.4704647.08564301.6575337.08564301h.2806036v15.24362526h-4.3355343v3.8106985h-4.44275v3.7250554h-12.01318261c-.27306495 0-.50313194-.085643-.69020098-.256929-.18706903-.1712861-.30936193-.3425721-.36687867-.5138581l-.06449694-.2785477v-14.2159091c0-.32815965.08627512-.5922949.25882537-.79240577.17255024-.20011086.34510049-.32150776.51765073-.36419068l.25882537-.0640244h3.36472977v-2.54767184c0-.31374722.08627513-.57067627.25882537-.77078714.17255025-.20011086.34510049-.32150776.51765074-.36419068l.25882536-.06402439h3.36472978v-2.56929047c0-.32815964.08627512-.5922949.25882537-.79240576.17255024-.20011087.34510049-.31430156.51765073-.34257207zm10.78355264 15.6294346v-13.53076498c-.2730649-.08536585-.4456152-.16380266-.5176507-.23531042-.1725502-.1424612-.2730649-.27078714-.3015441-.38497783v13.36031043h-9.87808272c0 .0144124-.02149898.0144124-.06449694 0-.04299795-.0144124-.08962561.006929-.13988296.0640244-.05025735.0570953-.07538603.1427383-.07538603.256929s.02149898.210643.06449694.289357c.04299795.078714.08599591.1322062.12899387.1604767l.06449693.0216187h10.71905571zm-10.2449613-2.4412417h7.98003v-11.60421286h-7.98003zm1.6827837-9.41990022h4.6153002c.1725502 0 .3199718.05349224.4422647.16047672s.1834393.23891353.1834393.39578714c0 .15687362-.0611464.28519956-.1834393.38497783s-.2697145.1496674-.4422647.1496674h-4.6153002c-.1725503 0-.3199719-.04988913-.4422647-.1496674-.1222929-.09977827-.1834394-.22810421-.1834394-.38497783 0-.15687361.0611465-.28880266.1834394-.39578714.1222928-.10698448.2697144-.16047672.4422647-.16047672zm-6.08197737 13.50997782h7.72120467v-.8131929h-3.79610541c-.27306495 0-.49950224-.085643-.67931188-.256929-.17980964-.1712861-.29847284-.3425721-.35598958-.5138581l-.06449694-.2785477v-10.02023282h-2.82530086zm6.77217827-11.36890243h3.2139578c.1295522 0 .240956.05709534.3342113.17128603.0932554.11419069.139883.24972284.139883.40659645 0 .15687362-.0466276.28880267-.139883.39578714-.0932553.10698448-.2046591.16047672-.3342113.16047672h-3.2139578c-.1295523 0-.2373264-.05349224-.3233223-.16047672-.0859959-.10698447-.1289938-.23891352-.1289938-.39578714 0-.15687361.0429979-.29240576.1289938-.40659645s.19377-.17128603.3233223-.17128603zm-11.15043132 15.11557653h7.69942646v-.7491685h-3.79610539c-.25854616 0-.48135376-.0892462-.66842279-.2677384-.18706904-.1784922-.30936193-.3605876-.36687868-.546286l-.06449694-.2569291v-10.04101994h-2.80352266zm14.62237682-4.5606985h-.8191949v2.1410754h-9.89986085s-.04299796.0285477-.12899387.085643c-.08599592.0570954-.12201369.1427384-.10805331.2569291 0 .1141907.01786928.210643.05360784.289357.03573856.0787139.07538603.125.1189424.138858l.06449694.0432373h10.71905575v-2.9542683zm-4.3991936 3.8106985h-.8191949v2.077051h-9.8563045c0 .0144124-.02149898.0144124-.06449694 0-.04299795-.0144125-.08962561.0105321-.13988296.0748337-.05025735.0643015-.07538603.1607538-.07538603.289357 0 .1141906.02149898.2070399.06449694.2785476.04299795.0715078.08599591.1141907.12899387.1280488l.06449693.0216186h10.69811519v-2.8686252z" />
|
9
|
-
</g>
|
10
|
-
</svg>
|
11
|
-
`;
|