@internetarchive/bookreader 5.0.0-24 → 5.0.0-24-sortingstate
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/.nvmrc +1 -0
- package/BookReader/BookReader.js +32148 -2
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bookreader-component-bundle.js +10916 -941
- package/BookReader/bookreader-component-bundle.js.map +1 -1
- package/BookReader/icons/1up.svg +12 -1
- package/BookReader/icons/2up.svg +15 -1
- package/BookReader/icons/advance.svg +26 -3
- package/BookReader/icons/chevron-right.svg +1 -1
- package/BookReader/icons/close-circle-dark.svg +1 -1
- package/BookReader/icons/close-circle.svg +1 -1
- package/BookReader/icons/fullscreen.svg +17 -1
- package/BookReader/icons/fullscreen_exit.svg +17 -1
- package/BookReader/icons/hamburger.svg +15 -1
- package/BookReader/icons/left-arrow.svg +12 -1
- package/BookReader/icons/magnify-minus.svg +16 -1
- package/BookReader/icons/magnify-plus.svg +17 -1
- package/BookReader/icons/magnify.svg +15 -1
- package/BookReader/icons/pause.svg +23 -1
- package/BookReader/icons/play.svg +22 -1
- package/BookReader/icons/playback-speed.svg +34 -1
- package/BookReader/icons/read-aloud.svg +22 -1
- package/BookReader/icons/review.svg +22 -3
- package/BookReader/icons/thumbnails.svg +17 -1
- package/BookReader/icons/voice.svg +1 -1
- package/BookReader/icons/volume-full.svg +22 -1
- package/BookReader/images/BRicons.svg +94 -5
- package/BookReader/images/books_graphic.svg +177 -1
- package/BookReader/images/icon_book.svg +12 -1
- package/BookReader/images/icon_bookmark.svg +12 -1
- package/BookReader/images/icon_gear.svg +14 -1
- package/BookReader/images/icon_hamburger.svg +20 -1
- package/BookReader/images/icon_home.svg +21 -1
- package/BookReader/images/icon_info.svg +11 -1
- package/BookReader/images/icon_one_page.svg +8 -1
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +15 -1
- package/BookReader/images/icon_search_button.svg +8 -1
- package/BookReader/images/icon_share.svg +9 -1
- package/BookReader/images/icon_skip-ahead.svg +6 -1
- package/BookReader/images/icon_skip-back.svg +13 -2
- package/BookReader/images/icon_speaker.svg +18 -1
- package/BookReader/images/icon_speaker_open.svg +10 -1
- package/BookReader/images/icon_thumbnails.svg +12 -1
- package/BookReader/images/icon_toc.svg +5 -1
- package/BookReader/images/icon_two_pages.svg +9 -1
- package/BookReader/images/marker_chap-off.svg +11 -1
- package/BookReader/images/marker_chap-on.svg +11 -1
- package/BookReader/images/marker_srch-on.svg +11 -1
- package/BookReader/jquery-1.10.1.js +108 -2
- package/BookReader/plugins/plugin.archive_analytics.js +170 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +163 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +333 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +72 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +332 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +241 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1263 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +839 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +9114 -2
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +750 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +326 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +411 -2
- package/BookReader/webcomponents-bundle.js.map +1 -1
- package/package.json +1 -1
- package/src/BookNavigator/volumes/volumes-provider.js +39 -9
- package/src/BookReader.js +4 -0
- package/src/plugins/plugin.url.js +209 -2
- package/tests/jest/plugins/plugin.url.test.js +160 -1
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +6 -6
package/package.json
CHANGED
@@ -7,8 +7,16 @@ import volumesIcon from '../assets/icon_volumes.js';
|
|
7
7
|
|
8
8
|
import './volumes.js';
|
9
9
|
|
10
|
+
const sortType = {
|
11
|
+
title_asc: 'title_asc',
|
12
|
+
title_desc: 'title_desc',
|
13
|
+
default: 'default'
|
14
|
+
};
|
10
15
|
export default class VolumesProvider {
|
11
16
|
|
17
|
+
/**
|
18
|
+
* @param {import('../../BookReader').default} bookreader
|
19
|
+
*/
|
12
20
|
constructor(baseHost, bookreader, optionChange) {
|
13
21
|
this.optionChange = optionChange;
|
14
22
|
this.component = document.createElement("viewable-files");
|
@@ -17,6 +25,9 @@ export default class VolumesProvider {
|
|
17
25
|
this.viewableFiles = Object.keys(files).map(item => files[item]);
|
18
26
|
this.volumeCount = Object.keys(files).length;
|
19
27
|
|
28
|
+
/** @type {import('../../BookReader').default} */
|
29
|
+
this.bookreader = bookreader;
|
30
|
+
|
20
31
|
this.component.subPrefix = bookreader.options.subPrefix || "";
|
21
32
|
this.component.hostUrl = baseHost;
|
22
33
|
this.component.viewableFiles = this.viewableFiles;
|
@@ -25,20 +36,27 @@ export default class VolumesProvider {
|
|
25
36
|
this.label = `Viewable files (${this.volumeCount})`;
|
26
37
|
this.icon = html`${volumesIcon}`;
|
27
38
|
|
28
|
-
|
29
|
-
this.
|
39
|
+
// get sort state from query param
|
40
|
+
this.bookreader.urlPlugin.pullFromAddressBar(location.pathname + location.search);
|
41
|
+
const urlSortValue = this.bookreader.urlPlugin.getUrlParam('sort');
|
42
|
+
if (urlSortValue === sortType.title_asc || urlSortValue === sortType.title_desc) {
|
43
|
+
this.sortOrderBy = urlSortValue;
|
44
|
+
} else {
|
45
|
+
this.sortOrderBy = sortType.default;
|
46
|
+
}
|
47
|
+
this.sortVolumes(this.sortOrderBy);
|
30
48
|
}
|
31
49
|
|
32
50
|
get sortButton() {
|
33
51
|
const sortIcons = {
|
34
|
-
|
52
|
+
default: html`
|
35
53
|
<button class="sort-by neutral-icon" aria-label="Sort volumes in initial order" @click=${() => this.sortVolumes("title_asc")}>${sortNeutralIcon}</button>
|
36
54
|
`,
|
37
55
|
title_asc: html`
|
38
56
|
<button class="sort-by asc-icon" aria-label="Sort volumes in ascending order" @click=${() => this.sortVolumes("title_desc")}>${sortAscIcon}</button>
|
39
57
|
`,
|
40
58
|
title_desc: html`
|
41
|
-
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("
|
59
|
+
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("default")}>${sortDescIcon}</button>
|
42
60
|
`,
|
43
61
|
};
|
44
62
|
|
@@ -46,28 +64,40 @@ export default class VolumesProvider {
|
|
46
64
|
}
|
47
65
|
|
48
66
|
/**
|
49
|
-
* @param {'
|
67
|
+
* @param {'default' | 'title_asc' | 'title_desc'} sortByType
|
50
68
|
*/
|
51
69
|
sortVolumes(sortByType) {
|
52
70
|
let sortedFiles = [];
|
53
71
|
|
54
72
|
const files = this.viewableFiles;
|
55
73
|
sortedFiles = files.sort((a, b) => {
|
56
|
-
if (sortByType ===
|
57
|
-
else if (sortByType ===
|
58
|
-
else return b.
|
74
|
+
if (sortByType === sortType.title_asc) return a.title.localeCompare(b.title);
|
75
|
+
else if (sortByType === sortType.title_desc) return b.title.localeCompare(a.title);
|
76
|
+
else return a.orig_sort - b.orig_sort;
|
59
77
|
});
|
60
78
|
|
61
79
|
this.sortOrderBy = sortByType;
|
62
80
|
this.component.viewableFiles = [...sortedFiles];
|
63
81
|
this.actionButton = this.sortButton;
|
82
|
+
|
83
|
+
if (this.sortOrderBy !== sortType.default) {
|
84
|
+
this.bookreader.urlPlugin.setUrlParam('sort', sortByType);
|
85
|
+
} else {
|
86
|
+
this.bookreader.urlPlugin.removeUrlParam('sort');
|
87
|
+
}
|
88
|
+
|
89
|
+
const urlSchema = this.bookreader.urlPlugin.urlSchema;
|
90
|
+
const urlState = this.bookreader.urlPlugin.urlState;
|
91
|
+
this.bookreader.urlPlugin.urlStateToUrlString(urlSchema, urlState);
|
92
|
+
this.bookreader.urlPlugin.pushToAddressBar();
|
93
|
+
|
64
94
|
this.optionChange(this.bookreader);
|
65
95
|
|
66
96
|
this.multipleFilesClicked(sortByType);
|
67
97
|
}
|
68
98
|
|
69
99
|
/**
|
70
|
-
* @param {'
|
100
|
+
* @param {'default' | 'title_asc' | 'title_desc'} orderBy
|
71
101
|
*/
|
72
102
|
multipleFilesClicked(orderBy) {
|
73
103
|
if (!window.archive_analytics) {
|
package/src/BookReader.js
CHANGED
@@ -63,6 +63,10 @@ if (location.toString().indexOf('_debugShowConsole=true') != -1) {
|
|
63
63
|
*/
|
64
64
|
export default function BookReader(overrides = {}) {
|
65
65
|
const options = jQuery.extend(true, {}, BookReader.defaultOptions, overrides, BookReader.optionOverrides);
|
66
|
+
|
67
|
+
/** @type {import('./plugins/plugin.url').UrlPlugin | null} */
|
68
|
+
this.urlPlugin = null;
|
69
|
+
|
66
70
|
this.setup(options);
|
67
71
|
}
|
68
72
|
|
@@ -50,7 +50,7 @@ BookReader.prototype.init = (function(super_) {
|
|
50
50
|
this.bind(BookReader.eventNames.PostInit, () => {
|
51
51
|
const { updateWindowTitle, urlMode } = this.options;
|
52
52
|
if (updateWindowTitle) {
|
53
|
-
document.title = this.shortTitle(50);
|
53
|
+
document.title = this.shortTitle(this.bookTitle, 50);
|
54
54
|
}
|
55
55
|
if (urlMode === 'hash') {
|
56
56
|
this.urlStartLocationPolling();
|
@@ -86,7 +86,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
|
|
86
86
|
this.oldLocationHash = this.urlReadFragment();
|
87
87
|
|
88
88
|
if (this.locationPollId) {
|
89
|
-
clearInterval(this.
|
89
|
+
clearInterval(this.locationPollId);
|
90
90
|
this.locationPollId = null;
|
91
91
|
}
|
92
92
|
|
@@ -196,3 +196,210 @@ BookReader.prototype.urlReadFragment = function() {
|
|
196
196
|
BookReader.prototype.urlReadHashFragment = function() {
|
197
197
|
return window.location.hash.substr(1);
|
198
198
|
};
|
199
|
+
export class UrlPlugin {
|
200
|
+
constructor(options = {}) {
|
201
|
+
this.bookReaderOptions = options;
|
202
|
+
|
203
|
+
this.urlSchema = [
|
204
|
+
{ name: 'page', position: 'path', default: 'n0' },
|
205
|
+
{ name: 'mode', position: 'path', default: '2up' },
|
206
|
+
{ name: 'search', position: 'path', deprecated_for: 'q' },
|
207
|
+
{ name: 'q', position: 'query_param' },
|
208
|
+
{ name: 'sort', position: 'query_param' },
|
209
|
+
{ name: 'view', position: 'query_param' },
|
210
|
+
{ name: 'admin', position: 'query_param' },
|
211
|
+
];
|
212
|
+
|
213
|
+
this.urlState = {};
|
214
|
+
this.urlMode = 'hash';
|
215
|
+
this.urlHistoryBasePath = '/';
|
216
|
+
this.urlLocationPollId = null;
|
217
|
+
this.oldLocationHash = null;
|
218
|
+
this.oldUserHash = null;
|
219
|
+
}
|
220
|
+
|
221
|
+
/**
|
222
|
+
* Parse JSON object URL state to string format
|
223
|
+
* Arrange path names in an order that it is positioned on the urlSchema
|
224
|
+
* @param {object} urlState
|
225
|
+
* @returns {string}
|
226
|
+
*/
|
227
|
+
urlStateToUrlString(urlSchema, urlState) {
|
228
|
+
const searchParams = new URLSearchParams();
|
229
|
+
const pathParams = {};
|
230
|
+
|
231
|
+
Object.keys(urlState).forEach(key => {
|
232
|
+
let schema = urlSchema.find(schema => schema.name === key);
|
233
|
+
if (schema?.deprecated_for) {
|
234
|
+
schema = urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
|
235
|
+
}
|
236
|
+
if (schema?.position == 'path') {
|
237
|
+
pathParams[schema?.name] = urlState[key];
|
238
|
+
} else {
|
239
|
+
searchParams.append(schema?.name || key, urlState[key]);
|
240
|
+
}
|
241
|
+
});
|
242
|
+
|
243
|
+
const strPathParams = urlSchema
|
244
|
+
.filter(s => s.position == 'path')
|
245
|
+
.map(schema => pathParams[schema.name] ? `${schema.name}/${pathParams[schema.name]}` : '')
|
246
|
+
.join('/');
|
247
|
+
|
248
|
+
const strStrippedTrailingSlash = `${strPathParams.replace(/\/$/, '')}`;
|
249
|
+
const concatenatedPath = `/${strStrippedTrailingSlash}?${searchParams.toString()}`;
|
250
|
+
return searchParams.toString() ? concatenatedPath : `/${strStrippedTrailingSlash}`;
|
251
|
+
}
|
252
|
+
|
253
|
+
/**
|
254
|
+
* Parse string URL and add it in the current urlState
|
255
|
+
* Example:
|
256
|
+
* /page/n7/mode/2up => {page: 'n7', mode: '2up'}
|
257
|
+
* /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}
|
258
|
+
* @param {array} urlSchema
|
259
|
+
* @param {string} str
|
260
|
+
* @returns {object}
|
261
|
+
*/
|
262
|
+
urlStringToUrlState(urlSchema, str) {
|
263
|
+
const urlState = {};
|
264
|
+
|
265
|
+
// Fetch searchParams from given {str}
|
266
|
+
// Note: whole URL path is needed for URLSearchParams
|
267
|
+
const urlPath = new URL(str, 'http://example.com');
|
268
|
+
const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());
|
269
|
+
const urlStrSplitSlashObj = Object.fromEntries(urlPath.pathname
|
270
|
+
.match(/[^\\/]+\/[^\\/]+/g)
|
271
|
+
.map(x => x.split('/'))
|
272
|
+
);
|
273
|
+
const doesKeyExists = (_object, _key) => {
|
274
|
+
return Object.keys(_object).some(value => value == _key);
|
275
|
+
};
|
276
|
+
|
277
|
+
urlSchema
|
278
|
+
.filter(schema => schema.position == 'path')
|
279
|
+
.forEach(schema => {
|
280
|
+
if (!urlStrSplitSlashObj[schema.name] && schema.default) {
|
281
|
+
return urlState[schema.name] = schema.default;
|
282
|
+
}
|
283
|
+
const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
|
284
|
+
const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
|
285
|
+
|
286
|
+
if (hasDeprecatedKey)
|
287
|
+
return urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];
|
288
|
+
|
289
|
+
if (hasPropertyKey)
|
290
|
+
return urlState[schema.name] = urlStrSplitSlashObj[schema.name];
|
291
|
+
});
|
292
|
+
|
293
|
+
// Add searchParams to urlState
|
294
|
+
// Check if Object value is a Boolean and convert value to Boolean
|
295
|
+
// Otherwise, return Object value
|
296
|
+
const isBoolean = value => value === 'true' || (value === 'false' ? false : value);
|
297
|
+
Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
|
298
|
+
urlState[key] = isBoolean(value);
|
299
|
+
});
|
300
|
+
|
301
|
+
return urlState;
|
302
|
+
}
|
303
|
+
|
304
|
+
/**
|
305
|
+
* Add or update key-value to the urlState
|
306
|
+
* @param {string} key
|
307
|
+
* @param {string} val
|
308
|
+
*/
|
309
|
+
setUrlParam(key, value) {
|
310
|
+
this.urlState[key] = value;
|
311
|
+
|
312
|
+
this.pushToAddressBar();
|
313
|
+
}
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Delete key-value to the urlState
|
317
|
+
* @param {string} key
|
318
|
+
*/
|
319
|
+
removeUrlParam(key) {
|
320
|
+
delete this.urlState[key];
|
321
|
+
|
322
|
+
this.pushToAddressBar();
|
323
|
+
}
|
324
|
+
|
325
|
+
/**
|
326
|
+
* Get key-value from the urlState
|
327
|
+
* @param {string} key
|
328
|
+
* @return {string}
|
329
|
+
*/
|
330
|
+
getUrlParam(key) {
|
331
|
+
return this.urlState[key];
|
332
|
+
}
|
333
|
+
|
334
|
+
/**
|
335
|
+
* Push URL params to addressbar
|
336
|
+
*/
|
337
|
+
pushToAddressBar() {
|
338
|
+
const urlStrPath = this.urlStateToUrlString(this.urlSchema, this.urlState);
|
339
|
+
if (this.urlMode == 'history') {
|
340
|
+
if (window.history && window.history.replaceState) {
|
341
|
+
const newUrlPath = `${this.urlHistoryBasePath}${urlStrPath}`;
|
342
|
+
window.history.replaceState({}, null, newUrlPath);
|
343
|
+
}
|
344
|
+
} else {
|
345
|
+
window.location.replace('#' + urlStrPath);
|
346
|
+
}
|
347
|
+
this.oldLocationHash = urlStrPath;
|
348
|
+
}
|
349
|
+
|
350
|
+
/**
|
351
|
+
* Get the url and check if it has changed
|
352
|
+
* If it was changeed, update the urlState
|
353
|
+
*/
|
354
|
+
listenForHashChanges() {
|
355
|
+
this.oldLocationHash = window.location.hash.substr(1);
|
356
|
+
if (this.urlLocationPollId) {
|
357
|
+
clearInterval(this.urlLocationPollId);
|
358
|
+
this.urlLocationPollId = null;
|
359
|
+
}
|
360
|
+
|
361
|
+
// check if the URL changes
|
362
|
+
const updateHash = () => {
|
363
|
+
const newFragment = window.location.hash.substr(1);
|
364
|
+
const hasFragmentChange = newFragment != this.oldLocationHash;
|
365
|
+
|
366
|
+
if (!hasFragmentChange) { return; }
|
367
|
+
|
368
|
+
this.urlState = this.urlStringToUrlState(newFragment);
|
369
|
+
};
|
370
|
+
this.urlLocationPollId = setInterval(updateHash, 500);
|
371
|
+
}
|
372
|
+
|
373
|
+
/**
|
374
|
+
* Will read either the hash or URL and return the bookreader fragment
|
375
|
+
* @param {string} location
|
376
|
+
* @return {string}
|
377
|
+
*/
|
378
|
+
pullFromAddressBar (location) {
|
379
|
+
const path = this.urlMode === 'history'
|
380
|
+
? location.substr(this.urlHistoryBasePath.length)
|
381
|
+
: location.substr(1);
|
382
|
+
this.urlState = this.urlStringToUrlState(this.urlSchema, path);
|
383
|
+
}
|
384
|
+
}
|
385
|
+
export class BookreaderUrlPlugin extends BookReader {
|
386
|
+
|
387
|
+
init() {
|
388
|
+
if (this.options.enableUrlPlugin) {
|
389
|
+
this.urlPlugin = new UrlPlugin(this.options);
|
390
|
+
this.bind(BookReader.eventNames.PostInit, () => {
|
391
|
+
const { urlMode } = this.options;
|
392
|
+
|
393
|
+
if (urlMode === 'hash') {
|
394
|
+
this.urlPlugin.listenForHashChanges();
|
395
|
+
}
|
396
|
+
});
|
397
|
+
}
|
398
|
+
|
399
|
+
super.init();
|
400
|
+
}
|
401
|
+
|
402
|
+
}
|
403
|
+
|
404
|
+
window.BookReader = BookreaderUrlPlugin;
|
405
|
+
export default BookreaderUrlPlugin;
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
1
|
import BookReader from '@/src/BookReader.js';
|
3
2
|
import '@/src/plugins/plugin.url.js';
|
3
|
+
import { UrlPlugin } from '@/src/plugins/plugin.url.js';
|
4
|
+
import sinon from 'sinon';
|
4
5
|
|
5
6
|
let br;
|
6
7
|
beforeAll(() => {
|
@@ -10,6 +11,164 @@ beforeAll(() => {
|
|
10
11
|
|
11
12
|
afterEach(() => {
|
12
13
|
jest.clearAllMocks();
|
14
|
+
sinon.restore();
|
15
|
+
});
|
16
|
+
|
17
|
+
|
18
|
+
describe.only('UrlPlugin tests', () => {
|
19
|
+
const urlPlugin = new UrlPlugin();
|
20
|
+
const urlSchema = [
|
21
|
+
{ name: 'page', position: 'path', default: 'n0' },
|
22
|
+
{ name: 'mode', position: 'path', default: '2up' },
|
23
|
+
{ name: 'search', position: 'path', deprecated_for: 'q' },
|
24
|
+
{ name: 'q', position: 'query_param' },
|
25
|
+
{ name: 'sort', position: 'query_param' },
|
26
|
+
{ name: 'view', position: 'query_param' },
|
27
|
+
{ name: 'admin', position: 'query_param' },
|
28
|
+
];
|
29
|
+
|
30
|
+
describe('urlStateToUrlString tests', () => {
|
31
|
+
test('urlStateToUrlString with known states in schema', () => {
|
32
|
+
const urlState = { page: 'n7', mode: '1up', search: 'foo' };
|
33
|
+
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', view: 'theater', sort: 'title_asc' };
|
34
|
+
|
35
|
+
const expectedUrlFromState = '/page/n7/mode/1up?q=foo';
|
36
|
+
const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&view=theater&sort=title_asc';
|
37
|
+
|
38
|
+
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
39
|
+
expect(urlPlugin.urlStateToUrlString(urlSchema, urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
40
|
+
});
|
41
|
+
|
42
|
+
test('urlStateToUrlString with unknown states in schema', () => {
|
43
|
+
const urlState = { page: 'n7', mode: '1up' };
|
44
|
+
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', viewer: 'theater', sortBy: 'title_asc' };
|
45
|
+
|
46
|
+
const expectedUrlFromState = '/page/n7/mode/1up';
|
47
|
+
const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&viewer=theater&sortBy=title_asc';
|
48
|
+
|
49
|
+
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
50
|
+
expect(urlPlugin.urlStateToUrlString(urlSchema, urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
51
|
+
});
|
52
|
+
|
53
|
+
test('urlStateToUrlString with boolean value', () => {
|
54
|
+
const urlState = { page: 'n7', mode: '1up', search: 'foo', view: 'theater', wrapper: false };
|
55
|
+
const expectedUrlFromState = '/page/n7/mode/1up?q=foo&view=theater&wrapper=false';
|
56
|
+
|
57
|
+
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
describe('urlStringToUrlState tests', () => {
|
62
|
+
test('urlStringToUrlState without query string', () => {
|
63
|
+
const url = '/page/n7/mode/2up';
|
64
|
+
const url1 = '/page/n7/mode/1up';
|
65
|
+
|
66
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up'});
|
67
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url1)).toEqual({page: 'n7', mode: '1up'});
|
68
|
+
});
|
69
|
+
|
70
|
+
test('urlStringToUrlState with deprecated_for', () => {
|
71
|
+
const url = '/page/n7/mode/2up/search/hello';
|
72
|
+
|
73
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
74
|
+
});
|
75
|
+
|
76
|
+
test('urlStringToUrlState with query string', () => {
|
77
|
+
const url = '/page/n7/mode/2up/search/hello?view=theather&foo=bar&sort=title_asc';
|
78
|
+
const url1 = '/mode/2up?ref=ol&ui=embed&wrapper=false&view=theater';
|
79
|
+
|
80
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual(
|
81
|
+
{page: 'n7', mode: '2up', q: 'hello', view: 'theather', foo: 'bar', sort: 'title_asc'}
|
82
|
+
);
|
83
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url1)).toEqual(
|
84
|
+
{page: 'n0', mode: '2up', ref: 'ol', ui: 'embed', wrapper: false, view: 'theater'}
|
85
|
+
);
|
86
|
+
});
|
87
|
+
|
88
|
+
test('urlStringToUrlState compare search and ?q', () => {
|
89
|
+
const url = '/page/n7/mode/2up/search/hello';
|
90
|
+
urlPlugin.urlState = { q: 'hello' };
|
91
|
+
|
92
|
+
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
93
|
+
});
|
94
|
+
});
|
95
|
+
|
96
|
+
describe('url plugin helper functions', () => {
|
97
|
+
test('setUrlParam', () => {
|
98
|
+
urlPlugin.urlState = {};
|
99
|
+
urlPlugin.setUrlParam('page', '20');
|
100
|
+
urlPlugin.setUrlParam('mode', '2up');
|
101
|
+
|
102
|
+
expect(urlPlugin.urlState).toEqual({page: '20', mode: '2up'});
|
103
|
+
});
|
104
|
+
|
105
|
+
test('removeUrlParam', () => {
|
106
|
+
urlPlugin.setUrlParam('page', '20');
|
107
|
+
urlPlugin.setUrlParam('mode', '2up');
|
108
|
+
urlPlugin.removeUrlParam('mode');
|
109
|
+
|
110
|
+
expect(urlPlugin.urlState).toEqual({page: '20'});
|
111
|
+
});
|
112
|
+
|
113
|
+
test('getUrlParam', () => {
|
114
|
+
urlPlugin.setUrlParam('page', '20');
|
115
|
+
urlPlugin.setUrlParam('mode', '2up');
|
116
|
+
expect(urlPlugin.getUrlParam('page')).toEqual('20');
|
117
|
+
expect(urlPlugin.getUrlParam('mode')).toEqual('2up');
|
118
|
+
});
|
119
|
+
});
|
120
|
+
|
121
|
+
describe('pullFromAddressBar and pushToAddressBar - hash mode', () => {
|
122
|
+
test('url without mode state value - use default', () => {
|
123
|
+
urlPlugin.urlState = {};
|
124
|
+
urlPlugin.urlMode = 'hash';
|
125
|
+
|
126
|
+
urlPlugin.pullFromAddressBar('/page/12');
|
127
|
+
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
|
128
|
+
|
129
|
+
urlPlugin.pushToAddressBar();
|
130
|
+
expect(window.location.hash).toEqual('#/page/12/mode/2up');
|
131
|
+
});
|
132
|
+
|
133
|
+
test('url with query param', () => {
|
134
|
+
urlPlugin.urlState = {};
|
135
|
+
urlPlugin.urlMode = 'hash';
|
136
|
+
|
137
|
+
urlPlugin.pullFromAddressBar('/page/12/search/hello?view=theater');
|
138
|
+
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
|
139
|
+
|
140
|
+
urlPlugin.pushToAddressBar();
|
141
|
+
expect(window.location.hash).toEqual('#/page/12/mode/2up?q=hello&view=theater');
|
142
|
+
});
|
143
|
+
});
|
144
|
+
|
145
|
+
describe('pullFromAddressBar and pushToAddressBar - history mode', () => {
|
146
|
+
test('url without mode state value - use default', () => {
|
147
|
+
urlPlugin.urlState = {};
|
148
|
+
urlPlugin.urlHistoryBasePath = '/details/foo';
|
149
|
+
urlPlugin.urlMode = 'history';
|
150
|
+
|
151
|
+
urlPlugin.pullFromAddressBar('/details/foo/page/12');
|
152
|
+
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
|
153
|
+
|
154
|
+
urlPlugin.pushToAddressBar();
|
155
|
+
expect(window.location.pathname).toEqual('/details/foo/page/12/mode/2up');
|
156
|
+
});
|
157
|
+
|
158
|
+
test('url with query param', () => {
|
159
|
+
urlPlugin.urlState = {};
|
160
|
+
urlPlugin.urlHistoryBasePath = '/details/foo';
|
161
|
+
urlPlugin.urlMode = 'history';
|
162
|
+
|
163
|
+
urlPlugin.pullFromAddressBar('/details/foo/page/12/search/hello?view=theater');
|
164
|
+
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
|
165
|
+
|
166
|
+
urlPlugin.pushToAddressBar();
|
167
|
+
const locationUrl = `${window.location.pathname}${window.location.search}`;
|
168
|
+
expect(locationUrl).toEqual('/details/foo/page/12/mode/2up?q=hello&view=theater');
|
169
|
+
});
|
170
|
+
});
|
171
|
+
|
13
172
|
});
|
14
173
|
|
15
174
|
describe('Plugin: URL controller', () => {
|
@@ -64,7 +64,7 @@ describe('Volumes Provider', () => {
|
|
64
64
|
const baseHost = "https://archive.org";
|
65
65
|
const provider = new volumesProvider(baseHost, brOptions, onSortClick);
|
66
66
|
|
67
|
-
expect(provider.sortOrderBy).to.equal("
|
67
|
+
expect(provider.sortOrderBy).to.equal("default");
|
68
68
|
|
69
69
|
provider.sortVolumes("title_asc");
|
70
70
|
expect(provider.sortOrderBy).to.equal("title_asc");
|
@@ -74,8 +74,8 @@ describe('Volumes Provider', () => {
|
|
74
74
|
expect(provider.sortOrderBy).to.equal("title_desc");
|
75
75
|
expect(provider.sortButton.getHTML()).includes("sort-by desc-icon");
|
76
76
|
|
77
|
-
provider.sortVolumes("
|
78
|
-
expect(provider.sortOrderBy).to.equal("
|
77
|
+
provider.sortVolumes("default");
|
78
|
+
expect(provider.sortOrderBy).to.equal("default");
|
79
79
|
expect(provider.sortButton.getHTML()).includes("sort-by neutral-icon");
|
80
80
|
});
|
81
81
|
|
@@ -88,9 +88,9 @@ describe('Volumes Provider', () => {
|
|
88
88
|
const files = Object.keys(parsedFiles).map(item => parsedFiles[item]).sort((a, b) => a.orig_sort - b.orig_sort);
|
89
89
|
const origSortTitles = files.map(item => item.title);
|
90
90
|
|
91
|
-
provider.sortVolumes("
|
91
|
+
provider.sortVolumes("default");
|
92
92
|
|
93
|
-
expect(provider.sortOrderBy).to.equal("
|
93
|
+
expect(provider.sortOrderBy).to.equal("default");
|
94
94
|
expect(provider.actionButton).to.exist;
|
95
95
|
|
96
96
|
const providerFileTitles = provider.viewableFiles.map(item => item.title);
|
@@ -144,7 +144,7 @@ describe('Volumes Provider', () => {
|
|
144
144
|
const baseHost = "https://archive.org";
|
145
145
|
const provider = new volumesProvider(baseHost, brOptions, onSortClick);
|
146
146
|
|
147
|
-
provider.sortOrderBy = '
|
147
|
+
provider.sortOrderBy = 'default';
|
148
148
|
const origSortButton = await fixture(provider.sortButton);
|
149
149
|
expect(origSortButton.classList.contains('neutral-icon')).to.be.true;
|
150
150
|
|