@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,501 @@
1
+ import {
2
+ html,
3
+ elementUpdated,
4
+ fixtureCleanup,
5
+ fixtureSync,
6
+ expect,
7
+ } from '@open-wc/testing';
8
+ import sinon from 'sinon';
9
+ import DownloadsProvider from '../../../src/BookNavigator/downloads/downloads-provider.js';
10
+ import SearchProvider from '../../../src/BookNavigator/search/search-provider.js';
11
+ import SharingProvider from '../../../src/BookNavigator/sharing.js';
12
+ import VisualAdjustmentsProvider from '../../../src/BookNavigator/visual-adjustments/visual-adjustments-provider.js';
13
+ import VolumesProvider from '../../../src/BookNavigator/volumes/volumes-provider.js';
14
+ import { ModalManager } from '@internetarchive/modal-manager';
15
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
16
+ import '../../../src/BookNavigator/book-navigator.js';
17
+
18
+ const promise0 = () => new Promise(res => setTimeout(res, 0));
19
+
20
+ const container = (sharedObserver = null) => {
21
+ const itemStub = {
22
+ metadata: {
23
+ identifier: 'foo',
24
+ creator: 'bar',
25
+ title: 'baz',
26
+ }
27
+ };
28
+ const modalMgr = new ModalManager();
29
+ return html`
30
+ <book-navigator
31
+ .itemMD=${itemStub}
32
+ .baseHost=${`https://foo.archive.org`}
33
+ .sharedObserver=${sharedObserver || new SharedResizeObserver()}
34
+ .modal=${modalMgr}
35
+ >
36
+ <div slot="main">
37
+ <div id="BookReader"></div>
38
+ <p class="visible-in-reader">now showing</p>
39
+ <\div>
40
+ </book-navigator>
41
+ `;
42
+ };
43
+
44
+ afterEach(() => {
45
+ window.br = null;
46
+ fixtureCleanup();
47
+ const body = document.querySelector('body');
48
+ body.innerHTML = '';
49
+ sinon.restore();
50
+ });
51
+
52
+
53
+ describe('<book-navigator>', () => {
54
+ describe("How it loads", () => {
55
+ describe('Attaches BookReader listeners before `br.init` is called', () => {
56
+ it('binds global event listeners', async () => {
57
+ const el = fixtureSync(container());
58
+ const spy = sinon.spy(el, 'bindEventListeners');
59
+ await elementUpdated(el);
60
+ expect(spy.callCount).to.equal(1);
61
+ });
62
+ it('Listens for Global Event @BookReader:PostInit', async () => {
63
+ const brStub = {
64
+ resize: sinon.fake(),
65
+ currentIndex: sinon.fake(),
66
+ jumpToIndex: sinon.fake(),
67
+ options: { enableMultipleBooks: false }, // for multipleBooks
68
+ el: '#BookReader'
69
+ };
70
+
71
+ const sharedObserver = new SharedResizeObserver();
72
+ sinon.spy(sharedObserver, 'addObserver');
73
+ const el = fixtureSync(container(sharedObserver));
74
+
75
+ el.initializeBookSubmenus = sinon.fake();
76
+ el.emitLoadingStatusUpdate = sinon.fake();
77
+ el.handleResize = sinon.fake();
78
+ await elementUpdated(el);
79
+
80
+ expect(brStub.resize.callCount).to.equal(0);
81
+
82
+ window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
83
+ detail: { props: brStub }
84
+ }));
85
+ await elementUpdated(el);
86
+
87
+ expect(el.emitLoadingStatusUpdate.callCount).to.equal(1);
88
+ expect(el.bookreader).to.equal(brStub); // sets bookreader
89
+ expect(el.bookReaderLoaded).to.be.true; // notes bookreader is loaded
90
+ expect(el.bookReaderCannotLoad).to.be.false;
91
+ expect(sharedObserver.addObserver.callCount).to.equal(1);
92
+
93
+ await promise0();
94
+
95
+ expect(brStub.resize.callCount > 0).to.be.true;
96
+ });
97
+ });
98
+ it('Emits a BrBookNav:PostInit event at completion', async () => {
99
+ let initEventFired = false;
100
+ window.addEventListener('BrBookNav:PostInit', (e) => {
101
+ initEventFired = true;
102
+ });
103
+ const el = fixtureSync(container());
104
+ const spy = sinon.spy(el, 'emitPostInit');
105
+
106
+ await elementUpdated(el);
107
+
108
+ expect(initEventFired).to.be.true;
109
+ expect(spy.callCount).to.equal(1);
110
+ });
111
+
112
+ it('creates an item image from metadata', async () => {
113
+ const el = fixtureSync(container());
114
+ const itemImage = fixtureSync(el.itemImage);
115
+ expect(itemImage).to.be.instanceOf(HTMLImageElement);
116
+ expect(itemImage.getAttribute('class')).to.equal('cover-img');
117
+ expect(itemImage.getAttribute('src')).to.equal('https://https://foo.archive.org/services/img/foo');
118
+ });
119
+ });
120
+ describe('Menu/Layer Provider', () => {
121
+ describe('Connecting with a provider:', () => {
122
+ // loads Providers with base shared resources
123
+ it('We load 3 Sub Menus by default', async() => {
124
+ const el = fixtureSync(container());
125
+ const $brContainer = document.createElement('div');
126
+ const brStub = {
127
+ resize: sinon.fake(),
128
+ currentIndex: sinon.fake(),
129
+ jumpToIndex: sinon.fake(),
130
+ options: {},
131
+ refs: {
132
+ $brContainer
133
+ }
134
+ };
135
+ el.bookreader = brStub;
136
+ await el.elementUpdated;
137
+
138
+ el.initializeBookSubmenus();
139
+ await el.elementUpdated;
140
+ const defaultMenus = Object.keys(el.menuProviders);
141
+ expect(defaultMenus).to.contain('downloads');
142
+ expect(el.menuProviders.downloads).to.be.instanceOf(DownloadsProvider);
143
+
144
+ expect(defaultMenus).to.contain('share');
145
+ expect(el.menuProviders.share).to.be.instanceOf(SharingProvider);
146
+
147
+ expect(defaultMenus).to.contain('visualAdjustments');
148
+ expect(el.menuProviders.visualAdjustments).to.be.instanceOf(VisualAdjustmentsProvider);
149
+ });
150
+ describe('Loading Sub Menus By Plugin Flags', async() => {
151
+ it('Search: uses `enableSearch` flag', async() => {
152
+ const el = fixtureSync(container());
153
+ const $brContainer = document.createElement('div');
154
+ const brStub = {
155
+ resize: sinon.fake(),
156
+ currentIndex: sinon.fake(),
157
+ jumpToIndex: sinon.fake(),
158
+ options: { enableSearch: true },
159
+ refs: {
160
+ $brContainer
161
+ }
162
+ };
163
+ el.bookreader = brStub;
164
+ await el.elementUpdated;
165
+
166
+ el.initializeBookSubmenus();
167
+ await el.elementUpdated;
168
+
169
+ expect(el.menuProviders.search).to.exist;
170
+ expect(el.menuProviders.search).to.be.instanceOf(SearchProvider);
171
+
172
+ // also adds a menu shortcut
173
+ expect(el.menuShortcuts.find(m => m.id === 'search')).to.exist;
174
+ });
175
+ it('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
176
+ const el = fixtureSync(container());
177
+ const $brContainer = document.createElement('div');
178
+ const brStub = {
179
+ resize: sinon.fake(),
180
+ currentIndex: sinon.fake(),
181
+ jumpToIndex: sinon.fake(),
182
+ options: {
183
+ enableMultipleBooks: true,
184
+ multipleBooksList: {
185
+ by_subprefix: {
186
+ fooSubprefix: 'beep'
187
+ }
188
+ }
189
+ },
190
+ refs: {
191
+ $brContainer
192
+ }
193
+ };
194
+ el.bookreader = brStub;
195
+ await el.elementUpdated;
196
+
197
+ el.initializeBookSubmenus();
198
+ await el.elementUpdated;
199
+
200
+ expect(el.menuProviders.volumes).to.exist;
201
+ expect(el.menuProviders.volumes).to.be.instanceOf(VolumesProvider);
202
+
203
+ // also adds a menu shortcut
204
+ expect(el.menuShortcuts.find(m => m.id === 'volumes')).to.be.exist;
205
+ });
206
+ });
207
+ it('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
208
+ const el = fixtureSync(container());
209
+ const baseConfigKeys = Object.keys(el.baseProviderConfig);
210
+ expect(baseConfigKeys).to.contain('baseHost');
211
+ expect(baseConfigKeys).to.contain('modal');
212
+ expect(baseConfigKeys).to.contain('sharedObserver');
213
+ expect(baseConfigKeys).to.contain('bookreader');
214
+ expect(baseConfigKeys).to.contain('item');
215
+ expect(baseConfigKeys).to.contain('signedIn');
216
+ expect(baseConfigKeys).to.contain('isAdmin');
217
+ expect(baseConfigKeys).to.contain('onProviderChange');
218
+ });
219
+ });
220
+
221
+ describe('Controlling Menu Side Panel & Shortcuts', () => {
222
+ describe('Side Menu Panels', () => {
223
+ it('`isWideEnoughToOpenMenu` checks if menu should be open', async () => {
224
+ const el = fixtureSync(container());
225
+ el.brWidth = 300;
226
+ await el.elementUpdated;
227
+
228
+ expect(el.isWideEnoughToOpenMenu).to.equal(false);
229
+
230
+ el.brWidth = 641;
231
+ await el.elementUpdated;
232
+
233
+ expect(el.isWideEnoughToOpenMenu).to.equal(true);
234
+ });
235
+ describe('Control which side menu to toggle open by using: `this.updateSideMenu`', () => {
236
+ it('Emits `@updateSideMenu` to signal which menu gets the update', async () => {
237
+ const el = fixtureSync(container());
238
+ const brStub = {
239
+ resize: sinon.fake(),
240
+ currentIndex: sinon.fake(),
241
+ jumpToIndex: sinon.fake(),
242
+ options: { enableMultipleBooks: true }
243
+ };
244
+ el.bookreader = brStub;
245
+ await elementUpdated(el);
246
+
247
+ let initEventFired = false;
248
+ let eventDetails = {};
249
+ el.addEventListener('updateSideMenu', (e) => {
250
+ eventDetails = e.detail;
251
+ initEventFired = true;
252
+ });
253
+
254
+ el.updateSideMenu('foo', 'open');
255
+ expect(initEventFired).to.equal(true);
256
+ expect(eventDetails.menuId).to.equal('foo');
257
+ expect(eventDetails.action).to.equal('open');
258
+ });
259
+ it('Will Not Emit `@updateSideMenu` if menu ID is missing', async() => {
260
+ const el = fixtureSync(container());
261
+ const brStub = {
262
+ resize: sinon.fake(),
263
+ currentIndex: sinon.fake(),
264
+ jumpToIndex: sinon.fake(),
265
+ options: { enableMultipleBooks: true }
266
+ };
267
+ el.bookreader = brStub;
268
+ await elementUpdated(el);
269
+
270
+ let initEventFired = false;
271
+ el.addEventListener('updateSideMenu', (e) => {
272
+ initEventFired = true;
273
+ });
274
+
275
+ el.updateSideMenu('', 'open');
276
+ expect(initEventFired).to.equal(false);
277
+ });
278
+ });
279
+ });
280
+
281
+ describe('Shortcuts', () => {
282
+ it('has specific order of menu shortcuts to show', () => {
283
+ const el = fixtureSync(container());
284
+ expect(el.shortcutOrder[0]).to.equal('fullscreen');
285
+ expect(el.shortcutOrder[1]).to.equal('volumes');
286
+ expect(el.shortcutOrder[2]).to.equal('search');
287
+ expect(el.shortcutOrder[3]).to.equal('bookmarks');
288
+ });
289
+ });
290
+
291
+ describe('Behaviors for specific menus', () => {
292
+ describe('Search menu - ref: plugin.search.js', () => {
293
+ it('Event: listens for `BookReader:ToggleSearchMenu to open search side panel', async () => {
294
+ const el = fixtureSync(container());
295
+ const brStub = {
296
+ resize: sinon.fake(),
297
+ currentIndex: sinon.fake(),
298
+ jumpToIndex: sinon.fake(),
299
+ options: { enableMultipleBooks: true }
300
+ };
301
+ el.bookreader = brStub;
302
+ await elementUpdated(el);
303
+
304
+ let sidePanelConfig = {};
305
+ el.addEventListener('updateSideMenu', (e) => {
306
+ console.log();
307
+ sidePanelConfig = e.detail;
308
+ });
309
+ const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
310
+ window.dispatchEvent(toggleSearchMenuEvent);
311
+
312
+ await elementUpdated(el);
313
+ expect(sidePanelConfig.menuId).to.equal('search');
314
+ expect(sidePanelConfig.action).to.equal('toggle');
315
+ });
316
+ });
317
+ });
318
+ });
319
+ });
320
+
321
+ describe('Resizing',() => {
322
+ it('keeps track of `brWidth` and `brHeight`', async () => {
323
+ const el = fixtureSync(container());
324
+ const brStub = {
325
+ resize: sinon.fake(),
326
+ options: {},
327
+ refs: {
328
+ $brContainer: document.createElement('div')
329
+ }
330
+ };
331
+ el.bookreader = brStub;
332
+ await elementUpdated(el);
333
+ expect(el.brWidth).to.equal(0);
334
+ expect(el.brHeight).to.equal(0);
335
+
336
+ const mockResizeEvent = {
337
+ contentRect: {
338
+ height: 500,
339
+ width: 900
340
+ },
341
+ target: el.mainBRContainer
342
+ };
343
+ el.handleResize(mockResizeEvent);
344
+
345
+ await elementUpdated(el);
346
+ await promise0();
347
+
348
+ expect(el.brHeight).to.equal(500);
349
+ expect(el.brWidth).to.equal(900);
350
+ });
351
+ it('resizes if height/width changes && is not animating', async () => {
352
+ const el = fixtureSync(container());
353
+ const brStub = {
354
+ animating: false,
355
+ resize: sinon.fake(),
356
+ options: {},
357
+ refs: {
358
+ $brContainer: document.createElement('div')
359
+ }
360
+ };
361
+
362
+ el.bookreader = brStub;
363
+ await elementUpdated(el);
364
+ expect(el.brWidth).to.equal(0);
365
+ expect(el.brHeight).to.equal(0);
366
+
367
+ const mockResizeEvent = {
368
+ contentRect: {
369
+ height: 500,
370
+ width: 900
371
+ },
372
+ target: el.mainBRContainer
373
+ };
374
+ el.handleResize(mockResizeEvent);
375
+
376
+ await elementUpdated(el);
377
+ await promise0();
378
+
379
+ expect(brStub.resize.callCount).to.equal(1);
380
+ });
381
+ it('does not resize bookreader if animating', async () => {
382
+ const el = fixtureSync(container());
383
+ const brStub = {
384
+ animating: true, // <-- testing for this
385
+ resize: sinon.fake(),
386
+ currentIndex: sinon.fake(),
387
+ jumpToIndex: sinon.fake(),
388
+ options: { enableMultipleBooks: true }
389
+ };
390
+
391
+ el.bookreader = brStub;
392
+ await elementUpdated(el);
393
+
394
+ expect(el.bookreader.resize.callCount).to.equal(0);
395
+ expect(el.bookreader.currentIndex.callCount).to.equal(0);
396
+ expect(el.bookreader.jumpToIndex.callCount).to.equal(0);
397
+ });
398
+ });
399
+
400
+ describe('Fullscreen Management', () => {
401
+ it('needs option: `enableFSLogoShortcut` to use FS logo', async () => {
402
+ const el = fixtureSync(container());
403
+ const brStub = {
404
+ isFullscreen: () => true,
405
+ options: {
406
+ enableFSLogoShortcut: false,
407
+ }
408
+ };
409
+
410
+ el.bookreader = brStub;
411
+ el.emitMenuShortcutsUpdated = sinon.fake();
412
+ await elementUpdated(el);
413
+
414
+ el.manageFullScreenBehavior();
415
+ await elementUpdated(el);
416
+ expect(el.menuShortcuts.length).to.equal(0);
417
+ });
418
+ it('sets fullscreen shortcut when entering Fullscreen', async () => {
419
+ const el = fixtureSync(container());
420
+ const brStub = {
421
+ isFullscreen: () => true,
422
+ options: {
423
+ enableFSLogoShortcut: true,
424
+ }
425
+ };
426
+
427
+ el.bookreader = brStub;
428
+ el.emitMenuShortcutsUpdated = sinon.fake();
429
+ await elementUpdated(el);
430
+
431
+ el.manageFullScreenBehavior();
432
+ await elementUpdated(el);
433
+ expect(el.menuShortcuts.length).to.equal(1);
434
+ expect(el.menuShortcuts[0].id).to.equal('fullscreen');
435
+ expect(el.menuShortcuts[0].icon).to.exist;
436
+ expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
437
+ });
438
+ it('clicking Fullscreen shortcut closes fullscreen', async () => {
439
+ const el = fixtureSync(container());
440
+ const brStub = {
441
+ isFullscreen: () => true,
442
+ options: {
443
+ enableFSLogoShortcut: true,
444
+ }
445
+ };
446
+
447
+ el.bookreader = brStub;
448
+ el.emitMenuShortcutsUpdated = sinon.fake();
449
+ el.closeFullscreen = sinon.fake();
450
+ await elementUpdated(el);
451
+
452
+ el.manageFullScreenBehavior();
453
+ await elementUpdated(el);
454
+
455
+ fixtureSync(el.menuShortcuts[0].icon).click();
456
+ await elementUpdated(el);
457
+
458
+ expect(el.closeFullscreen.callCount).to.equal(1);
459
+ });
460
+ it('removes Fullscreen shortcut when leaving fullscreen', async() => {
461
+ const el = fixtureSync(container());
462
+ const brStub = {
463
+ isFullscreen: () => false,
464
+ options: {
465
+ enableFSLogoShortcut: true,
466
+ }
467
+ };
468
+
469
+ el.bookreader = brStub;
470
+ el.emitMenuShortcutsUpdated = sinon.fake();
471
+ await elementUpdated(el);
472
+
473
+ el.manageFullScreenBehavior();
474
+ await elementUpdated(el);
475
+ expect(el.menuShortcuts.length).to.equal(0);
476
+ expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
477
+ });
478
+ it('Event: Listens for `BookReader:FullscreenToggled', async() => {
479
+ const el = fixtureSync(container());
480
+ const brStub = {
481
+ isFullscreen: () => true,
482
+ resize: sinon.fake(),
483
+ currentIndex: sinon.fake(),
484
+ jumpToIndex: sinon.fake(),
485
+ options: {
486
+ enableFSLogoShortcut: true,
487
+ }
488
+ };
489
+ el.bookreader = brStub;
490
+ el.manageFullScreenBehavior = sinon.fake();
491
+ await elementUpdated(el);
492
+
493
+ window.dispatchEvent(new CustomEvent('BookReader:fullscreenToggled', {
494
+ detail: { props: brStub }
495
+ }));
496
+ await elementUpdated(el);
497
+
498
+ expect(el.manageFullScreenBehavior.callCount).to.equal(1);
499
+ });
500
+ });
501
+ });
@@ -0,0 +1,44 @@
1
+ import {
2
+ html,
3
+ fixtureSync,
4
+ expect,
5
+ fixtureCleanup,
6
+ } from '@open-wc/testing';
7
+ import '../../../../src/BookNavigator/bookmarks/bookmark-button.js';
8
+ import sinon from 'sinon';
9
+
10
+ afterEach(() => {
11
+ sinon.restore();
12
+ fixtureCleanup();
13
+ });
14
+
15
+ describe('<bookmark-button>', () => {
16
+ it('sets default properties', async () => {
17
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
18
+
19
+ expect(el.side).to.be.undefined;
20
+ expect(el.state).to.equal('hollow');
21
+ });
22
+ it('Event: fires `@bookmarkButtonClicked on click', async () => {
23
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
24
+ let buttonClicked = false;
25
+ el.addEventListener('bookmarkButtonClicked', () => { buttonClicked = true; });
26
+ const eventStub = { preventDefault: sinon.fake()};
27
+ el.handleClick(eventStub);
28
+ await el.updateComplete;
29
+
30
+ expect(buttonClicked).to.be.true;
31
+ expect(eventStub.preventDefault.callCount).to.equal(1);
32
+ });
33
+ it('Title: Toggles title between `Add/Remove bookmark`', async () => {
34
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
35
+ expect(el.title).to.equal('Add bookmark');
36
+ expect(el.state).to.equal('hollow');
37
+
38
+ el.state = 'filled';
39
+ await el.updateComplete;
40
+
41
+ expect(el.title).to.equal('Remove bookmark');
42
+ expect(el.state).to.not.equal('hollow');
43
+ });
44
+ });
@@ -4,7 +4,7 @@ import {
4
4
  expect,
5
5
  oneEvent,
6
6
  } from '@open-wc/testing';
7
- import { IABookmarkEdit } from '../../../../src/BookNavigator/bookmarks/bookmark-edit.js';
7
+ import '../../../../src/BookNavigator/bookmarks/bookmark-edit.js';
8
8
 
9
9
  const bookmarkColors = [{
10
10
  id: 0,
@@ -23,8 +23,6 @@ const bookmarkColors = [{
23
23
  className: 'yellow',
24
24
  }];
25
25
 
26
- customElements.define('ia-bookmark-edit', IABookmarkEdit);
27
-
28
26
  const container = (bookmark = {}) => (
29
27
  html`<ia-bookmark-edit .bookmark=${bookmark} .bookmarkColors=${bookmarkColors}></ia-bookmark-edit>`
30
28
  );
@@ -4,8 +4,7 @@ import {
4
4
  expect,
5
5
  oneEvent,
6
6
  } from '@open-wc/testing';
7
- import { IABookmarksList } from '../../../../src/BookNavigator/bookmarks/bookmarks-list.js';
8
- customElements.define('ia-bookmarks-list', IABookmarksList);
7
+ import '../../../../src/BookNavigator/bookmarks/bookmarks-list.js';
9
8
 
10
9
  const bookmarks = [{
11
10
  id: 1,
@@ -50,7 +49,7 @@ describe('<ia-bookmarks-list>', () => {
50
49
  it('renders bookmarks that contain page numbers', async () => {
51
50
  const el = await fixture(container(bookmarks));
52
51
 
53
- expect(el.shadowRoot.innerHTML).to.include(`Page ${bookmarks[0].page}`);
52
+ expect(el.shadowRoot.textContent).to.include(`Page ${bookmarks[0].page}`);
54
53
  });
55
54
 
56
55
  it('renders bookmarks that contain an optional note', async () => {
@@ -162,7 +161,7 @@ describe('<ia-bookmarks-list>', () => {
162
161
  const el = await fixture(container([bookmarks[0]]));
163
162
  const bookmarksCount = await fixture(el.bookmarksCount);
164
163
 
165
- expect(bookmarksCount.innerHTML).to.include('(1)');
164
+ expect(bookmarksCount.textContent).to.include('(1)');
166
165
  });
167
166
 
168
167
  it('does not render the bookmarks count when no bookmarks present', async () => {
@@ -0,0 +1,57 @@
1
+ import {
2
+ html,
3
+ fixtureSync,
4
+ expect,
5
+ fixtureCleanup,
6
+ } from '@open-wc/testing';
7
+ import '../../../../src/BookNavigator/bookmarks/ia-bookmarks.js';
8
+ import sinon from 'sinon';
9
+
10
+ afterEach(() => {
11
+ sinon.restore();
12
+ fixtureCleanup();
13
+ });
14
+
15
+ describe('<ia-bookmarks>', () => {
16
+ it('uses `setup` to start component', async () => {
17
+ const el = fixtureSync(html`<ia-bookmarks></ia-bookmarks>`);
18
+ await el.updateComplete;
19
+
20
+ let fetchHappened = false;
21
+ el.bookreader.bookId = 'foo';
22
+ el.displayMode = 'bookmarks';
23
+
24
+ el.fetchBookmarks = async () => {
25
+ fetchHappened = true;
26
+ return await Promise.resolve();
27
+ };
28
+
29
+ const fetchSpy = sinon.spy(el, 'fetchUserBookmarks');
30
+
31
+ el.setup();
32
+ await el.updateComplete;
33
+
34
+ expect(fetchSpy.callCount).to.equal(1);
35
+ expect(fetchHappened).to.equal(true);
36
+ });
37
+ it('does not fetch user bookmarks if displayMode = login', async () => {
38
+ const el = fixtureSync(html`<ia-bookmarks></ia-bookmarks>`);
39
+ await el.updateComplete;
40
+
41
+ let fetchHappened = false;
42
+ el.displayMode = 'login';
43
+
44
+ el.fetchBookmarks = async () => {
45
+ fetchHappened = true;
46
+ return await Promise.resolve();
47
+ };
48
+
49
+ const fetchSpy = sinon.spy(el, 'fetchUserBookmarks');
50
+
51
+ el.setup();
52
+ await el.updateComplete;
53
+
54
+ expect(fetchSpy.callCount).to.equal(0);
55
+ expect(fetchHappened).to.equal(false);
56
+ });
57
+ });