@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.
Files changed (228) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +75 -4
  3. package/.github/workflows/npm-publish.yml +2 -16
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +83 -323
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -0
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1623 -0
  10. package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/close-circle-dark.svg +1 -0
  13. package/BookReader/icons/magnify-minus.svg +1 -1
  14. package/BookReader/icons/magnify-plus.svg +1 -1
  15. package/BookReader/icons/voice.svg +1 -0
  16. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  17. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  18. package/BookReader/plugins/plugin.autoplay.js +1 -1
  19. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  20. package/BookReader/plugins/plugin.chapters.js +1 -1
  21. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  22. package/BookReader/plugins/plugin.iframe.js +1 -1
  23. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  24. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  25. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  26. package/BookReader/plugins/plugin.resume.js +1 -1
  27. package/BookReader/plugins/plugin.resume.js.map +1 -1
  28. package/BookReader/plugins/plugin.search.js +1 -1
  29. package/BookReader/plugins/plugin.search.js.map +1 -1
  30. package/BookReader/plugins/plugin.text_selection.js +1 -1
  31. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  32. package/BookReader/plugins/plugin.tts.js +1 -1
  33. package/BookReader/plugins/plugin.tts.js.map +1 -1
  34. package/BookReader/plugins/plugin.url.js +1 -1
  35. package/BookReader/plugins/plugin.url.js.map +1 -1
  36. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  37. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  38. package/BookReader/webcomponents-bundle.js +3 -0
  39. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  40. package/BookReader/webcomponents-bundle.js.map +1 -0
  41. package/BookReaderDemo/BookReaderDemo.css +14 -1
  42. package/BookReaderDemo/IADemoBr.js +120 -0
  43. package/BookReaderDemo/demo-advanced.html +1 -1
  44. package/BookReaderDemo/demo-autoplay.html +1 -0
  45. package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
  46. package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
  47. package/BookReaderDemo/demo-fullscreen.html +1 -0
  48. package/BookReaderDemo/demo-iiif.html +1 -0
  49. package/BookReaderDemo/demo-internetarchive.html +74 -17
  50. package/BookReaderDemo/demo-multiple.html +1 -0
  51. package/BookReaderDemo/demo-preview-pages.html +1 -0
  52. package/BookReaderDemo/demo-simple.html +1 -0
  53. package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
  54. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  55. package/BookReaderDemo/immersion-1up.html +1 -0
  56. package/BookReaderDemo/immersion-mode.html +1 -0
  57. package/BookReaderDemo/toggle_controls.html +1 -0
  58. package/BookReaderDemo/view_mode.html +1 -0
  59. package/BookReaderDemo/viewmode-cycle.html +1 -2
  60. package/CHANGELOG.md +166 -0
  61. package/README.md +14 -1
  62. package/babel.config.js +18 -0
  63. package/codecov.yml +6 -0
  64. package/index.html +3 -0
  65. package/jsconfig.json +19 -0
  66. package/package.json +62 -47
  67. package/renovate.json +43 -0
  68. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  69. package/src/BookNavigator/assets/button-base.js +9 -2
  70. package/src/BookNavigator/assets/ia-logo.js +17 -0
  71. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  72. package/src/BookNavigator/assets/icon_close.js +1 -1
  73. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  74. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  75. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  76. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  77. package/src/BookNavigator/book-navigator.js +556 -0
  78. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  79. package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
  80. package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
  81. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  82. package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
  83. package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
  84. package/src/BookNavigator/delete-modal-actions.js +1 -1
  85. package/src/BookNavigator/downloads/downloads-provider.js +23 -17
  86. package/src/BookNavigator/downloads/downloads.js +17 -25
  87. package/src/BookNavigator/search/a-search-result.js +3 -3
  88. package/src/BookNavigator/search/search-provider.js +57 -24
  89. package/src/BookNavigator/search/search-results.js +8 -20
  90. package/src/BookNavigator/sharing.js +27 -0
  91. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
  92. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
  93. package/src/BookNavigator/volumes/volumes-provider.js +114 -0
  94. package/src/BookNavigator/volumes/volumes.js +188 -0
  95. package/src/BookReader/DebugConsole.js +3 -3
  96. package/src/BookReader/DragScrollable.js +233 -0
  97. package/src/BookReader/Mode1Up.js +51 -351
  98. package/src/BookReader/Mode1UpLit.js +441 -0
  99. package/src/BookReader/Mode2Up.js +104 -71
  100. package/src/BookReader/ModeSmoothZoom.js +179 -0
  101. package/src/BookReader/ModeThumb.js +16 -8
  102. package/src/BookReader/Navbar/Navbar.js +2 -31
  103. package/src/BookReader/PageContainer.js +57 -6
  104. package/src/BookReader/ReduceSet.js +1 -1
  105. package/src/BookReader/Toolbar/Toolbar.js +7 -7
  106. package/src/BookReader/options.js +10 -0
  107. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  108. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  109. package/src/BookReader/utils.js +68 -13
  110. package/src/BookReader.js +375 -289
  111. package/src/assets/icons/close-circle-dark.svg +1 -0
  112. package/src/assets/icons/magnify-minus.svg +3 -7
  113. package/src/assets/icons/magnify-plus.svg +3 -7
  114. package/src/assets/icons/voice.svg +1 -0
  115. package/src/css/BookReader.scss +0 -12
  116. package/src/css/_BRComponent.scss +1 -1
  117. package/src/css/_BRmain.scss +19 -24
  118. package/src/css/_BRnav.scss +4 -26
  119. package/src/css/_BRpages.scss +35 -0
  120. package/src/css/_BRsearch.scss +11 -215
  121. package/src/css/_TextSelection.scss +14 -17
  122. package/src/css/_colorbox.scss +2 -2
  123. package/src/css/_controls.scss +16 -3
  124. package/src/css/_icons.scss +6 -0
  125. package/src/ia-bookreader/ia-bookreader.js +224 -0
  126. package/src/plugins/plugin.chapters.js +26 -33
  127. package/src/plugins/plugin.mobile_nav.js +11 -10
  128. package/src/plugins/plugin.resume.js +3 -3
  129. package/src/plugins/plugin.text_selection.js +26 -39
  130. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  131. package/src/plugins/search/plugin.search.js +106 -107
  132. package/src/plugins/search/view.js +50 -163
  133. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  134. package/src/plugins/tts/FestivalTTSEngine.js +12 -13
  135. package/src/plugins/tts/PageChunk.js +15 -21
  136. package/src/plugins/tts/PageChunkIterator.js +8 -12
  137. package/src/plugins/tts/WebTTSEngine.js +64 -68
  138. package/src/plugins/tts/plugin.tts.js +79 -108
  139. package/src/plugins/url/UrlPlugin.js +184 -0
  140. package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
  141. package/tests/e2e/README.md +37 -0
  142. package/tests/e2e/autoplay.test.js +2 -2
  143. package/tests/e2e/base.test.js +7 -7
  144. package/tests/e2e/helpers/base.js +8 -3
  145. package/tests/e2e/helpers/debug.js +1 -1
  146. package/tests/e2e/helpers/desktopSearch.js +14 -13
  147. package/tests/e2e/helpers/mobileSearch.js +3 -3
  148. package/tests/e2e/helpers/params.js +17 -0
  149. package/tests/e2e/models/Navigation.js +12 -3
  150. package/tests/e2e/rightToLeft.test.js +4 -5
  151. package/tests/e2e/viewmode.test.js +38 -33
  152. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
  153. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  154. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  155. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  156. package/tests/jest/BookReader/Mode1UpLit.test.js +88 -0
  157. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
  158. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  159. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  160. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  161. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -6
  162. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  163. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  164. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  165. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  166. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  167. package/tests/jest/BookReader/utils.test.js +136 -0
  168. package/tests/jest/BookReader.keyboard.test.js +190 -0
  169. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  170. package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
  171. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  172. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
  173. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
  174. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  175. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  176. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  177. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  178. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  179. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +24 -25
  180. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
  181. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
  182. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  183. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  184. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  185. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  186. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
  187. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  188. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  189. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  190. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  191. package/tests/{util → jest/util}/strings.test.js +1 -1
  192. package/tests/{utils.js → jest/utils.js} +38 -0
  193. package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
  194. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  195. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
  196. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
  197. package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
  198. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
  199. package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
  200. package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
  201. package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
  202. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
  203. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
  204. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
  205. package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
  206. package/webpack.config.js +10 -4
  207. package/.babelrc +0 -12
  208. package/.dependabot/config.yml +0 -6
  209. package/.testcaferc.json +0 -5
  210. package/BookReader/bookreader-component-bundle.js +0 -1450
  211. package/BookReader/bookreader-component-bundle.js.map +0 -1
  212. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  213. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  214. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  215. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  216. package/src/BookNavigator/BookModel.js +0 -14
  217. package/src/BookNavigator/BookNavigator.js +0 -435
  218. package/src/BookNavigator/assets/book-loader.js +0 -27
  219. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  220. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  221. package/src/ItemNavigator/ItemNavigator.js +0 -372
  222. package/src/ItemNavigator/providers/sharing.js +0 -29
  223. package/src/dragscrollable-br.js +0 -261
  224. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  225. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  226. package/tests/BookReader/Mode1Up.test.js +0 -164
  227. package/tests/BookReader/utils.test.js +0 -109
  228. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,67 @@
1
+ import { expect, fixtureCleanup, fixtureSync } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ import DownloadsProvider from '../../../../src/BookNavigator/downloads/downloads-provider';
4
+
5
+ const downloadableTypes = [
6
+ ["PDF", "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.pdf"],
7
+ ["ePub", "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.epub"],
8
+ ["Plain Text", "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala_djvu.txt"],
9
+ ["DAISY", "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala_daisy.zip"],
10
+ ["Kindle", "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.mobi"]
11
+ ];
12
+
13
+ const downloads = [
14
+ {
15
+ type: "PDF",
16
+ url: "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.pdf",
17
+ note: "PDF files contain high quality images of pages."
18
+ },
19
+ {
20
+ type: "ePub",
21
+ url: "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.epub",
22
+ note: "ePub files are smaller in size, but may contain errors."
23
+ }
24
+ ];
25
+
26
+ afterEach(() => {
27
+ sinon.restore();
28
+ fixtureCleanup();
29
+ });
30
+
31
+ describe('Downloads Provider', () => {
32
+ it('constructor - initial setup', () => {
33
+ const isBookProtected = false;
34
+ const provider = new DownloadsProvider(isBookProtected);
35
+
36
+ expect(provider.id).to.equal('downloads');
37
+ expect(provider.icon).to.exist;
38
+ expect(fixtureSync(provider.icon).tagName).to.equal('IA-ICON-DL');
39
+ expect(provider.label).to.equal('Downloadable files');
40
+ expect(provider.menuDetails).to.exist;
41
+ expect(provider.component).to.exist;
42
+
43
+ provider.update(downloadableTypes);
44
+
45
+ expect(provider.isBookProtected).to.equal(false);
46
+
47
+ expect(provider.downloads[0].type).to.equals("PDF");
48
+ expect(provider.downloads[1].type).to.equals("ePub");
49
+
50
+ expect(provider.menuDetails).to.equal(`(${downloads.length} formats)`);
51
+ });
52
+
53
+ it('render view if book is protected', () => {
54
+ const provider = new DownloadsProvider({
55
+ bookreader: { options: { isProtected: true } }
56
+ });
57
+
58
+ expect(provider.isBookProtected).to.equal(true);
59
+
60
+ provider.update(downloadableTypes);
61
+
62
+ expect(provider.downloads[0].type).to.equals("Encrypted Adobe PDF");
63
+ expect(provider.downloads[1].type).to.equals("Encrypted Adobe ePub");
64
+
65
+ expect(provider.downloads.length).to.equals(downloads.length);
66
+ });
67
+ });
@@ -0,0 +1,54 @@
1
+ import {
2
+ html,
3
+ fixture,
4
+ expect,
5
+ fixtureCleanup,
6
+ } from '@open-wc/testing';
7
+ import sinon from 'sinon';
8
+ import '../../../../src/BookNavigator/downloads/downloads';
9
+
10
+
11
+ const downloads = [
12
+ {
13
+ type: "PDF",
14
+ url: "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.pdf",
15
+ note: "PDF files contain high quality images of pages."
16
+ },
17
+ {
18
+ type: "ePub",
19
+ url: "//archive.org/download/theworksofplato01platiala/theworksofplato01platiala.epub",
20
+ note: "ePub files are smaller in size, but may contain errors."
21
+ }
22
+ ];
23
+
24
+
25
+ const container = (downloads) => (
26
+ html`
27
+ <ia-book-downloads .downloads=${downloads}></ia-book-downloads>
28
+ `
29
+ );
30
+
31
+ beforeEach(() => {
32
+ const body = document.querySelector('body');
33
+ const brHook = document.createElement('div');
34
+ brHook.setAttribute('id', 'BookReader');
35
+ body.appendChild(brHook);
36
+ });
37
+
38
+ afterEach(() => {
39
+ sinon.restore();
40
+ fixtureCleanup();
41
+ });
42
+
43
+ describe('<ia-book-downloads>', () => {
44
+ it('sets default properties', async () => {
45
+ const el = await fixture(container(downloads));
46
+ await el.updateComplete;
47
+
48
+ expect(el.downloads.length).to.equal(2);
49
+ expect(el.shadowRoot.querySelector("ul").childElementCount).to.equal(2);
50
+ expect(el.isBookProtected).to.equal(false);
51
+
52
+ expect(el.shadowRoot.querySelector("ul li a").textContent).to.include("Get PDF");
53
+ });
54
+ });
@@ -0,0 +1,123 @@
1
+ import { expect, fixtureCleanup, fixtureSync } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ import searchProvider from '../../../../src/BookNavigator/search/search-provider';
4
+
5
+ afterEach(() => {
6
+ sinon.restore();
7
+ fixtureCleanup();
8
+ });
9
+
10
+ describe('Search Provider', () => {
11
+ describe('constructor', () => {
12
+ const provider = new searchProvider({
13
+ onProviderChange: sinon.fake(),
14
+ bookreader: {}
15
+ });
16
+
17
+ expect(provider.bookreader).to.exist;
18
+ expect(provider.onProviderChange).to.exist;
19
+ expect(provider.id).to.equal('search');
20
+ expect(provider.icon).to.exist;
21
+ expect(fixtureSync(provider.icon).tagName).to.equal('IA-ICON-SEARCH');
22
+ expect(provider.label).to.equal('Search inside');
23
+ expect(provider.menuDetails).to.exist;
24
+ expect(provider.component).to.exist;
25
+ });
26
+ describe('BR calls', () => {
27
+ it('`advanceToPage', () => {
28
+ const provider = new searchProvider({
29
+ onProviderChange: sinon.fake(),
30
+ bookreader: {
31
+ leafNumToIndex: sinon.fake(),
32
+ _searchPluginGoToResult: sinon.fake()
33
+ }
34
+ });
35
+
36
+ provider.advanceToPage(1);
37
+ expect(provider?.bookreader.leafNumToIndex.callCount).to.equal(1);
38
+ expect(provider?.bookreader._searchPluginGoToResult.callCount).to.equal(1);
39
+ });
40
+ });
41
+ describe('Search request life cycles', () => {
42
+ it('Event: catches `BookReader:SearchStarted`', async() => {
43
+ const provider = new searchProvider({
44
+ onProviderChange: sinon.fake(),
45
+ bookreader: {}
46
+ });
47
+ sinon.spy(provider, 'updateMenu');
48
+ window.dispatchEvent(new CustomEvent('BookReader:SearchStarted', { detail: { props: { term: 'foo' }}}));
49
+ expect(provider.updateMenu.callCount).to.equal(1);
50
+ });
51
+ it('Event: catches `BookReader:SearchCallback`', async() => {
52
+ const provider = new searchProvider({
53
+ onProviderChange: sinon.fake(),
54
+ bookreader: {}
55
+ });
56
+ sinon.spy(provider, 'updateMenu');
57
+ const brStub = {};
58
+ window.dispatchEvent(new CustomEvent('BookReader:SearchCallback', { detail: { props: { instance: brStub, results: { matches: []} }}}));
59
+ expect(provider.updateMenu.callCount).to.equal(1);
60
+ expect(provider.bookreader).to.equal(brStub);
61
+ });
62
+ it('Event: catches `BookReader:SearchCallbackEmpty`', async() => {
63
+ const provider = new searchProvider({
64
+ onProviderChange: sinon.fake(),
65
+ bookreader: {}
66
+ });
67
+ sinon.spy(provider, 'onSearchRequestError');
68
+ sinon.spy(provider, 'updateMenu');
69
+ const brStub = {};
70
+ window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackEmpty', { detail: { props: { instance: brStub }}}));
71
+ expect(provider.onSearchRequestError.getCall(0).args[1]).to.equal('noResults');
72
+ expect(provider.updateMenu.callCount).to.equal(1);
73
+ expect(provider.bookreader).to.equal(brStub);
74
+ });
75
+ it('Event: catches `BookReader:SearchCallbackNotIndexed`', async() => {
76
+ const provider = new searchProvider({
77
+ onProviderChange: sinon.fake(),
78
+ bookreader: {}
79
+ });
80
+ const brStub = {};
81
+ sinon.spy(provider, 'onSearchRequestError');
82
+ sinon.spy(provider, 'updateMenu');
83
+ window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackNotIndexed', { detail: { props: { instance: brStub }}}));
84
+ expect(provider.onSearchRequestError.getCall(0).args[1]).to.equal('notIndexed');
85
+ expect(provider.updateMenu.callCount).to.equal(1);
86
+ expect(provider.bookreader).to.equal(brStub);
87
+ });
88
+ it('Event: catches `BookReader:SearchCallbackError`', async() => {
89
+ const provider = new searchProvider({
90
+ onProviderChange: sinon.fake(),
91
+ bookreader: {}
92
+ });
93
+ sinon.spy(provider, 'onSearchRequestError');
94
+ sinon.spy(provider, 'updateMenu');
95
+ const brStub = {};
96
+ window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackError', { detail: { props: { instance: brStub }}}));
97
+ expect(provider.onSearchRequestError.getCall(0).args[1]).to.equal(undefined);
98
+ expect(provider.updateMenu.callCount).to.equal(1);
99
+ expect(provider.bookreader).to.equal(brStub);
100
+ });
101
+ it('Event: catches `component@resultSelected` - user clicks result in side panel - & turns page', async() => {
102
+ const provider = new searchProvider({
103
+ onProviderChange: sinon.fake(),
104
+ bookreader: {
105
+ leafNumToIndex: sinon.fake(),
106
+ _searchPluginGoToResult: sinon.fake()
107
+ }
108
+ });
109
+ sinon.spy(provider, 'advanceToPage');
110
+
111
+ const searchResultStub = {
112
+ match: { par: [{ text: 'foo', page: 3 }] },
113
+ };
114
+ fixtureSync(provider.component).dispatchEvent(
115
+ new CustomEvent('resultSelected',
116
+ { detail: searchResultStub })
117
+ );
118
+
119
+ expect(provider.advanceToPage.callCount).to.equal(1);
120
+ expect(provider.bookreader._searchPluginGoToResult.callCount).to.equal(1);
121
+ });
122
+ });
123
+ });
@@ -5,15 +5,12 @@ import {
5
5
  oneEvent,
6
6
  } from '@open-wc/testing';
7
7
  import sinon from 'sinon';
8
- import { IABookSearchResults } from '../../../src/BookNavigator/search/search-results.js';
9
- customElements.define('ia-book-search-results', IABookSearchResults);
8
+ import { IABookSearchResults } from '../../../../src/BookNavigator/search/search-results.js';
10
9
 
11
10
  const container = (results = [], query = '') => (
12
11
  html`<ia-book-search-results .results=${results} .query=${query}></ia-book-search-results>`
13
12
  );
14
13
 
15
- console.log("ia-book-search-results-test")
16
-
17
14
  const searchQuery = 'Bristol';
18
15
 
19
16
  const results = [{
@@ -0,0 +1,49 @@
1
+ import { expect, fixtureSync } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ import SharingProvider from '../../../../src/BookNavigator/sharing.js';
4
+
5
+ afterEach(() => {
6
+ sinon.restore();
7
+ });
8
+
9
+ const item = {
10
+ metadata: {
11
+ identifier: 'stubby-id',
12
+ creator: 'mr. big',
13
+ title: 'Stubby title',
14
+ }
15
+ };
16
+
17
+ const baseHost = 'foo.org';
18
+ const subPrefix = 'beep-boop_12 4 5';
19
+
20
+ describe('Sharing Provider', () => {
21
+ describe('constructor', () => {
22
+ const provider = new SharingProvider({
23
+ item,
24
+ baseHost,
25
+ bookreader: {
26
+ options: { subPrefix }
27
+ }
28
+ });
29
+
30
+ expect(provider.id).to.equal('share');
31
+ expect(provider.icon).to.exist;
32
+ expect(provider.label).to.equal('Share this book');
33
+ expect(fixtureSync(provider.component).tagName).to.contains('IA-SHARING-OPTIONS');
34
+ });
35
+
36
+ describe('Handles being a sub file/volume', () => {
37
+ it('encodes the subprefix if it has one', async () => {
38
+ const provider = new SharingProvider({
39
+ item,
40
+ baseHost,
41
+ bookreader: {
42
+ options: { subPrefix }
43
+ }
44
+ });
45
+
46
+ expect(fixtureSync(provider.component).fileSubPrefix).to.equal(subPrefix);
47
+ });
48
+ });
49
+ });
@@ -7,8 +7,6 @@ import {
7
7
  import sinon from 'sinon';
8
8
  import { IABookVisualAdjustments } from '../../../src/BookNavigator/visual-adjustments/visual-adjustments.js';
9
9
 
10
- customElements.define('ia-book-visual-adjustments', IABookVisualAdjustments);
11
-
12
10
  const options = [{
13
11
  id: 'contrast',
14
12
  name: 'Adjust contrast',
@@ -0,0 +1,184 @@
1
+ import { expect, fixture, fixtureCleanup, fixtureSync } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ import volumesProvider from '../../../../src/BookNavigator/volumes/volumes-provider';
4
+
5
+ const brOptions = {
6
+ "options": {
7
+ "enableMultipleBooks": true,
8
+ "multipleBooksList": {
9
+ "by_subprefix": {
10
+ "/details/SubBookTest": {
11
+ "url_path": "/details/SubBookTest",
12
+ "file_subprefix": "book1/GPORFP",
13
+ "orig_sort": 1,
14
+ "title": "book1/GPORFP.pdf",
15
+ "file_source": "/book1/GPORFP_jp2.zip"
16
+ },
17
+ "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive": {
18
+ "url_path": "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive",
19
+ "file_subprefix": "subdir/book2/brewster_kahle_internet_archive",
20
+ "orig_sort": 2,
21
+ "title": "subdir/book2/brewster_kahle_internet_archive.pdf",
22
+ "file_source": "/subdir/book2/brewster_kahle_internet_archive_jp2.zip"
23
+ },
24
+ "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume": {
25
+ "url_path": "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
26
+ "file_subprefix": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
27
+ "orig_sort": 3,
28
+ "title": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume.pdf",
29
+ "file_source": "/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume_jp2.zip"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ };
35
+
36
+ afterEach(() => {
37
+ sinon.restore();
38
+ fixtureCleanup();
39
+ });
40
+
41
+ describe('Volumes Provider', () => {
42
+ it('constructor', () => {
43
+ const onProviderChange = sinon.fake();
44
+ const baseHost = "https://archive.org";
45
+ const provider = new volumesProvider({
46
+ baseHost,
47
+ bookreader: brOptions,
48
+ onProviderChange
49
+ });
50
+
51
+ const files = brOptions.options.multipleBooksList.by_subprefix;
52
+ const volumeCount = Object.keys(files).length;
53
+
54
+ expect(provider.onProviderChange).to.equal(onProviderChange);
55
+ expect(provider.id).to.equal('volumes');
56
+ expect(provider.icon).to.exist;
57
+ expect(fixtureSync(provider.icon).tagName).to.equal('svg');
58
+ expect(provider.label).to.equal(`Viewable files (${volumeCount})`);
59
+ expect(provider.viewableFiles).to.exist;
60
+ expect(provider.viewableFiles.length).to.equal(3);
61
+
62
+ expect(provider.component.hostUrl).to.exist;
63
+ expect(provider.component.hostUrl).to.equal(baseHost);
64
+ expect(provider.component).to.exist;
65
+ });
66
+
67
+ it('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).to.equal("default");
77
+
78
+ provider.sortVolumes("title_asc");
79
+ expect(provider.sortOrderBy).to.equal("title_asc");
80
+ expect(fixtureSync(provider.sortButton).outerHTML).includes("sort-by asc-icon");
81
+
82
+ provider.sortVolumes("title_desc");
83
+ expect(provider.sortOrderBy).to.equal("title_desc");
84
+ expect(fixtureSync(provider.sortButton).outerHTML).includes("sort-by desc-icon");
85
+
86
+ provider.sortVolumes("default");
87
+ expect(provider.sortOrderBy).to.equal("default");
88
+ expect(fixtureSync(provider.sortButton).outerHTML).includes("sort-by neutral-icon");
89
+ });
90
+
91
+ it('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).to.equal("default");
107
+ expect(provider.actionButton).to.exist;
108
+
109
+ const providerFileTitles = provider.viewableFiles.map(item => item.title);
110
+ // use `.eql` for "lose equality" in order to deeply compare values.
111
+ expect(providerFileTitles).to.eql([...origSortTitles]);
112
+ });
113
+
114
+ it('sort volumes in ascending title order', async () => {
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).to.equal("title_asc");
130
+ expect(provider.actionButton).to.exist;
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).to.eql([...ascendingTitles]);
135
+ });
136
+
137
+ it('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).to.equals("title_desc");
154
+ expect(provider.actionButton).to.exist;
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).to.eql([...descendingTitles]);
159
+ });
160
+
161
+ describe('Sorting icons', () => {
162
+ it('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')).to.be.true;
174
+
175
+ provider.sortOrderBy = 'title_asc';
176
+ const ascButton = await fixture(provider.sortButton);
177
+ expect(ascButton.classList.contains('asc-icon')).to.be.true;
178
+
179
+ provider.sortOrderBy = 'title_desc';
180
+ const descButton = await fixture(provider.sortButton);
181
+ expect(descButton.classList.contains('desc-icon')).to.be.true;
182
+ });
183
+ });
184
+ });
@@ -0,0 +1,98 @@
1
+ import {
2
+ html,
3
+ fixture,
4
+ expect,
5
+ fixtureCleanup,
6
+ } from '@open-wc/testing';
7
+ import sinon from 'sinon';
8
+ import '../../../../src/BookNavigator/volumes/volumes.js';
9
+
10
+
11
+ const brOptions = {
12
+ "options": {
13
+ "enableMultipleBooks": true,
14
+ "multipleBooksList": {
15
+ "by_subprefix": {
16
+ "/details/SubBookTest": {
17
+ "url_path": "/details/SubBookTest",
18
+ "file_subprefix": "book1/GPORFP",
19
+ "orig_sort": 0,
20
+ "title": "book1/GPORFP.pdf",
21
+ "file_source": "/book1/GPORFP_jp2.zip"
22
+ },
23
+ "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive": {
24
+ "url_path": "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive",
25
+ "file_subprefix": "subdir/book2/brewster_kahle_internet_archive",
26
+ "orig_sort": 1,
27
+ "title": "subdir/book2/brewster_kahle_internet_archive.pdf",
28
+ "file_source": "/subdir/book2/brewster_kahle_internet_archive_jp2.zip"
29
+ },
30
+ "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume": {
31
+ "url_path": "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
32
+ "file_subprefix": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
33
+ "orig_sort": 2,
34
+ "title": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume.pdf",
35
+ "file_source": "/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume_jp2.zip"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ };
41
+
42
+ const container = (brOptions, prefix) => (
43
+ html`
44
+ <viewable-files .viewableFiles=${brOptions} .hostUrl="https://archive.org" .subPrefix=${prefix}></viewable-files>
45
+ `
46
+ );
47
+
48
+ beforeEach(() => {
49
+ const body = document.querySelector('body');
50
+ const brHook = document.createElement('div');
51
+ brHook.setAttribute('id', 'BookReader');
52
+ body.appendChild(brHook);
53
+ });
54
+
55
+ afterEach(() => {
56
+ sinon.restore();
57
+ fixtureCleanup();
58
+ });
59
+
60
+ describe('<viewable-files>', () => {
61
+ it('sets default properties', async () => {
62
+ const files = brOptions.options.multipleBooksList?.by_subprefix;
63
+ const viewableFiles = Object.keys(files).map(item => files[item]);
64
+ const el = await fixture(container(viewableFiles));
65
+ await el.updateComplete;
66
+
67
+ expect(el.viewableFiles).to.equal(viewableFiles);
68
+ expect(el.viewableFiles.length).to.equal(3);
69
+ expect(el.shadowRoot.querySelectorAll("ul li").length).to.equal(3);
70
+
71
+ expect(el.shadowRoot.querySelector(".item-title").innerText).to.include(`${viewableFiles[0].title}`);
72
+ });
73
+
74
+ it('render empty volumes', async () => {
75
+ const viewableFiles = [];
76
+ const el = await fixture(container(viewableFiles));
77
+ await el.updateComplete;
78
+
79
+ expect(el.viewableFiles).to.equal(viewableFiles);
80
+ expect(el.viewableFiles.length).to.equal(0);
81
+ expect(el.shadowRoot.childElementCount).to.equal(0);
82
+ });
83
+
84
+ it('render active volume item set as first viewable item ', async () => {
85
+ const files = brOptions.options.multipleBooksList?.by_subprefix;
86
+ const viewableFiles = Object.keys(files).map(item => files[item]);
87
+ const prefix = viewableFiles[0].file_subprefix;
88
+
89
+ const el = await fixture(container(viewableFiles, prefix));
90
+ await el.updateComplete;
91
+
92
+ expect(el.viewableFiles).to.equal(viewableFiles);
93
+ expect(el.viewableFiles.length).to.equal(3);
94
+
95
+ expect(el.shadowRoot.querySelectorAll("ul li div")[1].className).to.equal("content active");
96
+ });
97
+
98
+ });
package/webpack.config.js CHANGED
@@ -14,7 +14,11 @@ const shared = {
14
14
 
15
15
  module: {
16
16
  rules: [
17
- { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
17
+ {
18
+ test: /\.js$/,
19
+ exclude: /node_modules[/\\](?!(lit-element|lit-html|lit|@lit)[/\\]).*/,
20
+ loader: "babel-loader",
21
+ }
18
22
  ]
19
23
  },
20
24
 
@@ -31,6 +35,9 @@ module.exports = [
31
35
 
32
36
  // Output file -> srcfile
33
37
  entry: {
38
+ // Polyfill bundles
39
+ 'webcomponents-bundle.js': { import: '@webcomponents/webcomponentsjs/webcomponents-bundle.js' },
40
+
34
41
  // BookReader
35
42
  'BookReader.js': './src/BookReader.js',
36
43
 
@@ -39,15 +46,14 @@ module.exports = [
39
46
  'plugins/plugin.autoplay.js': { import: './src/plugins/plugin.autoplay.js', dependOn: 'BookReader.js' },
40
47
  'plugins/plugin.chapters.js': { import: './src/plugins/plugin.chapters.js', dependOn: 'BookReader.js' },
41
48
  'plugins/plugin.iframe.js': { import: './src/plugins/plugin.iframe.js', dependOn: 'BookReader.js' },
42
- 'plugins/plugin.menu_toggle.js': { import: './src/plugins/menu_toggle/plugin.menu_toggle.js', dependOn: 'BookReader.js' },
43
49
  'plugins/plugin.mobile_nav.js': { import: './src/plugins/plugin.mobile_nav.js', dependOn: 'BookReader.js' },
44
50
  'plugins/plugin.resume.js': { import: './src/plugins/plugin.resume.js', dependOn: 'BookReader.js' },
45
51
  'plugins/plugin.search.js': { import: './src/plugins/search/plugin.search.js', dependOn: 'BookReader.js' },
46
52
  'plugins/plugin.text_selection.js': { import: './src/plugins/plugin.text_selection.js', dependOn: 'BookReader.js' },
47
53
  'plugins/plugin.tts.js': { import: './src/plugins/tts/plugin.tts.js', dependOn: 'BookReader.js' },
48
- 'plugins/plugin.url.js': { import: './src/plugins/plugin.url.js', dependOn: 'BookReader.js' },
54
+ 'plugins/plugin.url.js': { import: './src/plugins/url/plugin.url.js', dependOn: 'BookReader.js' },
49
55
  'plugins/plugin.vendor-fullscreen.js': { import: './src/plugins/plugin.vendor-fullscreen.js', dependOn: 'BookReader.js' },
50
- 'bookreader-component-bundle.js': { import: './src/BookReaderComponent/BookReaderComponent.js', dependOn: 'BookReader.js' }
56
+ 'ia-bookreader-bundle.js': { import: './src/ia-bookreader/ia-bookreader.js', dependOn: 'BookReader.js' }
51
57
  },
52
58
 
53
59
  externals: {
package/.babelrc DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/preset-env",
5
- {
6
- "targets": "> 2%, ie 11, edge 14, samsung > 9, OperaMini all, UCAndroid > 12",
7
- "useBuiltIns": "usage",
8
- "corejs": 3
9
- }
10
- ]
11
- ]
12
- }
@@ -1,6 +0,0 @@
1
- version: 1
2
-
3
- update_configs:
4
- - package_manager: "javascript"
5
- directory: "/"
6
- update_schedule: "monthly"
package/.testcaferc.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "appCommand": "npm run serve",
3
- "browsers": ["chrome:headless", "firefox:headless"],
4
- "src": ["tests/e2e/**/*test.js"]
5
- }