@internetarchive/bookreader 5.0.0-70 → 5.0.0-70-a2
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 +583 -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
|
-
`;
|