@internetarchive/bookreader 5.0.0-4 → 5.0.0-40-a1
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/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +75 -4
- package/.github/workflows/npm-publish.yml +2 -16
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +83 -323
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -0
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1623 -0
- package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.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/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +14 -1
- package/BookReaderDemo/IADemoBr.js +120 -0
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -0
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
- package/BookReaderDemo/demo-fullscreen.html +1 -0
- package/BookReaderDemo/demo-iiif.html +1 -0
- package/BookReaderDemo/demo-internetarchive.html +74 -17
- package/BookReaderDemo/demo-multiple.html +1 -0
- package/BookReaderDemo/demo-preview-pages.html +1 -0
- package/BookReaderDemo/demo-simple.html +1 -0
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +1 -0
- package/BookReaderDemo/immersion-mode.html +1 -0
- package/BookReaderDemo/toggle_controls.html +1 -0
- package/BookReaderDemo/view_mode.html +1 -0
- package/BookReaderDemo/viewmode-cycle.html +1 -2
- package/CHANGELOG.md +166 -0
- package/README.md +14 -1
- package/babel.config.js +18 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +62 -47
- package/renovate.json +43 -0
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +9 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/src/BookNavigator/assets/icon_volumes.js +11 -0
- package/src/BookNavigator/book-navigator.js +556 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +23 -17
- package/src/BookNavigator/downloads/downloads.js +17 -25
- package/src/BookNavigator/search/a-search-result.js +3 -3
- package/src/BookNavigator/search/search-provider.js +57 -24
- package/src/BookNavigator/search/search-results.js +8 -20
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +51 -351
- package/src/BookReader/Mode1UpLit.js +441 -0
- package/src/BookReader/Mode2Up.js +104 -71
- package/src/BookReader/ModeSmoothZoom.js +179 -0
- package/src/BookReader/ModeThumb.js +16 -8
- package/src/BookReader/Navbar/Navbar.js +2 -31
- package/src/BookReader/PageContainer.js +57 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +7 -7
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +68 -13
- package/src/BookReader.js +375 -289
- package/src/assets/icons/close-circle-dark.svg +1 -0
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/BookReader.scss +0 -12
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +19 -24
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +35 -0
- package/src/css/_BRsearch.scss +11 -215
- package/src/css/_TextSelection.scss +14 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +16 -3
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.chapters.js +26 -33
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +26 -39
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +106 -107
- package/src/plugins/search/view.js +50 -163
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +12 -13
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +64 -68
- package/src/plugins/tts/plugin.tts.js +79 -108
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +7 -7
- package/tests/e2e/helpers/base.js +8 -3
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +14 -13
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/models/Navigation.js +12 -3
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +38 -33
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
- package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +88 -0
- package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +136 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +24 -25
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/{util → jest/util}/docCookies.test.js +1 -1
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
- package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
- package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
- package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
- package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
- package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
- package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
- package/webpack.config.js +10 -4
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -435
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -1,8 +1,8 @@
|
|
1
1
|
|
2
|
-
import BookReader from '
|
3
|
-
import '
|
4
|
-
import '
|
5
|
-
import '
|
2
|
+
import BookReader from '@/src/BookReader.js';
|
3
|
+
import '@/src/plugins/plugin.mobile_nav.js';
|
4
|
+
import '@/src/plugins/search/plugin.search.js';
|
5
|
+
import '@/src/plugins/search/view.js';
|
6
6
|
|
7
7
|
let br;
|
8
8
|
const namespace = 'BookReader:';
|
@@ -63,14 +63,14 @@ describe('View: Plugin: Search', () => {
|
|
63
63
|
|
64
64
|
expect(br.searchView.dom.searchNavigation).toBeUndefined();
|
65
65
|
|
66
|
-
br.searchView.handleSearchCallback(event, { results, options})
|
66
|
+
br.searchView.handleSearchCallback(event, { results, options});
|
67
67
|
expect(br.searchView.dom.searchNavigation).toBeDefined();
|
68
68
|
});
|
69
69
|
test('has controls', () => {
|
70
70
|
br.init();
|
71
71
|
const event = new CustomEvent(`${namespace}SearchCallback`);
|
72
72
|
const options = { goToFirstResult: false };
|
73
|
-
br.searchView.handleSearchCallback(event, { results, options})
|
73
|
+
br.searchView.handleSearchCallback(event, { results, options});
|
74
74
|
|
75
75
|
const searchResultsNav = document.querySelector('.BRsearch-navigation');
|
76
76
|
expect(searchResultsNav).toBeDefined();
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import sinon from 'sinon';
|
2
2
|
import { afterEventLoop } from '../../utils.js';
|
3
|
-
import AbstractTTSEngine from '
|
4
|
-
import PageChunkIterator from '
|
5
|
-
/** @typedef {import('
|
3
|
+
import AbstractTTSEngine from '@/src/plugins/tts/AbstractTTSEngine.js';
|
4
|
+
import PageChunkIterator from '@/src/plugins/tts/PageChunkIterator.js';
|
5
|
+
/** @typedef {import('@/src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
|
6
6
|
|
7
7
|
// Skipping because it's flaky. Fix in #672
|
8
8
|
describe.skip('AbstractTTSEngine', () => {
|
9
|
-
test('stops playing once done', () => {
|
9
|
+
test('stops playing once done', async () => {
|
10
10
|
class DummyEngine extends AbstractTTSEngine {
|
11
11
|
getVoices() { return []; }
|
12
12
|
}
|
@@ -15,8 +15,8 @@ describe.skip('AbstractTTSEngine', () => {
|
|
15
15
|
const stopStub = sinon.stub(d, 'stop');
|
16
16
|
expect(stopStub.callCount).toBe(0);
|
17
17
|
d.step();
|
18
|
-
|
19
|
-
|
18
|
+
await afterEventLoop();
|
19
|
+
expect(stopStub.callCount).toBe(1);
|
20
20
|
});
|
21
21
|
});
|
22
22
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import FestivalTTSEngine from '
|
1
|
+
import FestivalTTSEngine from '@/src/plugins/tts/FestivalTTSEngine.js';
|
2
2
|
import sinon from 'sinon';
|
3
3
|
import { afterEventLoop } from '../../utils.js';
|
4
4
|
import { DUMMY_TTS_ENGINE_OPTS } from './AbstractTTSEngine.test.js';
|
5
|
-
import PageChunk from '
|
6
|
-
import PageChunkIterator from '
|
7
|
-
/** @typedef {import('
|
5
|
+
import PageChunk from '@/src/plugins/tts/PageChunk.js';
|
6
|
+
import PageChunkIterator from '@/src/plugins/tts/PageChunkIterator.js';
|
7
|
+
/** @typedef {import('@/src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
|
8
8
|
|
9
9
|
describe('iOSCaptureUserIntentHack', () => {
|
10
10
|
test('synchronously calls createSound/play to capture user intent', () => {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import sinon from 'sinon';
|
2
|
-
import PageChunkIterator from "
|
3
|
-
import PageChunk from '
|
2
|
+
import PageChunkIterator from "@/src/plugins/tts/PageChunkIterator";
|
3
|
+
import PageChunk from '@/src/plugins/tts/PageChunk';
|
4
4
|
|
5
5
|
describe('Buffers pages', () => {
|
6
6
|
test('Does not error if no room for reverse buffer', async () => {
|
@@ -109,7 +109,7 @@ describe('Iterates pages', () => {
|
|
109
109
|
expect(iterator._cursor.chunk).toBe(0);
|
110
110
|
|
111
111
|
for (let i = 2; i >= 0; i--) {
|
112
|
-
await iterator.decrement()
|
112
|
+
await iterator.decrement();
|
113
113
|
expect(iterator._cursor.page).toBe(49);
|
114
114
|
expect(iterator._cursor.chunk).toBe(i);
|
115
115
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import sinon from 'sinon';
|
2
2
|
import { afterEventLoop, eventTargetMixin } from '../../utils.js';
|
3
|
-
import * as utils from '
|
3
|
+
import * as utils from '@/src/plugins/tts/utils.js';
|
4
4
|
|
5
5
|
describe('promisifyEvent', () => {
|
6
6
|
const { promisifyEvent } = utils;
|
@@ -10,7 +10,7 @@ describe('promisifyEvent', () => {
|
|
10
10
|
const resolveSpy = sinon.spy();
|
11
11
|
promisifyEvent(fakeTarget, 'pause').then(resolveSpy);
|
12
12
|
|
13
|
-
await afterEventLoop()
|
13
|
+
await afterEventLoop();
|
14
14
|
expect(resolveSpy.callCount).toBe(0);
|
15
15
|
fakeTarget.dispatchEvent('pause', {});
|
16
16
|
await afterEventLoop();
|
@@ -22,7 +22,7 @@ describe('promisifyEvent', () => {
|
|
22
22
|
const resolveSpy = sinon.spy();
|
23
23
|
promisifyEvent(fakeTarget, 'pause').then(resolveSpy);
|
24
24
|
|
25
|
-
await afterEventLoop()
|
25
|
+
await afterEventLoop();
|
26
26
|
expect(resolveSpy.callCount).toBe(0);
|
27
27
|
fakeTarget.dispatchEvent('pause', {});
|
28
28
|
fakeTarget.dispatchEvent('pause', {});
|
@@ -0,0 +1,190 @@
|
|
1
|
+
import { UrlPlugin } from '@/src/plugins/url/UrlPlugin';
|
2
|
+
|
3
|
+
afterEach(() => {
|
4
|
+
jest.clearAllMocks();
|
5
|
+
});
|
6
|
+
|
7
|
+
describe('UrlPlugin tests', () => {
|
8
|
+
const urlPlugin = new UrlPlugin();
|
9
|
+
|
10
|
+
describe('urlStateToUrlString tests', () => {
|
11
|
+
test('urlStateToUrlString with known states in schema', () => {
|
12
|
+
const urlState = { page: 'n7', mode: '1up', search: 'foo' };
|
13
|
+
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', view: 'theater', sort: 'title_asc' };
|
14
|
+
|
15
|
+
const expectedUrlFromState = 'page/n7/mode/1up?q=foo';
|
16
|
+
const expectedUrlFromStateWithQueries = 'page/n7/mode/1up?q=hello&view=theater&sort=title_asc';
|
17
|
+
|
18
|
+
expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
|
19
|
+
expect(urlPlugin.urlStateToUrlString(urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
20
|
+
});
|
21
|
+
|
22
|
+
test('urlStateToUrlString with unknown states in schema', () => {
|
23
|
+
const urlState = { page: 'n7', mode: '1up' };
|
24
|
+
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', viewer: 'theater', sortBy: 'title_asc' };
|
25
|
+
|
26
|
+
const expectedUrlFromState = 'page/n7/mode/1up';
|
27
|
+
const expectedUrlFromStateWithQueries = 'page/n7/mode/1up?q=hello&viewer=theater&sortBy=title_asc';
|
28
|
+
|
29
|
+
expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
|
30
|
+
expect(urlPlugin.urlStateToUrlString(urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
31
|
+
});
|
32
|
+
|
33
|
+
test('urlStateToUrlString with boolean value', () => {
|
34
|
+
const urlState = { page: 'n7', mode: '1up', search: 'foo', view: 'theater', wrapper: 'false' };
|
35
|
+
const expectedUrlFromState = 'page/n7/mode/1up?q=foo&view=theater&wrapper=false';
|
36
|
+
|
37
|
+
expect(urlPlugin.urlStateToUrlString(urlState)).toBe(expectedUrlFromState);
|
38
|
+
});
|
39
|
+
});
|
40
|
+
|
41
|
+
describe('urlStringToUrlState tests', () => {
|
42
|
+
test('urlStringToUrlState without query string', () => {
|
43
|
+
const url = '/page/n7/mode/2up';
|
44
|
+
const url1 = '/page/n7/mode/1up';
|
45
|
+
|
46
|
+
expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up'});
|
47
|
+
expect(urlPlugin.urlStringToUrlState(url1)).toEqual({page: 'n7', mode: '1up'});
|
48
|
+
});
|
49
|
+
|
50
|
+
test('urlStringToUrlState with deprecated_for', () => {
|
51
|
+
const url = '/page/n7/mode/2up/search/hello';
|
52
|
+
|
53
|
+
expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
54
|
+
});
|
55
|
+
|
56
|
+
test('urlStringToUrlState with query string', () => {
|
57
|
+
const url = '/page/n7/mode/2up/search/hello?view=theather&foo=bar&sort=title_asc';
|
58
|
+
const url1 = '/mode/2up?ref=ol&ui=embed&wrapper=false&view=theater';
|
59
|
+
|
60
|
+
expect(urlPlugin.urlStringToUrlState(url)).toEqual(
|
61
|
+
{page: 'n7', mode: '2up', q: 'hello', view: 'theather', foo: 'bar', sort: 'title_asc'}
|
62
|
+
);
|
63
|
+
expect(urlPlugin.urlStringToUrlState(url1)).toEqual(
|
64
|
+
{mode: '2up', ref: 'ol', ui: 'embed', wrapper: 'false', view: 'theater'}
|
65
|
+
);
|
66
|
+
});
|
67
|
+
|
68
|
+
test('urlStringToUrlState compare search and ?q', () => {
|
69
|
+
const url = '/page/n7/mode/2up/search/hello';
|
70
|
+
urlPlugin.urlState = { q: 'hello' };
|
71
|
+
|
72
|
+
expect(urlPlugin.urlStringToUrlState(url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
73
|
+
});
|
74
|
+
});
|
75
|
+
|
76
|
+
describe('url plugin helper functions', () => {
|
77
|
+
test('setUrlParam', () => {
|
78
|
+
urlPlugin.urlState = {};
|
79
|
+
urlPlugin.setUrlParam('page', '20');
|
80
|
+
urlPlugin.setUrlParam('mode', '2up');
|
81
|
+
|
82
|
+
expect(urlPlugin.urlState).toEqual({page: '20', mode: '2up'});
|
83
|
+
});
|
84
|
+
|
85
|
+
test('removeUrlParam', () => {
|
86
|
+
urlPlugin.setUrlParam('page', '20');
|
87
|
+
urlPlugin.setUrlParam('mode', '2up');
|
88
|
+
urlPlugin.removeUrlParam('mode');
|
89
|
+
|
90
|
+
expect(urlPlugin.urlState).toEqual({page: '20'});
|
91
|
+
});
|
92
|
+
|
93
|
+
test('getUrlParam', () => {
|
94
|
+
urlPlugin.setUrlParam('page', '20');
|
95
|
+
urlPlugin.setUrlParam('mode', '2up');
|
96
|
+
expect(urlPlugin.getUrlParam('page')).toEqual('20');
|
97
|
+
expect(urlPlugin.getUrlParam('mode')).toEqual('2up');
|
98
|
+
});
|
99
|
+
});
|
100
|
+
|
101
|
+
describe('pullFromAddressBar and pushToAddressBar - hash mode', () => {
|
102
|
+
test('url first load - empty state', () => {
|
103
|
+
urlPlugin.urlState = {};
|
104
|
+
urlPlugin.urlMode = 'hash';
|
105
|
+
|
106
|
+
urlPlugin.pullFromAddressBar({ pathname: '', search: '', hash: '#' });
|
107
|
+
expect(urlPlugin.urlState).toEqual({});
|
108
|
+
|
109
|
+
urlPlugin.pushToAddressBar();
|
110
|
+
expect(window.location.hash).toEqual('');
|
111
|
+
});
|
112
|
+
|
113
|
+
test('url without mode state value - use default', () => {
|
114
|
+
urlPlugin.urlState = {};
|
115
|
+
urlPlugin.urlMode = 'hash';
|
116
|
+
|
117
|
+
urlPlugin.pullFromAddressBar({ pathname: '', search: '', hash: '#page/12' });
|
118
|
+
expect(urlPlugin.urlState).toEqual({page: '12'});
|
119
|
+
|
120
|
+
urlPlugin.pushToAddressBar();
|
121
|
+
expect(window.location.hash).toEqual('#page/12');
|
122
|
+
});
|
123
|
+
|
124
|
+
test('url with query param', () => {
|
125
|
+
urlPlugin.urlState = {};
|
126
|
+
urlPlugin.urlMode = 'hash';
|
127
|
+
|
128
|
+
urlPlugin.pullFromAddressBar({ pathname: '', search: '', hash: '#page/12?q=hello&view=theater' });
|
129
|
+
expect(urlPlugin.urlState).toEqual({page: '12', q: 'hello', view: 'theater'});
|
130
|
+
|
131
|
+
urlPlugin.pushToAddressBar();
|
132
|
+
expect(window.location.hash).toEqual('#page/12?q=hello&view=theater');
|
133
|
+
});
|
134
|
+
});
|
135
|
+
|
136
|
+
describe('pullFromAddressBar and pushToAddressBar - history mode', () => {
|
137
|
+
test('url first load - empty state', () => {
|
138
|
+
urlPlugin.urlState = {};
|
139
|
+
urlPlugin.urlHistoryBasePath = '/details/foo';
|
140
|
+
urlPlugin.urlMode = 'history';
|
141
|
+
|
142
|
+
urlPlugin.pullFromAddressBar({ pathname: '', search: '', hash: '' });
|
143
|
+
expect(urlPlugin.urlState).toEqual({});
|
144
|
+
|
145
|
+
urlPlugin.pushToAddressBar();
|
146
|
+
expect(window.location.pathname).toEqual('/details/foo');
|
147
|
+
});
|
148
|
+
|
149
|
+
test('url without mode state value', () => {
|
150
|
+
urlPlugin.urlState = {};
|
151
|
+
urlPlugin.urlHistoryBasePath = '/details/foo/';
|
152
|
+
urlPlugin.urlMode = 'history';
|
153
|
+
|
154
|
+
urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '', hash: '' });
|
155
|
+
expect(urlPlugin.urlState).toEqual({page: '12'});
|
156
|
+
|
157
|
+
urlPlugin.pushToAddressBar();
|
158
|
+
expect(window.location.pathname).toEqual('/details/foo/page/12');
|
159
|
+
});
|
160
|
+
|
161
|
+
test('url with query param', () => {
|
162
|
+
urlPlugin.urlState = {};
|
163
|
+
urlPlugin.urlHistoryBasePath = '/details/foo/';
|
164
|
+
urlPlugin.urlMode = 'history';
|
165
|
+
|
166
|
+
urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '?q=hello&view=theater', hash: '' });
|
167
|
+
expect(urlPlugin.urlState).toEqual({page: '12', q: 'hello', view: 'theater'});
|
168
|
+
|
169
|
+
urlPlugin.pushToAddressBar();
|
170
|
+
const locationUrl = `${window.location.pathname}${window.location.search}`;
|
171
|
+
expect(locationUrl).toEqual('/details/foo/page/12?q=hello&view=theater');
|
172
|
+
});
|
173
|
+
|
174
|
+
test('strips leading slash of incoming path name for no double slash', () => {
|
175
|
+
const urlPlugin = new UrlPlugin();
|
176
|
+
urlPlugin.urlMode = 'history';
|
177
|
+
|
178
|
+
urlPlugin.urlHistoryBasePath = '/details/SubBookTest/book1/GPORFP/';
|
179
|
+
urlPlugin.urlState = {
|
180
|
+
"mode": "1up",
|
181
|
+
};
|
182
|
+
|
183
|
+
urlPlugin.setUrlParam('sort', 'title_asc');
|
184
|
+
urlPlugin.setUrlParam('mode', 'thumb');
|
185
|
+
|
186
|
+
expect(window.location.href).toEqual('http://localhost/details/SubBookTest/book1/GPORFP/mode/thumb?sort=title_asc');
|
187
|
+
});
|
188
|
+
});
|
189
|
+
|
190
|
+
});
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
import
|
3
|
-
import '
|
1
|
+
import BookReader from '@/src/BookReader.js';
|
2
|
+
import '@/src/plugins/url/plugin.url.js';
|
3
|
+
import sinon from 'sinon';
|
4
4
|
|
5
5
|
let br;
|
6
6
|
beforeAll(() => {
|
@@ -10,6 +10,7 @@ beforeAll(() => {
|
|
10
10
|
|
11
11
|
afterEach(() => {
|
12
12
|
jest.clearAllMocks();
|
13
|
+
sinon.restore();
|
13
14
|
});
|
14
15
|
|
15
16
|
describe('Plugin: URL controller', () => {
|
@@ -26,10 +27,10 @@ describe('Plugin: URL controller', () => {
|
|
26
27
|
expect(defaultOptions).toHaveProperty('updateWindowTitle');
|
27
28
|
expect(defaultOptions).toHaveProperty('defaults');
|
28
29
|
expect(defaultOptions).toHaveProperty('bookId');
|
29
|
-
})
|
30
|
+
});
|
30
31
|
|
31
32
|
test('has a whitelist of params that it tracks', () => {
|
32
|
-
['page', 'search', 'mode', 'region', 'highlight']
|
33
|
+
['page', 'search', 'mode', 'region', 'highlight'];
|
33
34
|
const { defaultOptions: { urlTrackedParams } } = BookReader;
|
34
35
|
expect(Array.isArray(urlTrackedParams)).toEqual(true);
|
35
36
|
expect(urlTrackedParams.find(param => param === 'page')).toBeTruthy();
|
@@ -37,7 +38,8 @@ describe('Plugin: URL controller', () => {
|
|
37
38
|
expect(urlTrackedParams.find(param => param === 'mode')).toBeTruthy();
|
38
39
|
expect(urlTrackedParams.find(param => param === 'region')).toBeTruthy();
|
39
40
|
expect(urlTrackedParams.find(param => param === 'highlight')).toBeTruthy();
|
40
|
-
|
41
|
+
expect(urlTrackedParams.find(param => param === 'view')).toBeTruthy();
|
42
|
+
});
|
41
43
|
|
42
44
|
test('initializes polling for url changes if using hash', () => {
|
43
45
|
BookReader.prototype.urlStartLocationPolling = jest.fn();
|
@@ -60,7 +62,7 @@ describe('Plugin: URL controller', () => {
|
|
60
62
|
br.urlUpdateFragment();
|
61
63
|
|
62
64
|
expect(window.history.replaceState).toHaveBeenCalled();
|
63
|
-
})
|
65
|
+
});
|
64
66
|
|
65
67
|
test('updates URL when mode changes', () => {
|
66
68
|
window.history.replaceState = jest.fn();
|
@@ -76,7 +78,7 @@ describe('Plugin: URL controller', () => {
|
|
76
78
|
br.urlUpdateFragment();
|
77
79
|
|
78
80
|
expect(window.history.replaceState).toHaveBeenCalled();
|
79
|
-
})
|
81
|
+
});
|
80
82
|
|
81
83
|
test('updates URL when search changes', () => {
|
82
84
|
window.history.replaceState = jest.fn();
|
@@ -93,7 +95,24 @@ describe('Plugin: URL controller', () => {
|
|
93
95
|
br.urlUpdateFragment();
|
94
96
|
|
95
97
|
expect(window.history.replaceState).toHaveBeenCalled();
|
96
|
-
})
|
98
|
+
});
|
99
|
+
|
100
|
+
test('updates URL when view changes', () => {
|
101
|
+
window.history.replaceState = jest.fn();
|
102
|
+
BookReader.prototype.currentIndex = jest.fn(() => 1);
|
103
|
+
BookReader.prototype.urlReadFragment = jest.fn(() => '');
|
104
|
+
BookReader.prototype.paramsFromCurrent = jest.fn(() => ({
|
105
|
+
index: 1,
|
106
|
+
mode: 2,
|
107
|
+
view: 'theater'
|
108
|
+
}));
|
109
|
+
BookReader.prototype.search = jest.fn();
|
110
|
+
br.options.urlMode = 'history';
|
111
|
+
br.init();
|
112
|
+
br.urlUpdateFragment();
|
113
|
+
|
114
|
+
expect(window.history.replaceState).toHaveBeenCalled();
|
115
|
+
});
|
97
116
|
|
98
117
|
test('does not update URL when search in query string', () => {
|
99
118
|
window.history.replaceState = jest.fn();
|
@@ -112,18 +131,18 @@ describe('Plugin: URL controller', () => {
|
|
112
131
|
br.urlUpdateFragment();
|
113
132
|
|
114
133
|
expect(window.history.replaceState).toHaveBeenCalledTimes(0);
|
115
|
-
})
|
134
|
+
});
|
116
135
|
|
117
136
|
test('only q= param is selected from url query params', () => {
|
118
|
-
const INTIAL_URL = "http://127.0.0.1:8080/BookReaderDemo/demo-internetarchive.html?ocaid=adventuresofoli00dick&q=foo"
|
137
|
+
const INTIAL_URL = "http://127.0.0.1:8080/BookReaderDemo/demo-internetarchive.html?ocaid=adventuresofoli00dick&q=foo";
|
119
138
|
const result = br.urlParamsFiltersOnlySearch(INTIAL_URL);
|
120
139
|
expect(result).toBe("?q=foo");
|
121
|
-
})
|
140
|
+
});
|
122
141
|
|
123
142
|
test('only q= param is selected from url query params with special character', () => {
|
124
|
-
const INTIAL_URL = "http://127.0.0.1:8080/BookReaderDemo/demo-internetarchive.html?ocaid=adventuresofoli00dick&q=foo%24%24"
|
143
|
+
const INTIAL_URL = "http://127.0.0.1:8080/BookReaderDemo/demo-internetarchive.html?ocaid=adventuresofoli00dick&q=foo%24%24";
|
125
144
|
const result = br.urlParamsFiltersOnlySearch(INTIAL_URL);
|
126
145
|
expect(result).toBe("?q=foo%24%24");
|
127
|
-
})
|
146
|
+
});
|
128
147
|
});
|
129
148
|
|
@@ -31,6 +31,44 @@ export function eventTargetMixin() {
|
|
31
31
|
};
|
32
32
|
}
|
33
33
|
|
34
|
+
/** @implements {EventTarget} */
|
35
|
+
export class EventTargetSpy {
|
36
|
+
/** @type {Record<string, Function[]} */
|
37
|
+
_listeners = {}
|
38
|
+
get _totalListenerCount() {
|
39
|
+
return Object.values(this._listeners)
|
40
|
+
.map(a => a.length)
|
41
|
+
.reduce((a, b) => a + b, 0);
|
42
|
+
}
|
43
|
+
|
44
|
+
addEventListener(evName, listener) {
|
45
|
+
const listeners = this._listeners[evName] || [];
|
46
|
+
listeners.push(listener);
|
47
|
+
this._listeners[evName] = listeners;
|
48
|
+
}
|
49
|
+
|
50
|
+
dispatchEvent(evName, ev) {
|
51
|
+
const listeners = this._listeners[evName] || [];
|
52
|
+
listeners.forEach(fn => fn(ev));
|
53
|
+
}
|
54
|
+
|
55
|
+
removeEventListener(evName, listener) {
|
56
|
+
const listeners = this._listeners[evName] || [];
|
57
|
+
this._listeners[evName] = listeners.filter(fn => fn != listener);
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* @param {EventTarget} realEventTarget
|
62
|
+
*/
|
63
|
+
static wrap(realEventTarget) {
|
64
|
+
const spy = new EventTargetSpy();
|
65
|
+
realEventTarget.addEventListener = spy.addEventListener.bind(spy);
|
66
|
+
realEventTarget.removeEventListener = spy.removeEventListener.bind(spy);
|
67
|
+
realEventTarget.dispatchEvent = spy.dispatchEvent.bind(spy);
|
68
|
+
return spy;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
34
72
|
/**
|
35
73
|
* Lazy deep copy function; only supports objects (no classes)
|
36
74
|
* @template T
|