@internetarchive/bookreader 5.0.0-24-sortingstate-11 → 5.0.0-26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/BookReader/BookReader.css +4 -0
  2. package/BookReader/BookReader.js +2 -32145
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/bookreader-component-bundle.js +1286 -11256
  5. package/BookReader/bookreader-component-bundle.js.map +1 -1
  6. package/BookReader/icons/1up.svg +1 -12
  7. package/BookReader/icons/2up.svg +1 -15
  8. package/BookReader/icons/advance.svg +3 -26
  9. package/BookReader/icons/chevron-right.svg +1 -1
  10. package/BookReader/icons/close-circle-dark.svg +1 -1
  11. package/BookReader/icons/close-circle.svg +1 -1
  12. package/BookReader/icons/fullscreen.svg +1 -17
  13. package/BookReader/icons/fullscreen_exit.svg +1 -17
  14. package/BookReader/icons/hamburger.svg +1 -15
  15. package/BookReader/icons/left-arrow.svg +1 -12
  16. package/BookReader/icons/magnify-minus.svg +1 -16
  17. package/BookReader/icons/magnify-plus.svg +1 -17
  18. package/BookReader/icons/magnify.svg +1 -15
  19. package/BookReader/icons/pause.svg +1 -23
  20. package/BookReader/icons/play.svg +1 -22
  21. package/BookReader/icons/playback-speed.svg +1 -34
  22. package/BookReader/icons/read-aloud.svg +1 -22
  23. package/BookReader/icons/review.svg +3 -22
  24. package/BookReader/icons/thumbnails.svg +1 -17
  25. package/BookReader/icons/voice.svg +1 -1
  26. package/BookReader/icons/volume-full.svg +1 -22
  27. package/BookReader/images/BRicons.svg +5 -94
  28. package/BookReader/images/books_graphic.svg +1 -177
  29. package/BookReader/images/icon_book.svg +1 -12
  30. package/BookReader/images/icon_bookmark.svg +1 -12
  31. package/BookReader/images/icon_gear.svg +1 -14
  32. package/BookReader/images/icon_hamburger.svg +1 -20
  33. package/BookReader/images/icon_home.svg +1 -21
  34. package/BookReader/images/icon_info.svg +1 -11
  35. package/BookReader/images/icon_one_page.svg +1 -8
  36. package/BookReader/images/icon_pause.svg +1 -1
  37. package/BookReader/images/icon_play.svg +1 -1
  38. package/BookReader/images/icon_playback-rate.svg +1 -15
  39. package/BookReader/images/icon_search_button.svg +1 -8
  40. package/BookReader/images/icon_share.svg +1 -9
  41. package/BookReader/images/icon_skip-ahead.svg +1 -6
  42. package/BookReader/images/icon_skip-back.svg +2 -13
  43. package/BookReader/images/icon_speaker.svg +1 -18
  44. package/BookReader/images/icon_speaker_open.svg +1 -10
  45. package/BookReader/images/icon_thumbnails.svg +1 -12
  46. package/BookReader/images/icon_toc.svg +1 -5
  47. package/BookReader/images/icon_two_pages.svg +1 -9
  48. package/BookReader/images/marker_chap-off.svg +1 -11
  49. package/BookReader/images/marker_chap-on.svg +1 -11
  50. package/BookReader/images/marker_srch-on.svg +1 -11
  51. package/BookReader/jquery-1.10.1.js +2 -108
  52. package/BookReader/plugins/plugin.archive_analytics.js +1 -170
  53. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  54. package/BookReader/plugins/plugin.autoplay.js +1 -163
  55. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  56. package/BookReader/plugins/plugin.chapters.js +1 -333
  57. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  58. package/BookReader/plugins/plugin.iframe.js +1 -72
  59. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  60. package/BookReader/plugins/plugin.mobile_nav.js +1 -332
  61. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  62. package/BookReader/plugins/plugin.resume.js +1 -241
  63. package/BookReader/plugins/plugin.resume.js.map +1 -1
  64. package/BookReader/plugins/plugin.search.js +1 -1263
  65. package/BookReader/plugins/plugin.search.js.map +1 -1
  66. package/BookReader/plugins/plugin.text_selection.js +1 -839
  67. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  68. package/BookReader/plugins/plugin.tts.js +2 -9114
  69. package/BookReader/plugins/plugin.tts.js.map +1 -1
  70. package/BookReader/plugins/plugin.url.js +1 -768
  71. package/BookReader/plugins/plugin.url.js.map +1 -1
  72. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -326
  73. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  74. package/BookReader/webcomponents-bundle.js +2 -411
  75. package/BookReader/webcomponents-bundle.js.map +1 -1
  76. package/BookReaderDemo/demo-internetarchive.html +86 -4
  77. package/CHANGELOG.md +5 -0
  78. package/package.json +1 -1
  79. package/src/BookNavigator/bookmarks/ia-bookmarks.js +1 -0
  80. package/src/BookNavigator/volumes/volumes-provider.js +9 -40
  81. package/src/BookReader.js +102 -64
  82. package/src/css/_controls.scss +4 -0
  83. package/src/plugins/plugin.url.js +2 -218
  84. package/tests/jest/BookReader.keyboard.test.js +190 -0
  85. package/tests/jest/plugins/plugin.url.test.js +1 -151
  86. package/.nvmrc +0 -1
@@ -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(this.bookTitle, 50);
53
+ document.title = this.shortTitle(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.locationPollId);
89
+ clearInterval(this.locationPollID);
90
90
  this.locationPollId = null;
91
91
  }
92
92
 
@@ -196,219 +196,3 @@ 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
- // the canonical order of elements is important in the path and query string
204
- this.urlSchema = [
205
- { name: 'page', position: 'path', default: 'n0' },
206
- { name: 'mode', position: 'path', default: '2up' },
207
- { name: 'search', position: 'path', deprecated_for: 'q' },
208
- { name: 'q', position: 'query_param' },
209
- { name: 'sort', position: 'query_param' },
210
- { name: 'view', position: 'query_param' },
211
- { name: 'admin', position: 'query_param' },
212
- ];
213
-
214
- this.urlState = {};
215
- this.urlMode = this.bookReaderOptions.urlMode || 'hash';
216
- this.urlHistoryBasePath = this.bookReaderOptions.urlHistoryBasePath || '/';
217
- this.urlLocationPollId = null;
218
- this.oldLocationHash = null;
219
- this.oldUserHash = null;
220
- }
221
-
222
- /**
223
- * Parse JSON object URL state to string format
224
- * Arrange path names in an order that it is positioned on the urlSchema
225
- * @param {Object} urlState
226
- * @returns {string}
227
- */
228
- urlStateToUrlString(urlState) {
229
- const searchParams = new URLSearchParams();
230
- const pathParams = {};
231
-
232
- Object.keys(urlState).forEach(key => {
233
- let schema = this.urlSchema.find(schema => schema.name === key);
234
- if (schema?.deprecated_for) {
235
- schema = this.urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
236
- }
237
- if (schema?.position == 'path') {
238
- pathParams[schema?.name] = urlState[key];
239
- } else {
240
- searchParams.append(schema?.name || key, urlState[key]);
241
- }
242
- });
243
-
244
- const strPathParams = this.urlSchema
245
- .filter(s => s.position == 'path')
246
- .map(schema => pathParams[schema.name] ? `${schema.name}/${pathParams[schema.name]}` : '')
247
- .join('/');
248
-
249
- const strStrippedTrailingSlash = `${strPathParams.replace(/\/$/, '')}`;
250
- const concatenatedPath = `/${strStrippedTrailingSlash}?${searchParams.toString()}`;
251
- return searchParams.toString() ? concatenatedPath : `/${strStrippedTrailingSlash}`;
252
- }
253
-
254
- /**
255
- * Parse string URL and add it in the current urlState
256
- * Example:
257
- * /page/n7/mode/2up => {page: 'n7', mode: '2up'}
258
- * /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}
259
- * @param {string} urlString
260
- * @returns {object}
261
- */
262
- urlStringToUrlState(urlString) {
263
- console.log('urlString: ', urlString);
264
- const urlState = {};
265
-
266
- // Fetch searchParams from given {urlString}
267
- // Note: whole URL path is needed for URLSearchParams
268
- const urlPath = new URL(urlString, 'http://example.com');
269
- console.log('urlPath: ', urlPath);
270
- console.log('urlSearch: ', urlPath.searchParams, ' urlPath: ', urlPath.pathname);
271
- const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());
272
- const urlStrSplitSlashObj = Object.fromEntries(urlPath.pathname
273
- .match(/[^\\/]+\/[^\\/]+/g)
274
- .map(x => x.split('/'))
275
- );
276
- const doesKeyExists = (_object, _key) => {
277
- return Object.keys(_object).some(value => value == _key);
278
- };
279
-
280
- // Add path objects to urlState
281
- this.urlSchema
282
- .filter(schema => schema.position == 'path')
283
- .forEach(schema => {
284
- if (!urlStrSplitSlashObj[schema.name] && schema.default) {
285
- return urlState[schema.name] = schema.default;
286
- }
287
- const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
288
- const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
289
-
290
- if (hasDeprecatedKey) {
291
- urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];
292
- return;
293
- }
294
-
295
- if (hasPropertyKey) {
296
- urlState[schema.name] = urlStrSplitSlashObj[schema.name];
297
- return;
298
- }
299
- });
300
-
301
- // Add searchParams to urlState
302
- // Check if Object value is a Boolean and convert value to Boolean
303
- // Otherwise, return Object value
304
- const isBooleanValue = value => value === 'true' || (value === 'false' ? false : value);
305
- Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
306
- urlState[key] = isBooleanValue(value);
307
- });
308
-
309
- return urlState;
310
- }
311
-
312
- /**
313
- * Add or update key-value to the urlState
314
- * @param {string} key
315
- * @param {string} val
316
- */
317
- setUrlParam(key, value) {
318
- this.urlState[key] = value;
319
-
320
- this.pushToAddressBar();
321
- }
322
-
323
- /**
324
- * Delete key-value to the urlState
325
- * @param {string} key
326
- */
327
- removeUrlParam(key) {
328
- delete this.urlState[key];
329
-
330
- this.pushToAddressBar();
331
- }
332
-
333
- /**
334
- * Get key-value from the urlState
335
- * @param {string} key
336
- * @return {string}
337
- */
338
- getUrlParam(key) {
339
- return this.urlState[key];
340
- }
341
-
342
- /**
343
- * Push URL params to addressbar
344
- */
345
- pushToAddressBar() {
346
- const urlStrPath = this.urlStateToUrlString(this.urlState);
347
- if (this.urlMode == 'history') {
348
- if (window.history && window.history.replaceState) {
349
- const newUrlPath = `${this.urlHistoryBasePath}${urlStrPath}`;
350
- console.log('newUrlPath: ', newUrlPath);
351
- window.history.replaceState({}, null, newUrlPath);
352
- }
353
- } else {
354
- window.location.replace('#' + urlStrPath);
355
- }
356
- this.oldLocationHash = urlStrPath;
357
- }
358
-
359
- /**
360
- * Get the url and check if it has changed
361
- * If it was changeed, update the urlState
362
- */
363
- listenForHashChanges() {
364
- this.oldLocationHash = window.location.hash.substr(1);
365
- if (this.urlLocationPollId) {
366
- clearInterval(this.urlLocationPollId);
367
- this.urlLocationPollId = null;
368
- }
369
-
370
- // check if the URL changes
371
- const updateHash = () => {
372
- const newFragment = window.location.hash.substr(1);
373
- const hasFragmentChange = newFragment != this.oldLocationHash;
374
-
375
- if (!hasFragmentChange) { return; }
376
-
377
- this.urlState = this.urlStringToUrlState(newFragment);
378
- };
379
- this.urlLocationPollId = setInterval(updateHash, 500);
380
- }
381
-
382
- /**
383
- * Will read either the hash or URL and return the bookreader fragment
384
- */
385
- pullFromAddressBar (location = window.location) {
386
- const path = this.urlMode === 'history'
387
- ? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)
388
- : location.hash.substr(1);
389
- console.log('path: ', path);
390
- this.urlState = this.urlStringToUrlState(path);
391
- }
392
- }
393
-
394
- export class BookreaderUrlPlugin extends BookReader {
395
-
396
- init() {
397
- if (this.options.enableUrlPlugin) {
398
- this.urlPlugin = new UrlPlugin(this.options);
399
- this.bind(BookReader.eventNames.PostInit, () => {
400
- const { urlMode } = this.options;
401
-
402
- if (urlMode === 'hash') {
403
- this.urlPlugin.listenForHashChanges();
404
- }
405
- });
406
- }
407
-
408
- super.init();
409
- }
410
-
411
- }
412
-
413
- window.BookReader = BookreaderUrlPlugin;
414
- export default BookreaderUrlPlugin;
@@ -0,0 +1,190 @@
1
+ import BookReader from '@/src/BookReader.js';
2
+ import * as utils from '@/src/BookReader/utils.js';
3
+
4
+ let br;
5
+ beforeAll(() => {
6
+ document.body.innerHTML = '<div id="BookReader">';
7
+ br = new BookReader();
8
+ });
9
+
10
+ afterEach(() => {
11
+ jest.clearAllMocks();
12
+ });
13
+
14
+ /**
15
+ * Only run init() once. Otherwise multiple EventListeners will be added.
16
+ */
17
+ test('Initialzation enables IntersectionObserver and defaults', () => {
18
+ const observe = jest.fn();
19
+ window.IntersectionObserver = jest.fn(() => ({
20
+ observe
21
+ }));
22
+ br.init();
23
+ expect(br.hasKeyFocus).toBe(true);
24
+ expect(observe).toHaveBeenCalledTimes(1);
25
+ });
26
+
27
+ describe('Keyboard shortcuts turned off', () => {
28
+
29
+ test('Focus flag disables', () => {
30
+ br.next = jest.fn();
31
+ br.hasKeyFocus = false;
32
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowDown'});
33
+ keyEvent.preventDefault = jest.fn();
34
+ document.dispatchEvent(keyEvent);
35
+ expect(br.next).toHaveBeenCalledTimes(0);
36
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(0);
37
+ // Must reset for following tests
38
+ br.hasKeyFocus = true;
39
+ });
40
+
41
+ test('Input active disables', () => {
42
+ // eslint-disable-next-line no-import-assign
43
+ utils.isInputActive = jest.fn(() => true);
44
+ br.next = jest.fn();
45
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowDown'});
46
+ keyEvent.preventDefault = jest.fn();
47
+ document.dispatchEvent(keyEvent);
48
+ expect(br.next).toHaveBeenCalledTimes(0);
49
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(0);
50
+ // Must reset for following tests
51
+ utils.isInputActive.mockReset();
52
+ });
53
+
54
+ });
55
+
56
+ describe('Keyboard shortcuts', () => {
57
+
58
+ test('Home key', () => {
59
+ br.first = jest.fn();
60
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'Home'});
61
+ keyEvent.preventDefault = jest.fn();
62
+ document.dispatchEvent(keyEvent);
63
+ expect(br.first).toHaveBeenCalledTimes(1);
64
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
65
+ });
66
+
67
+ test('End key', () => {
68
+ br.last = jest.fn();
69
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'End'});
70
+ keyEvent.preventDefault = jest.fn();
71
+ document.dispatchEvent(keyEvent);
72
+ expect(br.last).toHaveBeenCalledTimes(1);
73
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
74
+ });
75
+
76
+ test('ArrowDown key', () => {
77
+ br.mode = br.constMode2up;
78
+ br.next = jest.fn();
79
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowDown'});
80
+ keyEvent.preventDefault = jest.fn();
81
+ document.dispatchEvent(keyEvent);
82
+ expect(br.next).toHaveBeenCalledTimes(1);
83
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
84
+ });
85
+
86
+ test('PageDown key', () => {
87
+ br.mode = br.constMode2up;
88
+ br.next = jest.fn();
89
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'PageDown'});
90
+ keyEvent.preventDefault = jest.fn();
91
+ document.dispatchEvent(keyEvent);
92
+ expect(br.next).toHaveBeenCalledTimes(1);
93
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
94
+ });
95
+
96
+ test('ArrowUp key', () => {
97
+ br.mode = br.constMode2up;
98
+ br.prev = jest.fn();
99
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowUp'});
100
+ keyEvent.preventDefault = jest.fn();
101
+ document.dispatchEvent(keyEvent);
102
+ expect(br.prev).toHaveBeenCalledTimes(1);
103
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
104
+ });
105
+
106
+ test('PageUp key', () => {
107
+ br.mode = br.constMode2up;
108
+ br.prev = jest.fn();
109
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'PageUp'});
110
+ keyEvent.preventDefault = jest.fn();
111
+ document.dispatchEvent(keyEvent);
112
+ expect(br.prev).toHaveBeenCalledTimes(1);
113
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
114
+ });
115
+
116
+ test('ArrowLeft key', () => {
117
+ br.mode = br.constMode2up;
118
+ br.left = jest.fn();
119
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowLeft'});
120
+ keyEvent.preventDefault = jest.fn();
121
+ document.dispatchEvent(keyEvent);
122
+ expect(br.left).toHaveBeenCalledTimes(1);
123
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
124
+ });
125
+
126
+ test('ArrowRight key', () => {
127
+ br.mode = br.constMode2up;
128
+ br.right = jest.fn();
129
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'ArrowRight'});
130
+ keyEvent.preventDefault = jest.fn();
131
+ document.dispatchEvent(keyEvent);
132
+ expect(br.right).toHaveBeenCalledTimes(1);
133
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
134
+ });
135
+
136
+ test('Subtract key', () => {
137
+ br.zoom = jest.fn();
138
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'Subtract'});
139
+ keyEvent.preventDefault = jest.fn();
140
+ document.dispatchEvent(keyEvent);
141
+ expect(br.zoom).toHaveBeenCalledTimes(1);
142
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
143
+ });
144
+
145
+ test('- key', () => {
146
+ br.zoom = jest.fn();
147
+ const keyEvent = new KeyboardEvent('keydown', {'key': '-'});
148
+ keyEvent.preventDefault = jest.fn();
149
+ document.dispatchEvent(keyEvent);
150
+ expect(br.zoom).toHaveBeenCalledTimes(1);
151
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
152
+ });
153
+
154
+ test('Add key', () => {
155
+ br.zoom = jest.fn();
156
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'Add'});
157
+ keyEvent.preventDefault = jest.fn();
158
+ document.dispatchEvent(keyEvent);
159
+ expect(br.zoom).toHaveBeenCalledTimes(1);
160
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
161
+ });
162
+
163
+ test('+ key', () => {
164
+ br.zoom = jest.fn();
165
+ const keyEvent = new KeyboardEvent('keydown', {'key': '+'});
166
+ keyEvent.preventDefault = jest.fn();
167
+ document.dispatchEvent(keyEvent);
168
+ expect(br.zoom).toHaveBeenCalledTimes(1);
169
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
170
+ });
171
+
172
+ test('= key', () => {
173
+ br.zoom = jest.fn();
174
+ const keyEvent = new KeyboardEvent('keydown', {'key': '='});
175
+ keyEvent.preventDefault = jest.fn();
176
+ document.dispatchEvent(keyEvent);
177
+ expect(br.zoom).toHaveBeenCalledTimes(1);
178
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
179
+ });
180
+
181
+ test('F key', () => {
182
+ br.toggleFullscreen = jest.fn();
183
+ const keyEvent = new KeyboardEvent('keydown', {'key': 'F'});
184
+ keyEvent.preventDefault = jest.fn();
185
+ document.dispatchEvent(keyEvent);
186
+ expect(br.toggleFullscreen).toHaveBeenCalledTimes(1);
187
+ expect(keyEvent.preventDefault).toHaveBeenCalledTimes(1);
188
+ });
189
+
190
+ });
@@ -1,7 +1,6 @@
1
+
1
2
  import BookReader from '@/src/BookReader.js';
2
3
  import '@/src/plugins/plugin.url.js';
3
- import { UrlPlugin } from '@/src/plugins/plugin.url.js';
4
- import sinon from 'sinon';
5
4
 
6
5
  let br;
7
6
  beforeAll(() => {
@@ -11,155 +10,6 @@ beforeAll(() => {
11
10
 
12
11
  afterEach(() => {
13
12
  jest.clearAllMocks();
14
- sinon.restore();
15
- });
16
-
17
-
18
- describe.only('UrlPlugin tests', () => {
19
- const urlPlugin = new UrlPlugin();
20
-
21
- describe('urlStateToUrlString tests', () => {
22
- test('urlStateToUrlString with known states in schema', () => {
23
- const urlState = { page: 'n7', mode: '1up', search: 'foo' };
24
- const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', view: 'theater', sort: 'title_asc' };
25
-
26
- const expectedUrlFromState = '/page/n7/mode/1up?q=foo';
27
- const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&view=theater&sort=title_asc';
28
-
29
- expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
30
- expect(urlPlugin.urlStateToUrlString(urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
31
- });
32
-
33
- test('urlStateToUrlString with unknown states in schema', () => {
34
- const urlState = { page: 'n7', mode: '1up' };
35
- const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', viewer: 'theater', sortBy: 'title_asc' };
36
-
37
- const expectedUrlFromState = '/page/n7/mode/1up';
38
- const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&viewer=theater&sortBy=title_asc';
39
-
40
- expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
41
- expect(urlPlugin.urlStateToUrlString(urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
42
- });
43
-
44
- test('urlStateToUrlString with boolean value', () => {
45
- const urlState = { page: 'n7', mode: '1up', search: 'foo', view: 'theater', wrapper: false };
46
- const expectedUrlFromState = '/page/n7/mode/1up?q=foo&view=theater&wrapper=false';
47
-
48
- expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
49
- });
50
- });
51
-
52
- describe('urlStringToUrlState tests', () => {
53
- test('urlStringToUrlState without query string', () => {
54
- const url = '/page/n7/mode/2up';
55
- const url1 = '/page/n7/mode/1up';
56
-
57
- expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up'});
58
- expect(urlPlugin.urlStringToUrlState(url1)).toEqual({page: 'n7', mode: '1up'});
59
- });
60
-
61
- test('urlStringToUrlState with deprecated_for', () => {
62
- const url = '/page/n7/mode/2up/search/hello';
63
-
64
- expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
65
- });
66
-
67
- test('urlStringToUrlState with query string', () => {
68
- const url = '/page/n7/mode/2up/search/hello?view=theather&foo=bar&sort=title_asc';
69
- const url1 = '/mode/2up?ref=ol&ui=embed&wrapper=false&view=theater';
70
-
71
- expect(urlPlugin.urlStringToUrlState(url)).toEqual(
72
- {page: 'n7', mode: '2up', q: 'hello', view: 'theather', foo: 'bar', sort: 'title_asc'}
73
- );
74
- expect(urlPlugin.urlStringToUrlState(url1)).toEqual(
75
- {page: 'n0', mode: '2up', ref: 'ol', ui: 'embed', wrapper: false, view: 'theater'}
76
- );
77
- });
78
-
79
- test('urlStringToUrlState compare search and ?q', () => {
80
- const url = '/page/n7/mode/2up/search/hello';
81
- urlPlugin.urlState = { q: 'hello' };
82
-
83
- expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
84
- });
85
- });
86
-
87
- describe('url plugin helper functions', () => {
88
- test('setUrlParam', () => {
89
- urlPlugin.urlState = {};
90
- urlPlugin.setUrlParam('page', '20');
91
- urlPlugin.setUrlParam('mode', '2up');
92
-
93
- expect(urlPlugin.urlState).toEqual({page: '20', mode: '2up'});
94
- });
95
-
96
- test('removeUrlParam', () => {
97
- urlPlugin.setUrlParam('page', '20');
98
- urlPlugin.setUrlParam('mode', '2up');
99
- urlPlugin.removeUrlParam('mode');
100
-
101
- expect(urlPlugin.urlState).toEqual({page: '20'});
102
- });
103
-
104
- test('getUrlParam', () => {
105
- urlPlugin.setUrlParam('page', '20');
106
- urlPlugin.setUrlParam('mode', '2up');
107
- expect(urlPlugin.getUrlParam('page')).toEqual('20');
108
- expect(urlPlugin.getUrlParam('mode')).toEqual('2up');
109
- });
110
- });
111
-
112
- describe('pullFromAddressBar and pushToAddressBar - hash mode', () => {
113
- test('url without mode state value - use default', () => {
114
- urlPlugin.urlState = {};
115
- urlPlugin.urlMode = 'hash';
116
-
117
- urlPlugin.pullFromAddressBar({ pathname: '/page/12', search: '', hash: '' });
118
- expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
119
-
120
- urlPlugin.pushToAddressBar();
121
- expect(window.location.hash).toEqual('#/page/12/mode/2up');
122
- });
123
-
124
- test('url with query param', () => {
125
- urlPlugin.urlState = {};
126
- urlPlugin.urlMode = 'hash';
127
-
128
- urlPlugin.pullFromAddressBar({ pathname: '/page/12', search: '?q=hello&view=theater', hash: '' });
129
- expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
130
-
131
- urlPlugin.pushToAddressBar();
132
- expect(window.location.hash).toEqual('#/page/12/mode/2up?q=hello&view=theater');
133
- });
134
- });
135
-
136
- describe('pullFromAddressBar and pushToAddressBar - history mode', () => {
137
- test('url without mode state value - use default', () => {
138
- urlPlugin.urlState = {};
139
- urlPlugin.urlHistoryBasePath = '/details/foo';
140
- urlPlugin.urlMode = 'history';
141
-
142
- urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '', hash: '' });
143
- expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
144
-
145
- urlPlugin.pushToAddressBar();
146
- expect(window.location.pathname).toEqual('/details/foo/page/12/mode/2up');
147
- });
148
-
149
- test('url with query param', () => {
150
- urlPlugin.urlState = {};
151
- urlPlugin.urlHistoryBasePath = '/details/foo';
152
- urlPlugin.urlMode = 'history';
153
-
154
- urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '?q=hello&view=theater', hash: '' });
155
- expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
156
-
157
- urlPlugin.pushToAddressBar();
158
- const locationUrl = `${window.location.pathname}${window.location.search}`;
159
- expect(locationUrl).toEqual('/details/foo/page/12/mode/2up?q=hello&view=theater');
160
- });
161
- });
162
-
163
13
  });
164
14
 
165
15
  describe('Plugin: URL controller', () => {
package/.nvmrc DELETED
@@ -1 +0,0 @@
1
- 14