@internetarchive/bookreader 5.0.0-6-14 → 5.0.0-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (271) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +72 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +241 -140
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1519 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
  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/pause.svg +1 -1
  16. package/BookReader/icons/playback-speed.svg +1 -1
  17. package/BookReader/icons/read-aloud.svg +1 -1
  18. package/BookReader/icons/voice.svg +1 -0
  19. package/BookReader/images/BRicons.svg +2 -2
  20. package/BookReader/images/books_graphic.svg +1 -1
  21. package/BookReader/images/icon_book.svg +1 -1
  22. package/BookReader/images/icon_gear.svg +1 -1
  23. package/BookReader/images/icon_info.svg +1 -1
  24. package/BookReader/images/icon_playback-rate.svg +1 -1
  25. package/BookReader/images/icon_search_button.svg +1 -1
  26. package/BookReader/images/icon_share.svg +1 -1
  27. package/BookReader/images/icon_speaker.svg +1 -1
  28. package/BookReader/images/icon_speaker_open.svg +1 -1
  29. package/BookReader/images/marker_chap-off.svg +1 -1
  30. package/BookReader/images/marker_chap-on.svg +1 -1
  31. package/BookReader/images/marker_srch-on.svg +1 -1
  32. package/BookReader/jquery-3.js +2 -0
  33. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  34. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  35. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  36. package/BookReader/plugins/plugin.autoplay.js +1 -1
  37. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  38. package/BookReader/plugins/plugin.chapters.js +1 -1
  39. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  40. package/BookReader/plugins/plugin.iframe.js +1 -1
  41. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  42. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  43. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  44. package/BookReader/plugins/plugin.resume.js +1 -1
  45. package/BookReader/plugins/plugin.resume.js.map +1 -1
  46. package/BookReader/plugins/plugin.search.js +1 -1
  47. package/BookReader/plugins/plugin.search.js.map +1 -1
  48. package/BookReader/plugins/plugin.text_selection.js +1 -1
  49. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  50. package/BookReader/plugins/plugin.tts.js +1 -1
  51. package/BookReader/plugins/plugin.tts.js.map +1 -1
  52. package/BookReader/plugins/plugin.url.js +1 -1
  53. package/BookReader/plugins/plugin.url.js.map +1 -1
  54. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  55. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  56. package/BookReader/webcomponents-bundle.js +3 -0
  57. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  58. package/BookReader/webcomponents-bundle.js.map +1 -0
  59. package/BookReaderDemo/BookReaderDemo.css +14 -1
  60. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  61. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  62. package/BookReaderDemo/IADemoBr.js +147 -0
  63. package/BookReaderDemo/demo-advanced.html +2 -2
  64. package/BookReaderDemo/demo-autoplay.html +2 -1
  65. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  66. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  67. package/BookReaderDemo/demo-fullscreen.html +2 -1
  68. package/BookReaderDemo/demo-iiif.html +2 -1
  69. package/BookReaderDemo/demo-internetarchive.html +84 -17
  70. package/BookReaderDemo/demo-multiple.html +2 -1
  71. package/BookReaderDemo/demo-preview-pages.html +2 -1
  72. package/BookReaderDemo/demo-simple.html +2 -1
  73. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  74. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  75. package/BookReaderDemo/immersion-1up.html +2 -1
  76. package/BookReaderDemo/immersion-mode.html +2 -1
  77. package/BookReaderDemo/toggle_controls.html +2 -1
  78. package/BookReaderDemo/view_mode.html +2 -1
  79. package/BookReaderDemo/viewmode-cycle.html +2 -3
  80. package/CHANGELOG.md +244 -0
  81. package/README.md +14 -1
  82. package/babel.config.js +19 -0
  83. package/codecov.yml +6 -0
  84. package/index.html +3 -0
  85. package/jsconfig.json +19 -0
  86. package/netlify.toml +5 -0
  87. package/package.json +70 -59
  88. package/renovate.json +52 -0
  89. package/scripts/preversion.js +4 -1
  90. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  91. package/src/BookNavigator/assets/button-base.js +9 -2
  92. package/src/BookNavigator/assets/ia-logo.js +17 -0
  93. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  94. package/src/BookNavigator/assets/icon_close.js +1 -1
  95. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  96. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  97. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  98. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  99. package/src/BookNavigator/book-navigator.js +585 -0
  100. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  101. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  102. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  103. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  104. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  105. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  106. package/src/BookNavigator/delete-modal-actions.js +1 -1
  107. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  108. package/src/BookNavigator/downloads/downloads.js +41 -25
  109. package/src/BookNavigator/search/search-provider.js +80 -28
  110. package/src/BookNavigator/search/search-results.js +34 -25
  111. package/src/BookNavigator/sharing.js +27 -0
  112. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  113. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  114. package/src/BookNavigator/volumes/volumes-provider.js +111 -0
  115. package/src/BookNavigator/volumes/volumes.js +188 -0
  116. package/src/BookReader/BookModel.js +59 -30
  117. package/src/BookReader/DebugConsole.js +3 -3
  118. package/src/BookReader/DragScrollable.js +233 -0
  119. package/src/BookReader/Mode1Up.js +56 -351
  120. package/src/BookReader/Mode1UpLit.js +391 -0
  121. package/src/BookReader/Mode2Up.js +73 -1318
  122. package/src/BookReader/Mode2UpLit.js +781 -0
  123. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  124. package/src/BookReader/ModeSmoothZoom.js +211 -0
  125. package/src/BookReader/ModeThumb.js +17 -11
  126. package/src/BookReader/Navbar/Navbar.js +10 -36
  127. package/src/BookReader/PageContainer.js +69 -6
  128. package/src/BookReader/ReduceSet.js +1 -1
  129. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  130. package/src/BookReader/events.js +2 -0
  131. package/src/BookReader/options.js +24 -2
  132. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  133. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  134. package/src/BookReader/utils.js +108 -13
  135. package/src/BookReader.js +481 -828
  136. package/src/assets/icons/close-circle-dark.svg +1 -0
  137. package/src/assets/icons/magnify-minus.svg +3 -7
  138. package/src/assets/icons/magnify-plus.svg +3 -7
  139. package/src/assets/icons/voice.svg +1 -0
  140. package/src/css/_BRBookmarks.scss +1 -1
  141. package/src/css/_BRComponent.scss +1 -1
  142. package/src/css/_BRmain.scss +33 -0
  143. package/src/css/_BRnav.scss +4 -26
  144. package/src/css/_BRpages.scss +147 -40
  145. package/src/css/_BRsearch.scss +25 -11
  146. package/src/css/_TextSelection.scss +16 -17
  147. package/src/css/_colorbox.scss +2 -2
  148. package/src/css/_controls.scss +17 -5
  149. package/src/css/_icons.scss +7 -1
  150. package/src/ia-bookreader/ia-bookreader.js +224 -0
  151. package/src/plugins/plugin.archive_analytics.js +3 -3
  152. package/src/plugins/plugin.autoplay.js +4 -9
  153. package/src/plugins/plugin.chapters.js +28 -35
  154. package/src/plugins/plugin.mobile_nav.js +11 -10
  155. package/src/plugins/plugin.resume.js +3 -3
  156. package/src/plugins/plugin.text_selection.js +32 -41
  157. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  158. package/src/plugins/search/plugin.search.js +179 -103
  159. package/src/plugins/search/view.js +59 -44
  160. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  161. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  162. package/src/plugins/tts/PageChunk.js +15 -21
  163. package/src/plugins/tts/PageChunkIterator.js +8 -12
  164. package/src/plugins/tts/WebTTSEngine.js +87 -71
  165. package/src/plugins/tts/plugin.tts.js +94 -125
  166. package/src/plugins/tts/utils.js +0 -25
  167. package/src/plugins/url/UrlPlugin.js +193 -0
  168. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  169. package/src/util/docCookies.js +21 -2
  170. package/tests/e2e/README.md +37 -0
  171. package/tests/e2e/autoplay.test.js +2 -2
  172. package/tests/e2e/base.test.js +7 -7
  173. package/tests/e2e/helpers/base.js +28 -23
  174. package/tests/e2e/helpers/debug.js +1 -1
  175. package/tests/e2e/helpers/desktopSearch.js +14 -13
  176. package/tests/e2e/helpers/mobileSearch.js +3 -3
  177. package/tests/e2e/helpers/params.js +17 -0
  178. package/tests/e2e/helpers/rightToLeft.js +4 -10
  179. package/tests/e2e/models/Navigation.js +13 -4
  180. package/tests/e2e/rightToLeft.test.js +4 -5
  181. package/tests/e2e/viewmode.test.js +40 -33
  182. package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
  183. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  184. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  185. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  186. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  187. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  188. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  189. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  190. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +104 -60
  191. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  192. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  193. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  194. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  195. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +59 -14
  196. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  197. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  198. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  199. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  200. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  201. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  202. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  203. package/tests/jest/BookReader/ModeSmoothZoom.test.js +175 -0
  204. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  205. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  206. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  207. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  208. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  209. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  210. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  211. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  212. package/tests/jest/BookReader/utils.test.js +217 -0
  213. package/tests/jest/BookReader.keyboard.test.js +190 -0
  214. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  215. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  216. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  217. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  218. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  219. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  220. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  221. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  222. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  223. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  224. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +57 -47
  225. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  226. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  227. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  228. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  229. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  230. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  231. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  232. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  233. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  234. package/tests/jest/setup.js +3 -0
  235. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  236. package/tests/jest/util/docCookies.test.js +24 -0
  237. package/tests/{util → jest/util}/strings.test.js +1 -1
  238. package/tests/{utils.js → jest/utils.js} +38 -0
  239. package/webpack.config.js +11 -5
  240. package/.babelrc +0 -12
  241. package/.dependabot/config.yml +0 -6
  242. package/.testcaferc.json +0 -5
  243. package/BookReader/bookreader-component-bundle.js +0 -1450
  244. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  245. package/BookReader/bookreader-component-bundle.js.map +0 -1
  246. package/BookReader/jquery-1.10.1.js +0 -2
  247. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  248. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  249. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  250. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  251. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  252. package/karma.conf.js +0 -23
  253. package/src/BookNavigator/BookModel.js +0 -14
  254. package/src/BookNavigator/BookNavigator.js +0 -438
  255. package/src/BookNavigator/assets/book-loader.js +0 -27
  256. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  257. package/src/BookNavigator/search/a-search-result.js +0 -55
  258. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  259. package/src/ItemNavigator/ItemNavigator.js +0 -372
  260. package/src/ItemNavigator/providers/sharing.js +0 -29
  261. package/src/dragscrollable-br.js +0 -261
  262. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  263. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  264. package/tests/BookReader/Mode1Up.test.js +0 -164
  265. package/tests/BookReader/Mode2Up.test.js +0 -247
  266. package/tests/BookReader/utils.test.js +0 -109
  267. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  268. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  269. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  270. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  271. package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,658 @@
1
+ import {
2
+ html,
3
+ elementUpdated,
4
+ fixtureCleanup,
5
+ fixtureSync,
6
+ } from '@open-wc/testing-helpers';
7
+ import sinon from 'sinon';
8
+ import DownloadsProvider from '@/src/BookNavigator/downloads/downloads-provider.js';
9
+ import SearchProvider from '@/src/BookNavigator/search/search-provider.js';
10
+ import SharingProvider from '@/src/BookNavigator/sharing.js';
11
+ import VisualAdjustmentsProvider from '@/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js';
12
+ import VolumesProvider from '@/src/BookNavigator/volumes/volumes-provider.js';
13
+ import { ModalManager } from '@internetarchive/modal-manager';
14
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
15
+ import '@/src/BookNavigator/book-navigator.js';
16
+
17
+ const promise0 = () => new Promise(res => setTimeout(res, 0));
18
+
19
+ const container = (sharedObserver = null) => {
20
+ const itemStub = {
21
+ metadata: {
22
+ identifier: 'foo',
23
+ creator: 'bar',
24
+ title: 'baz',
25
+ }
26
+ };
27
+ const modalMgr = new ModalManager();
28
+ return html`
29
+ <book-navigator
30
+ .itemMD=${itemStub}
31
+ .baseHost=${`https://foo.archive.org`}
32
+ .sharedObserver=${sharedObserver || new SharedResizeObserver()}
33
+ .modal=${modalMgr}
34
+ >
35
+ <div slot="main">
36
+ <div id="BookReader"></div>
37
+ <p class="visible-in-reader">now showing</p>
38
+ <\div>
39
+ </book-navigator>
40
+ `;
41
+ };
42
+
43
+ window.ResizeObserver = class ResizeObserver {
44
+ observe = sinon.fake()
45
+ unobserve = sinon.fake()
46
+ disconnect = sinon.fake()
47
+ };
48
+
49
+ beforeEach(() => {
50
+ window.archive_analytics = {
51
+ send_event_no_sampling: sinon.fake(),
52
+ send_event: sinon.fake()
53
+ };
54
+ });
55
+
56
+ afterEach(() => {
57
+ window.br = null;
58
+ fixtureCleanup();
59
+ const body = document.querySelector('body');
60
+ body.innerHTML = '';
61
+ sinon.restore();
62
+ });
63
+
64
+
65
+ describe('<book-navigator>', () => {
66
+ describe("How it loads", () => {
67
+ describe('Attaches BookReader listeners before `br.init` is called', () => {
68
+ test('binds global event listeners', async () => {
69
+ const el = fixtureSync(container());
70
+ const spy = sinon.spy(el, 'bindEventListeners');
71
+ await elementUpdated(el);
72
+ expect(spy.callCount).toEqual(1);
73
+ });
74
+ test('Listens for Global Event @BookReader:PostInit', async () => {
75
+ const brStub = {
76
+ resize: sinon.fake(),
77
+ currentIndex: sinon.fake(),
78
+ jumpToIndex: sinon.fake(),
79
+ options: { enableMultipleBooks: false }, // for multipleBooks
80
+ el: '#BookReader',
81
+ refs: {}
82
+ };
83
+
84
+ const sharedObserver = new SharedResizeObserver();
85
+ sinon.spy(sharedObserver, 'addObserver');
86
+ const el = fixtureSync(container(sharedObserver));
87
+
88
+ el.initializeBookSubmenus = sinon.fake();
89
+ el.emitLoadingStatusUpdate = sinon.fake();
90
+ el.handleResize = sinon.fake();
91
+ await elementUpdated(el);
92
+
93
+ expect(brStub.resize.callCount).toEqual(0);
94
+
95
+ window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
96
+ detail: { props: brStub }
97
+ }));
98
+ await elementUpdated(el);
99
+
100
+ expect(el.emitLoadingStatusUpdate.callCount).toEqual(1);
101
+ expect(el.bookreader).toEqual(brStub); // sets bookreader
102
+ expect(el.bookReaderLoaded).toBeTruthy(); // notes bookreader is loaded
103
+ expect(el.bookReaderCannotLoad).toBeFalsy();
104
+ expect(sharedObserver.addObserver.callCount).toEqual(1);
105
+
106
+ await promise0();
107
+
108
+ expect(brStub.resize.callCount > 0).toBeTruthy();
109
+ });
110
+ });
111
+ test('Emits a BrBookNav:PostInit event at completion', async () => {
112
+ let initEventFired = false;
113
+ window.addEventListener('BrBookNav:PostInit', (e) => {
114
+ initEventFired = true;
115
+ });
116
+ const el = fixtureSync(container());
117
+ const spy = sinon.spy(el, 'emitPostInit');
118
+
119
+ await elementUpdated(el);
120
+
121
+ expect(initEventFired).toBeTruthy();
122
+ expect(spy.callCount).toEqual(1);
123
+ });
124
+
125
+ test('creates an item image from metadata', async () => {
126
+ const el = fixtureSync(container());
127
+ const itemImage = fixtureSync(el.itemImage);
128
+ expect(itemImage).toBeInstanceOf(HTMLImageElement);
129
+ expect(itemImage.getAttribute('class')).toEqual('cover-img');
130
+ expect(itemImage.getAttribute('src')).toEqual('https://https://foo.archive.org/services/img/foo');
131
+ });
132
+ });
133
+ describe('Menu/Layer Provider', () => {
134
+ describe('Connecting with a provider:', () => {
135
+ // loads Providers with base shared resources
136
+ test('We load 3 Sub Menus by default', async() => {
137
+ const el = fixtureSync(container());
138
+ const $brContainer = document.createElement('div');
139
+ const brStub = {
140
+ resize: sinon.fake(),
141
+ currentIndex: sinon.fake(),
142
+ jumpToIndex: sinon.fake(),
143
+ options: {},
144
+ refs: {
145
+ $brContainer
146
+ }
147
+ };
148
+ el.bookreader = brStub;
149
+ await el.elementUpdated;
150
+
151
+ el.downloadableTypes = ['foo/bar'];
152
+ await el.elementUpdated;
153
+
154
+ el.initializeBookSubmenus();
155
+ await el.elementUpdated;
156
+ const defaultMenus = Object.keys(el.menuProviders);
157
+ expect(defaultMenus).toContain('downloads');
158
+ expect(el.menuProviders.downloads).toBeInstanceOf(DownloadsProvider);
159
+
160
+ expect(defaultMenus).toContain('share');
161
+ expect(el.menuProviders.share).toBeInstanceOf(SharingProvider);
162
+
163
+ expect(defaultMenus).toContain('visualAdjustments');
164
+ expect(el.menuProviders.visualAdjustments).toBeInstanceOf(VisualAdjustmentsProvider);
165
+ });
166
+ describe('Loading Sub Menus By Plugin Flags', () => {
167
+ test('Search: uses `enableSearch` flag', async() => {
168
+ const el = fixtureSync(container());
169
+ const $brContainer = document.createElement('div');
170
+ const brStub = {
171
+ resize: sinon.fake(),
172
+ currentIndex: sinon.fake(),
173
+ jumpToIndex: sinon.fake(),
174
+ options: { enableSearch: true },
175
+ refs: {
176
+ $brContainer
177
+ }
178
+ };
179
+ el.bookreader = brStub;
180
+ await el.elementUpdated;
181
+
182
+ el.initializeBookSubmenus();
183
+ await el.elementUpdated;
184
+
185
+ expect(el.menuProviders.search).toBeDefined();
186
+ expect(el.menuProviders.search).toBeInstanceOf(SearchProvider);
187
+
188
+ // also adds a menu shortcut
189
+ expect(el.menuShortcuts.find(m => m.id === 'search')).toBeDefined();
190
+ });
191
+ test('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
192
+ const el = fixtureSync(container());
193
+ const $brContainer = document.createElement('div');
194
+ const brStub = {
195
+ resize: sinon.fake(),
196
+ currentIndex: sinon.fake(),
197
+ jumpToIndex: sinon.fake(),
198
+ options: {
199
+ enableMultipleBooks: true,
200
+ multipleBooksList: {
201
+ by_subprefix: {
202
+ fooSubprefix: 'beep'
203
+ }
204
+ }
205
+ },
206
+ refs: {
207
+ $brContainer
208
+ }
209
+ };
210
+ el.bookreader = brStub;
211
+ await el.elementUpdated;
212
+
213
+ el.initializeBookSubmenus();
214
+ await el.elementUpdated;
215
+
216
+ expect(el.menuProviders.volumes).toBeDefined();
217
+ expect(el.menuProviders.volumes).toBeInstanceOf(VolumesProvider);
218
+
219
+ // also adds a menu shortcut
220
+ expect(el.menuShortcuts.find(m => m.id === 'volumes')).toBeDefined();
221
+ });
222
+ });
223
+ test('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
224
+ const el = fixtureSync(container());
225
+ const baseConfigKeys = Object.keys(el.baseProviderConfig);
226
+ expect(baseConfigKeys).toContain('baseHost');
227
+ expect(baseConfigKeys).toContain('modal');
228
+ expect(baseConfigKeys).toContain('sharedObserver');
229
+ expect(baseConfigKeys).toContain('bookreader');
230
+ expect(baseConfigKeys).toContain('item');
231
+ expect(baseConfigKeys).toContain('signedIn');
232
+ expect(baseConfigKeys).toContain('isAdmin');
233
+ expect(baseConfigKeys).toContain('onProviderChange');
234
+ });
235
+
236
+ test('Downloads panel - does not show if no available `downloadableTypes`', async () => {
237
+ const el = fixtureSync(container());
238
+ const $brContainer = document.createElement('div');
239
+ const brStub = {
240
+ resize: sinon.fake(),
241
+ currentIndex: sinon.fake(),
242
+ jumpToIndex: sinon.fake(),
243
+ options: {},
244
+ refs: {
245
+ $brContainer
246
+ }
247
+ };
248
+ el.bookreader = brStub;
249
+ await el.elementUpdated;
250
+
251
+ el.initializeBookSubmenus();
252
+ await el.elementUpdated;
253
+ const defaultMenus = Object.keys(el.menuProviders);
254
+ expect(defaultMenus.find(menu => menu === 'downloads')).toBeUndefined;
255
+ });
256
+ });
257
+
258
+ describe('Controlling Menu Side Panel & Shortcuts', () => {
259
+ describe('Side Menu Panels', () => {
260
+ test('`isWideEnoughToOpenMenu` checks if menu should be open', async () => {
261
+ const el = fixtureSync(container());
262
+ el.brWidth = 300;
263
+ await el.elementUpdated;
264
+
265
+ expect(el.isWideEnoughToOpenMenu).toEqual(false);
266
+
267
+ el.brWidth = 641;
268
+ await el.elementUpdated;
269
+
270
+ expect(el.isWideEnoughToOpenMenu).toEqual(true);
271
+ });
272
+ describe('Control which side menu to toggle open by using: `this.updateSideMenu`', () => {
273
+ test('Emits `@updateSideMenu` to signal which menu gets the update', async () => {
274
+ const el = fixtureSync(container());
275
+ const brStub = {
276
+ resize: sinon.fake(),
277
+ currentIndex: sinon.fake(),
278
+ jumpToIndex: sinon.fake(),
279
+ options: { enableMultipleBooks: true },
280
+ refs: {},
281
+ };
282
+ el.bookreader = brStub;
283
+ await elementUpdated(el);
284
+
285
+ let initEventFired = false;
286
+ let eventDetails = {};
287
+ el.addEventListener('updateSideMenu', (e) => {
288
+ eventDetails = e.detail;
289
+ initEventFired = true;
290
+ });
291
+
292
+ el.updateSideMenu('foo', 'open');
293
+ expect(initEventFired).toEqual(true);
294
+ expect(eventDetails.menuId).toEqual('foo');
295
+ expect(eventDetails.action).toEqual('open');
296
+ });
297
+ test('Will Not Emit `@updateSideMenu` if menu ID is missing', async() => {
298
+ const el = fixtureSync(container());
299
+ const brStub = {
300
+ resize: sinon.fake(),
301
+ currentIndex: sinon.fake(),
302
+ jumpToIndex: sinon.fake(),
303
+ options: { enableMultipleBooks: true },
304
+ refs: {},
305
+ };
306
+ el.bookreader = brStub;
307
+ await elementUpdated(el);
308
+
309
+ let initEventFired = false;
310
+ el.addEventListener('updateSideMenu', (e) => {
311
+ initEventFired = true;
312
+ });
313
+
314
+ el.updateSideMenu('', 'open');
315
+ expect(initEventFired).toEqual(false);
316
+ });
317
+ });
318
+ });
319
+
320
+ describe('Shortcuts', () => {
321
+ test('has specific order of menu shortcuts to show', () => {
322
+ const el = fixtureSync(container());
323
+ expect(el.shortcutOrder[0]).toEqual('fullscreen');
324
+ expect(el.shortcutOrder[1]).toEqual('volumes');
325
+ expect(el.shortcutOrder[2]).toEqual('search');
326
+ expect(el.shortcutOrder[3]).toEqual('bookmarks');
327
+ });
328
+ });
329
+
330
+ describe('Behaviors for specific menus', () => {
331
+ describe('Search menu - ref: plugin.search.js', () => {
332
+ test('Event: listens for `BookReader:ToggleSearchMenu to open search side panel', async () => {
333
+ const el = fixtureSync(container());
334
+ const brStub = {
335
+ resize: sinon.fake(),
336
+ currentIndex: sinon.fake(),
337
+ jumpToIndex: sinon.fake(),
338
+ options: { enableMultipleBooks: true },
339
+ refs: {},
340
+ };
341
+ el.bookreader = brStub;
342
+ await elementUpdated(el);
343
+
344
+ let sidePanelConfig = {};
345
+ el.addEventListener('updateSideMenu', (e) => {
346
+ console.log();
347
+ sidePanelConfig = e.detail;
348
+ });
349
+ const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
350
+ window.dispatchEvent(toggleSearchMenuEvent);
351
+
352
+ await elementUpdated(el);
353
+ expect(sidePanelConfig.menuId).toEqual('search');
354
+ expect(sidePanelConfig.action).toEqual('toggle');
355
+ });
356
+ });
357
+ });
358
+ });
359
+ });
360
+
361
+ describe('Resizing',() => {
362
+ test('keeps track of `brWidth` and `brHeight`', async () => {
363
+ const el = fixtureSync(container());
364
+ const brStub = {
365
+ resize: sinon.fake(),
366
+ options: {},
367
+ refs: {
368
+ $brContainer: document.createElement('div')
369
+ }
370
+ };
371
+ el.bookreader = brStub;
372
+ await elementUpdated(el);
373
+ expect(el.brWidth).toEqual(0);
374
+ expect(el.brHeight).toEqual(0);
375
+
376
+ const mockResizeEvent = {
377
+ contentRect: {
378
+ height: 500,
379
+ width: 900
380
+ },
381
+ target: el.mainBRContainer
382
+ };
383
+ el.handleResize(mockResizeEvent);
384
+
385
+ await elementUpdated(el);
386
+ await promise0();
387
+
388
+ expect(el.brHeight).toEqual(500);
389
+ expect(el.brWidth).toEqual(900);
390
+ });
391
+ test('resizes if height/width changes && is not animating', async () => {
392
+ const el = fixtureSync(container());
393
+ const brStub = {
394
+ animating: false,
395
+ resize: sinon.fake(),
396
+ options: {},
397
+ refs: {
398
+ $brContainer: document.createElement('div')
399
+ }
400
+ };
401
+
402
+ el.bookreader = brStub;
403
+ await elementUpdated(el);
404
+ expect(el.brWidth).toEqual(0);
405
+ expect(el.brHeight).toEqual(0);
406
+
407
+ const mockResizeEvent = {
408
+ contentRect: {
409
+ height: 500,
410
+ width: 900
411
+ },
412
+ target: el.mainBRContainer
413
+ };
414
+ el.handleResize(mockResizeEvent);
415
+
416
+ await elementUpdated(el);
417
+ await promise0();
418
+
419
+ expect(brStub.resize.callCount).toEqual(1);
420
+ });
421
+ test('does not resize bookreader if animating', async () => {
422
+ const el = fixtureSync(container());
423
+ const brStub = {
424
+ animating: true, // <-- testing for this
425
+ resize: sinon.fake(),
426
+ currentIndex: sinon.fake(),
427
+ jumpToIndex: sinon.fake(),
428
+ options: { enableMultipleBooks: true },
429
+ refs: {},
430
+ };
431
+
432
+ el.bookreader = brStub;
433
+ await elementUpdated(el);
434
+
435
+ expect(el.bookreader.resize.callCount).toEqual(0);
436
+ expect(el.bookreader.currentIndex.callCount).toEqual(0);
437
+ expect(el.bookreader.jumpToIndex.callCount).toEqual(0);
438
+ });
439
+ });
440
+
441
+ describe('Fullscreen Management', () => {
442
+ test('needs option: `enableFSLogoShortcut` to use FS logo', async () => {
443
+ const el = fixtureSync(container());
444
+ const brStub = {
445
+ isFullscreen: () => true,
446
+ options: {
447
+ enableFSLogoShortcut: false,
448
+ },
449
+ refs: {},
450
+ };
451
+
452
+ el.bookreader = brStub;
453
+ el.emitMenuShortcutsUpdated = sinon.fake();
454
+ await elementUpdated(el);
455
+
456
+ el.manageFullScreenBehavior();
457
+ await elementUpdated(el);
458
+ expect(el.menuShortcuts.length).toEqual(0);
459
+ });
460
+ test('sets fullscreen shortcut when entering Fullscreen', async () => {
461
+ const el = fixtureSync(container());
462
+ const brStub = {
463
+ isFullscreen: () => true,
464
+ options: {
465
+ enableFSLogoShortcut: true,
466
+ },
467
+ refs: {},
468
+ };
469
+
470
+ el.bookreader = brStub;
471
+ el.emitMenuShortcutsUpdated = sinon.fake();
472
+ await elementUpdated(el);
473
+
474
+ el.manageFullScreenBehavior();
475
+ await elementUpdated(el);
476
+ expect(el.menuShortcuts.length).toEqual(1);
477
+ expect(el.menuShortcuts[0].id).toEqual('fullscreen');
478
+ expect(el.menuShortcuts[0].icon).toBeDefined();
479
+ expect(el.emitMenuShortcutsUpdated.callCount).toEqual(1);
480
+ });
481
+ test('clicking Fullscreen shortcut closes fullscreen', async () => {
482
+ const el = fixtureSync(container());
483
+ const brStub = {
484
+ isFullscreen: () => true,
485
+ options: {
486
+ enableFSLogoShortcut: true,
487
+ },
488
+ refs: {},
489
+ };
490
+
491
+ el.bookreader = brStub;
492
+ el.emitMenuShortcutsUpdated = sinon.fake();
493
+ el.closeFullscreen = sinon.fake();
494
+ await elementUpdated(el);
495
+
496
+ el.manageFullScreenBehavior();
497
+ await elementUpdated(el);
498
+
499
+ fixtureSync(el.menuShortcuts[0].icon).click();
500
+ await elementUpdated(el);
501
+
502
+ expect(el.closeFullscreen.callCount).toEqual(1);
503
+ });
504
+ test('removes Fullscreen shortcut when leaving fullscreen', async() => {
505
+ const el = fixtureSync(container());
506
+ const brStub = {
507
+ isFullscreen: () => false,
508
+ options: {
509
+ enableFSLogoShortcut: true,
510
+ },
511
+ refs: {},
512
+ };
513
+
514
+ el.bookreader = brStub;
515
+ el.emitMenuShortcutsUpdated = sinon.fake();
516
+ await elementUpdated(el);
517
+
518
+ el.manageFullScreenBehavior();
519
+ await elementUpdated(el);
520
+ expect(el.menuShortcuts.length).toEqual(0);
521
+ expect(el.emitMenuShortcutsUpdated.callCount).toEqual(1);
522
+ });
523
+ test('Event: Listens for `BookReader:FullscreenToggled', async() => {
524
+ const el = fixtureSync(container());
525
+ const brStub = {
526
+ isFullscreen: () => true,
527
+ resize: sinon.fake(),
528
+ currentIndex: sinon.fake(),
529
+ jumpToIndex: sinon.fake(),
530
+ options: {
531
+ enableFSLogoShortcut: true,
532
+ },
533
+ refs: {},
534
+ };
535
+ el.bookreader = brStub;
536
+ el.manageFullScreenBehavior = sinon.fake();
537
+ await elementUpdated(el);
538
+
539
+ window.dispatchEvent(new CustomEvent('BookReader:fullscreenToggled', {
540
+ detail: { props: brStub }
541
+ }));
542
+ await elementUpdated(el);
543
+
544
+ expect(el.manageFullScreenBehavior.callCount).toEqual(1);
545
+ });
546
+ });
547
+ describe('Handles Restricted Books', () => {
548
+ describe('contextMenu is prevented when book is restricted', () => {
549
+ it('watches on `div.BRscreen`', async () => {
550
+ const el = fixtureSync(container());
551
+ const brStub = {
552
+ options: { restricted: true },
553
+ };
554
+
555
+ el.bookreader = brStub;
556
+ el.bookIsRestricted = true;
557
+
558
+ const elSpy = sinon.spy(el.manageContextMenuVisibility);
559
+ await el.elementUpdated;
560
+
561
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
562
+ expect(window.archive_analytics.send_event.called).toEqual(false);
563
+ expect(elSpy.called).toEqual(false);
564
+
565
+ const body = document.querySelector('body');
566
+
567
+ const divBRscreen = document.createElement('div');
568
+ divBRscreen.classList.add('BRscreen');
569
+ body.appendChild(divBRscreen);
570
+
571
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
572
+
573
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
574
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
575
+ expect(preventDefaultSpy.called).toEqual(false);
576
+
577
+ divBRscreen.dispatchEvent(contextMenuEvent);
578
+
579
+ // analytics fires
580
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
581
+ false
582
+ );
583
+ expect(window.archive_analytics.send_event.called).toEqual(true);
584
+ // we prevent default
585
+ expect(preventDefaultSpy.called).toEqual(true);
586
+ });
587
+ it('watches on `img.BRpageimage`', async () => {
588
+ const el = fixtureSync(container());
589
+ const brStub = {
590
+ options: { restricted: true },
591
+ };
592
+
593
+ el.bookreader = brStub;
594
+ el.bookIsRestricted = true;
595
+
596
+ await el.elementUpdated;
597
+
598
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
599
+ expect(window.archive_analytics.send_event.called).toEqual(false);
600
+
601
+ const body = document.querySelector('body');
602
+ // const element stub for img.BRpageimage
603
+ const imgBRpageimage = document.createElement('img');
604
+ imgBRpageimage.classList.add('BRpageimage');
605
+ body.appendChild(imgBRpageimage);
606
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
607
+
608
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
609
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
610
+ expect(preventDefaultSpy.called).toEqual(false);
611
+
612
+ imgBRpageimage.dispatchEvent(contextMenuEvent);
613
+
614
+ // analytics fires
615
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
616
+ expect(window.archive_analytics.send_event.called).toEqual(true);
617
+ // we prevent default
618
+ expect(preventDefaultSpy.called).toEqual(true);
619
+ });
620
+ });
621
+ it('Allows unrestricted books access to context menu', async () => {
622
+ const el = fixtureSync(container());
623
+ const brStub = {
624
+ options: { restricted: false },
625
+ };
626
+
627
+ el.bookreader = brStub;
628
+ el.bookIsRestricted = false;
629
+
630
+ await el.elementUpdated;
631
+
632
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
633
+ false
634
+ );
635
+ expect(window.archive_analytics.send_event.called).toEqual(false);
636
+
637
+
638
+ const body = document.querySelector('body');
639
+ // const element stub for img.BRpageimage
640
+ const imgBRpageimage = document.createElement('img');
641
+ imgBRpageimage.classList.add('not-targeted-element');
642
+ body.appendChild(imgBRpageimage);
643
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
644
+
645
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
646
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
647
+ expect(preventDefaultSpy.called).toEqual(false);
648
+
649
+ imgBRpageimage.dispatchEvent(contextMenuEvent);
650
+
651
+ // analytics fires
652
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
653
+ expect(window.archive_analytics.send_event.called).toEqual(true);
654
+ // we do not prevent default
655
+ expect(preventDefaultSpy.called).toEqual(false);
656
+ });
657
+ });
658
+ });
@@ -0,0 +1,43 @@
1
+ import {
2
+ html,
3
+ fixtureSync,
4
+ fixtureCleanup,
5
+ } from '@open-wc/testing-helpers';
6
+ import '@/src/BookNavigator/bookmarks/bookmark-button.js';
7
+ import sinon from 'sinon';
8
+
9
+ afterEach(() => {
10
+ sinon.restore();
11
+ fixtureCleanup();
12
+ });
13
+
14
+ describe('<bookmark-button>', () => {
15
+ test('sets default properties', async () => {
16
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
17
+
18
+ expect(el.side).toBeUndefined();
19
+ expect(el.state).toEqual('hollow');
20
+ });
21
+ test('Event: fires `@bookmarkButtonClicked on click', async () => {
22
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
23
+ let buttonClicked = false;
24
+ el.addEventListener('bookmarkButtonClicked', () => { buttonClicked = true; });
25
+ const eventStub = { preventDefault: sinon.fake()};
26
+ el.handleClick(eventStub);
27
+ await el.updateComplete;
28
+
29
+ expect(buttonClicked).toBeTruthy();
30
+ expect(eventStub.preventDefault.callCount).toEqual(1);
31
+ });
32
+ test('Title: Toggles title between `Add/Remove bookmark`', async () => {
33
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
34
+ expect(el.title).toEqual('Add bookmark');
35
+ expect(el.state).toEqual('hollow');
36
+
37
+ el.state = 'filled';
38
+ await el.updateComplete;
39
+
40
+ expect(el.title).toEqual('Remove bookmark');
41
+ expect(el.state).not.toEqual('hollow');
42
+ });
43
+ });