@internetarchive/bookreader 5.0.0-26 → 5.0.0-29

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 (236) hide show
  1. package/.husky/_/husky.sh +30 -0
  2. package/BookReader/BookReader.css +1 -1
  3. package/BookReader/BookReader.js +1 -1
  4. package/BookReader/BookReader.js.map +1 -1
  5. package/BookReader/bookreader-component-bundle.js +570 -542
  6. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +23 -0
  7. package/BookReader/bookreader-component-bundle.js.map +1 -1
  8. package/BookReader/plugins/plugin.search.js +1 -1
  9. package/BookReader/plugins/plugin.search.js.map +1 -1
  10. package/BookReader/plugins/plugin.tts.js.map +1 -1
  11. package/BookReader/plugins/plugin.url.js +1 -1
  12. package/BookReader/plugins/plugin.url.js.map +1 -1
  13. package/BookReaderDemo/BookReaderDemo.css +14 -1
  14. package/BookReaderDemo/IADemoBr.js +104 -0
  15. package/BookReaderDemo/demo-internetarchive.html +65 -98
  16. package/CHANGELOG.md +10 -0
  17. package/package.json +9 -6
  18. package/src/BookNavigator/assets/ia-logo.js +17 -0
  19. package/src/BookNavigator/book-navigator.js +521 -0
  20. package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
  21. package/src/BookNavigator/bookmarks/bookmarks-provider.js +20 -8
  22. package/src/BookNavigator/bookmarks/ia-bookmarks.js +84 -51
  23. package/src/BookNavigator/downloads/downloads-provider.js +5 -9
  24. package/src/BookNavigator/downloads/downloads.js +1 -0
  25. package/src/BookNavigator/search/search-provider.js +15 -8
  26. package/src/BookNavigator/sharing.js +27 -0
  27. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +9 -8
  28. package/src/BookNavigator/volumes/volumes-provider.js +44 -13
  29. package/src/BookNavigator/volumes/volumes.js +14 -3
  30. package/src/BookReader/options.js +6 -0
  31. package/src/BookReader.js +20 -8
  32. package/src/BookReaderComponent/BookReaderComponent.js +53 -32
  33. package/src/css/_BRComponent.scss +1 -1
  34. package/src/plugins/search/plugin.search.js +10 -9
  35. package/src/plugins/tts/FestivalTTSEngine.js +1 -1
  36. package/src/plugins/url/UrlPlugin.js +184 -0
  37. package/src/plugins/url/plugin.url.js +220 -0
  38. package/{src → stat}/BookNavigator/BookModel.js +0 -0
  39. package/{src → stat}/BookNavigator/BookNavigator.js +109 -102
  40. package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
  41. package/stat/BookNavigator/assets/button-base.js +61 -0
  42. package/stat/BookNavigator/assets/ia-logo.js +17 -0
  43. package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
  44. package/stat/BookNavigator/assets/icon_close.js +3 -0
  45. package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
  46. package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
  47. package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
  48. package/stat/BookNavigator/assets/icon_volumes.js +11 -0
  49. package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
  50. package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
  51. package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
  52. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
  53. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
  54. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
  55. package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
  56. package/stat/BookNavigator/delete-modal-actions.js +49 -0
  57. package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
  58. package/stat/BookNavigator/downloads/downloads.js +139 -0
  59. package/stat/BookNavigator/provider-config.js +0 -0
  60. package/stat/BookNavigator/search/a-search-result.js +55 -0
  61. package/stat/BookNavigator/search/search-provider.js +180 -0
  62. package/stat/BookNavigator/search/search-results.js +360 -0
  63. package/{src/ItemNavigator/providers → stat/BookNavigator}/sharing.js +3 -5
  64. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
  65. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
  66. package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
  67. package/stat/BookNavigator/volumes/volumes.js +178 -0
  68. package/stat/BookReader/BookModel.js +518 -0
  69. package/stat/BookReader/DebugConsole.js +54 -0
  70. package/stat/BookReader/DragScrollable.js +233 -0
  71. package/stat/BookReader/ImageCache.js +116 -0
  72. package/stat/BookReader/Mode1Up.js +102 -0
  73. package/stat/BookReader/Mode1UpLit.js +434 -0
  74. package/stat/BookReader/Mode2Up.js +1372 -0
  75. package/stat/BookReader/ModeSmoothZoom.js +177 -0
  76. package/stat/BookReader/ModeThumb.js +344 -0
  77. package/stat/BookReader/Navbar/Navbar.js +310 -0
  78. package/stat/BookReader/PageContainer.js +120 -0
  79. package/stat/BookReader/ReduceSet.js +26 -0
  80. package/stat/BookReader/Toolbar/Toolbar.js +384 -0
  81. package/stat/BookReader/events.js +20 -0
  82. package/stat/BookReader/options.js +324 -0
  83. package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  84. package/stat/BookReader/utils/classes.js +36 -0
  85. package/stat/BookReader/utils.js +240 -0
  86. package/stat/BookReader.js +2550 -0
  87. package/stat/BookReaderComponent/BookReaderComponent.js +117 -0
  88. package/stat/assets/icons/1up.svg +12 -0
  89. package/stat/assets/icons/2up.svg +15 -0
  90. package/stat/assets/icons/advance.svg +26 -0
  91. package/stat/assets/icons/chevron-right.svg +1 -0
  92. package/stat/assets/icons/close-circle-dark.svg +1 -0
  93. package/stat/assets/icons/close-circle.svg +1 -0
  94. package/stat/assets/icons/fullscreen.svg +17 -0
  95. package/stat/assets/icons/fullscreen_exit.svg +17 -0
  96. package/stat/assets/icons/hamburger.svg +15 -0
  97. package/stat/assets/icons/left-arrow.svg +12 -0
  98. package/stat/assets/icons/magnify-minus.svg +16 -0
  99. package/stat/assets/icons/magnify-plus.svg +17 -0
  100. package/stat/assets/icons/magnify.svg +15 -0
  101. package/stat/assets/icons/pause.svg +23 -0
  102. package/stat/assets/icons/play.svg +22 -0
  103. package/stat/assets/icons/playback-speed.svg +34 -0
  104. package/stat/assets/icons/read-aloud.svg +22 -0
  105. package/stat/assets/icons/review.svg +22 -0
  106. package/stat/assets/icons/thumbnails.svg +17 -0
  107. package/stat/assets/icons/voice.svg +1 -0
  108. package/stat/assets/icons/volume-full.svg +22 -0
  109. package/stat/assets/images/BRicons.png +0 -0
  110. package/stat/assets/images/BRicons.svg +94 -0
  111. package/stat/assets/images/BRicons_ia.png +0 -0
  112. package/stat/assets/images/back_pages.png +0 -0
  113. package/stat/assets/images/book_bottom_icon.png +0 -0
  114. package/stat/assets/images/book_down_icon.png +0 -0
  115. package/stat/assets/images/book_left_icon.png +0 -0
  116. package/stat/assets/images/book_leftmost_icon.png +0 -0
  117. package/stat/assets/images/book_right_icon.png +0 -0
  118. package/stat/assets/images/book_rightmost_icon.png +0 -0
  119. package/stat/assets/images/book_top_icon.png +0 -0
  120. package/stat/assets/images/book_up_icon.png +0 -0
  121. package/stat/assets/images/books_graphic.svg +177 -0
  122. package/stat/assets/images/booksplit.png +0 -0
  123. package/stat/assets/images/control_pause_icon.png +0 -0
  124. package/stat/assets/images/control_play_icon.png +0 -0
  125. package/stat/assets/images/embed_icon.png +0 -0
  126. package/stat/assets/images/icon-home-ia.png +0 -0
  127. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  128. package/stat/assets/images/icon_alert-xs.png +0 -0
  129. package/stat/assets/images/icon_book.svg +12 -0
  130. package/stat/assets/images/icon_bookmark.svg +12 -0
  131. package/stat/assets/images/icon_close-pop.png +0 -0
  132. package/stat/assets/images/icon_download.png +0 -0
  133. package/stat/assets/images/icon_gear.svg +14 -0
  134. package/stat/assets/images/icon_hamburger.svg +20 -0
  135. package/stat/assets/images/icon_home.png +0 -0
  136. package/stat/assets/images/icon_home.svg +21 -0
  137. package/stat/assets/images/icon_home_ia.png +0 -0
  138. package/stat/assets/images/icon_indicator.png +0 -0
  139. package/stat/assets/images/icon_info.svg +11 -0
  140. package/stat/assets/images/icon_one_page.svg +8 -0
  141. package/stat/assets/images/icon_pause.svg +1 -0
  142. package/stat/assets/images/icon_play.svg +1 -0
  143. package/stat/assets/images/icon_playback-rate.svg +15 -0
  144. package/stat/assets/images/icon_return.png +0 -0
  145. package/stat/assets/images/icon_search_button.svg +8 -0
  146. package/stat/assets/images/icon_share.svg +9 -0
  147. package/stat/assets/images/icon_skip-ahead.svg +6 -0
  148. package/stat/assets/images/icon_skip-back.svg +13 -0
  149. package/stat/assets/images/icon_speaker.svg +18 -0
  150. package/stat/assets/images/icon_speaker_open.svg +10 -0
  151. package/stat/assets/images/icon_thumbnails.svg +12 -0
  152. package/stat/assets/images/icon_toc.svg +5 -0
  153. package/stat/assets/images/icon_two_pages.svg +9 -0
  154. package/stat/assets/images/icon_zoomer.png +0 -0
  155. package/stat/assets/images/loading.gif +0 -0
  156. package/stat/assets/images/logo_icon.png +0 -0
  157. package/stat/assets/images/marker_chap-off.png +0 -0
  158. package/stat/assets/images/marker_chap-off.svg +11 -0
  159. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  160. package/stat/assets/images/marker_chap-on.png +0 -0
  161. package/stat/assets/images/marker_chap-on.svg +11 -0
  162. package/stat/assets/images/marker_srch-on.svg +11 -0
  163. package/stat/assets/images/marker_srchchap-off.png +0 -0
  164. package/stat/assets/images/marker_srchchap-on.png +0 -0
  165. package/stat/assets/images/nav_control-dn.png +0 -0
  166. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  167. package/stat/assets/images/nav_control-up.png +0 -0
  168. package/stat/assets/images/nav_control-up_ia.png +0 -0
  169. package/stat/assets/images/nav_control.png +0 -0
  170. package/stat/assets/images/one_page_mode_icon.png +0 -0
  171. package/stat/assets/images/paper-badge.png +0 -0
  172. package/stat/assets/images/print_icon.png +0 -0
  173. package/stat/assets/images/progressbar.gif +0 -0
  174. package/stat/assets/images/right_edges.png +0 -0
  175. package/stat/assets/images/slider.png +0 -0
  176. package/stat/assets/images/slider_ia.png +0 -0
  177. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  178. package/stat/assets/images/transparent.png +0 -0
  179. package/stat/assets/images/two_page_mode_icon.png +0 -0
  180. package/stat/assets/images/zoom_in_icon.png +0 -0
  181. package/stat/assets/images/zoom_out_icon.png +0 -0
  182. package/stat/css/BookReader.scss +89 -0
  183. package/stat/css/_BRBookmarks.scss +29 -0
  184. package/stat/css/_BRComponent.scss +13 -0
  185. package/stat/css/_BRfloat.scss +197 -0
  186. package/stat/css/_BRicon.scss +48 -0
  187. package/stat/css/_BRmain.scss +251 -0
  188. package/stat/css/_BRnav.scss +359 -0
  189. package/stat/css/_BRpages.scss +139 -0
  190. package/stat/css/_BRsearch.scss +226 -0
  191. package/stat/css/_BRtoolbar.scss +84 -0
  192. package/stat/css/_BRvendor.scss +5 -0
  193. package/stat/css/_MobileNav.scss +194 -0
  194. package/stat/css/_TextSelection.scss +32 -0
  195. package/stat/css/_colorbox.scss +52 -0
  196. package/stat/css/_controls.scss +253 -0
  197. package/stat/css/_icons.scss +121 -0
  198. package/stat/jquery-wrapper.js +4 -0
  199. package/stat/plugins/plugin.archive_analytics.js +86 -0
  200. package/stat/plugins/plugin.autoplay.js +129 -0
  201. package/stat/plugins/plugin.chapters.js +248 -0
  202. package/stat/plugins/plugin.iframe.js +48 -0
  203. package/stat/plugins/plugin.mobile_nav.js +288 -0
  204. package/stat/plugins/plugin.resume.js +68 -0
  205. package/stat/plugins/plugin.text_selection.js +291 -0
  206. package/{src → stat}/plugins/plugin.url.js +0 -0
  207. package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
  208. package/stat/plugins/search/plugin.search.js +439 -0
  209. package/stat/plugins/search/view.js +439 -0
  210. package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
  211. package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
  212. package/stat/plugins/tts/PageChunk.js +107 -0
  213. package/stat/plugins/tts/PageChunkIterator.js +163 -0
  214. package/stat/plugins/tts/WebTTSEngine.js +357 -0
  215. package/stat/plugins/tts/plugin.tts.js +357 -0
  216. package/stat/plugins/tts/tooltip_dict.js +15 -0
  217. package/stat/plugins/tts/utils.js +91 -0
  218. package/stat/util/browserSniffing.js +30 -0
  219. package/stat/util/debouncer.js +26 -0
  220. package/stat/util/docCookies.js +67 -0
  221. package/stat/util/strings.js +34 -0
  222. package/tests/e2e/viewmode.test.js +30 -30
  223. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +64 -52
  224. package/tests/jest/BookReader.test.js +1 -1
  225. package/tests/jest/plugins/url/UrlPlugin.test.js +175 -0
  226. package/tests/jest/plugins/{plugin.url.test.js → url/plugin.url.test.js} +3 -2
  227. package/tests/karma/BookNavigator/book-navigator.test.js +413 -108
  228. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  229. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +6 -3
  230. package/tests/karma/BookNavigator/search/search-provider.test.js +106 -6
  231. package/tests/karma/BookNavigator/search/search-results.test.js +0 -2
  232. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +29 -20
  233. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +46 -22
  234. package/webpack.config.js +1 -1
  235. package/src/BookNavigator/assets/book-loader.js +0 -27
  236. package/src/ItemNavigator/ItemNavigator.js +0 -377
@@ -6,175 +6,480 @@ import {
6
6
  expect,
7
7
  } from '@open-wc/testing';
8
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';
9
17
 
10
- import '../../../src/BookNavigator/BookNavigator.js';
11
- import BRFullscreenMgr from '../../../src/BookNavigator/br-fullscreen-mgr.js';
18
+ const promise0 = () => new Promise(res => setTimeout(res, 0));
12
19
 
13
- const container = () => {
14
- const item = {};
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();
15
29
  return html`
16
30
  <book-navigator
17
- .item=${item}
18
- .baseHost
31
+ .itemMD=${itemStub}
32
+ .baseHost=${`https://foo.archive.org`}
33
+ .sharedObserver=${sharedObserver || new SharedResizeObserver()}
34
+ .modal=${modalMgr}
19
35
  >
20
- <div slot="bookreader">
36
+ <div slot="theater-main">
37
+ <div id="BookReader"></div>
21
38
  <p class="visible-in-reader">now showing</p>
22
- <div>
23
- <p class="bunny">foo</p>
24
- </
39
+ <\div>
40
+ </book-navigator>
25
41
  `;
26
42
  };
27
43
 
28
- beforeEach(() => {
29
- const body = document.querySelector('body');
30
- const brHook = document.createElement('div');
31
- brHook.setAttribute('id', 'BookReader');
32
- body.appendChild(brHook);
33
- });
34
-
35
44
  afterEach(() => {
36
45
  window.br = null;
37
46
  fixtureCleanup();
47
+ const body = document.querySelector('body');
48
+ body.innerHTML = '';
49
+ sinon.restore();
38
50
  });
39
51
 
40
52
 
41
53
  describe('<book-navigator>', () => {
42
- describe('first update', () => {
43
- it('binds global event listeners', async () => {
44
- const el = fixtureSync(container());
45
- const spy = sinon.spy(el, 'bindEventListeners');
46
- await elementUpdated(el);
47
- expect(spy.callCount).to.equal(1);
48
- });
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();
49
94
 
50
- it('emits a BrBookNav:PostInit event', async () => {
95
+ expect(brStub.resize.callCount > 0).to.be.true;
96
+ });
97
+ });
98
+ it('Emits a BrBookNav:PostInit event at completion', async () => {
51
99
  let initEventFired = false;
52
100
  window.addEventListener('BrBookNav:PostInit', (e) => {
53
101
  initEventFired = true;
54
102
  });
55
103
  const el = fixtureSync(container());
56
104
  const spy = sinon.spy(el, 'emitPostInit');
105
+
57
106
  await elementUpdated(el);
58
107
 
59
108
  expect(initEventFired).to.be.true;
60
109
  expect(spy.callCount).to.equal(1);
61
110
  });
62
- });
63
111
 
64
- it('handles global event: BookReader:PostInit', async () => {
65
- const setTimeoutSpy = sinon.spy(window, 'setTimeout');
66
- const brStub = {
67
- resize: sinon.fake(),
68
- currentIndex: sinon.fake(),
69
- jumpToIndex: sinon.fake(),
70
- options: { enableMultipleBooks: false }, // for multipleBooks
71
- el: '#BookReader'
72
- };
73
-
74
- const el = fixtureSync(container());
75
- const initializeBookSubmenus = sinon.spy(el, 'initializeBookSubmenus');
76
-
77
- await elementUpdated(el);
78
- window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
79
- detail: { props: brStub }
80
- }));
81
- await elementUpdated(el);
82
-
83
- expect(initializeBookSubmenus.callCount).to.equal(1);
84
- expect(el.bookreader).to.equal(brStub); // sets bookreader
85
- expect(el.bookReaderLoaded).to.be.true; // notes bookreader is loaded
86
- expect(el.bookReaderCannotLoad).to.be.false;
87
- expect(el.fullscreenMgr).to.an.instanceof(BRFullscreenMgr);
88
- expect(el.brResizeObserver).to.an.instanceof(window.ResizeObserver);
89
- expect(setTimeoutSpy.callCount).to.equal(1); // resizes at end
112
+ it('creates an item image from metadata', async () => {
113
+ const el = fixtureSync(container());
114
+ el.item = {
115
+ metadata: { identifier: 'foo' },
116
+ };
117
+ await elementUpdated(el);
118
+
119
+ const itemImage = fixtureSync(el.itemImage);
120
+ expect(itemImage).to.be.instanceOf(HTMLImageElement);
121
+ expect(itemImage.getAttribute('class')).to.equal('cover-img');
122
+ expect(itemImage.getAttribute('src')).to.equal('https://https://foo.archive.org/services/img/foo');
123
+ });
90
124
  });
125
+ describe('Menu/Layer Provider', () => {
126
+ describe('Connecting with a provider:', () => {
127
+ // loads Providers with base shared resources
128
+ it('We load 3 Sub Menus by default', async() => {
129
+ const el = fixtureSync(container());
130
+ const $brContainer = document.createElement('div');
131
+ const brStub = {
132
+ resize: sinon.fake(),
133
+ currentIndex: sinon.fake(),
134
+ jumpToIndex: sinon.fake(),
135
+ options: {},
136
+ refs: {
137
+ $brContainer
138
+ }
139
+ };
140
+ el.bookreader = brStub;
141
+ await el.elementUpdated;
142
+
143
+ el.initializeBookSubmenus();
144
+ await el.elementUpdated;
145
+ const defaultMenus = Object.keys(el.menuProviders);
146
+ expect(defaultMenus).to.contain('downloads');
147
+ expect(el.menuProviders.downloads).to.be.instanceOf(DownloadsProvider);
91
148
 
92
- it('resizes bookreader when side menu toggles', async () => {
93
- const el = fixtureSync(container());
94
- const brStub = {
95
- resize: sinon.fake(),
96
- currentIndex: sinon.fake(),
97
- jumpToIndex: sinon.fake(),
98
- options: { enableMultipleBooks: true },
99
- };
149
+ expect(defaultMenus).to.contain('share');
150
+ expect(el.menuProviders.share).to.be.instanceOf(SharingProvider);
100
151
 
101
- el.bookreader = brStub;
102
- await elementUpdated(el);
152
+ expect(defaultMenus).to.contain('visualAdjustments');
153
+ expect(el.menuProviders.visualAdjustments).to.be.instanceOf(VisualAdjustmentsProvider);
154
+ });
155
+ describe('Loading Sub Menus By Plugin Flags', async() => {
156
+ it('Search: uses `enableSearch` flag', async() => {
157
+ const el = fixtureSync(container());
158
+ const $brContainer = document.createElement('div');
159
+ const brStub = {
160
+ resize: sinon.fake(),
161
+ currentIndex: sinon.fake(),
162
+ jumpToIndex: sinon.fake(),
163
+ options: { enableSearch: true },
164
+ refs: {
165
+ $brContainer
166
+ }
167
+ };
168
+ el.bookreader = brStub;
169
+ await el.elementUpdated;
103
170
 
104
- el.sideMenuOpen = true;
105
- await elementUpdated(el);
171
+ el.initializeBookSubmenus();
172
+ await el.elementUpdated;
106
173
 
107
- expect(el.bookreader.resize.callCount).to.equal(1);
174
+ expect(el.menuProviders.search).to.exist;
175
+ expect(el.menuProviders.search).to.be.instanceOf(SearchProvider);
108
176
 
109
- el.sideMenuOpen = false;
110
- await elementUpdated(el);
177
+ // also adds a menu shortcut
178
+ expect(el.menuShortcuts.find(m => m.id === 'search')).to.exist;
179
+ });
180
+ it('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
181
+ const el = fixtureSync(container());
182
+ const $brContainer = document.createElement('div');
183
+ const brStub = {
184
+ resize: sinon.fake(),
185
+ currentIndex: sinon.fake(),
186
+ jumpToIndex: sinon.fake(),
187
+ options: {
188
+ enableMultipleBooks: true,
189
+ multipleBooksList: {
190
+ by_subprefix: {
191
+ fooSubprefix: 'beep'
192
+ }
193
+ }
194
+ },
195
+ refs: {
196
+ $brContainer
197
+ }
198
+ };
199
+ el.bookreader = brStub;
200
+ await el.elementUpdated;
111
201
 
112
- expect(el.bookreader.resize.callCount).to.equal(2);
113
- });
202
+ el.initializeBookSubmenus();
203
+ await el.elementUpdated;
114
204
 
115
- it('does not resize bookreader if animating', async () => {
116
- const el = fixtureSync(container());
117
- const brStub = {
118
- animating: true, // <-- testing for this
119
- resize: sinon.fake(),
120
- currentIndex: sinon.fake(),
121
- jumpToIndex: sinon.fake(),
122
- options: { enableMultipleBooks: true }
123
- };
124
-
125
- el.bookreader = brStub;
126
- await elementUpdated(el);
127
-
128
- el.sideMenuOpen = true;
129
- await elementUpdated(el);
130
-
131
- expect(el.bookreader.resize.callCount).to.equal(0);
132
- expect(el.bookreader.currentIndex.callCount).to.equal(0);
133
- expect(el.bookreader.jumpToIndex.callCount).to.equal(0);
205
+ expect(el.menuProviders.volumes).to.exist;
206
+ expect(el.menuProviders.volumes).to.be.instanceOf(VolumesProvider);
207
+
208
+ // also adds a menu shortcut
209
+ expect(el.menuShortcuts.find(m => m.id === 'volumes')).to.be.exist;
210
+ });
211
+ });
212
+ it('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
213
+ const el = fixtureSync(container());
214
+ const baseConfigKeys = Object.keys(el.baseProviderConfig);
215
+ expect(baseConfigKeys).to.contain('baseHost');
216
+ expect(baseConfigKeys).to.contain('modal');
217
+ expect(baseConfigKeys).to.contain('sharedObserver');
218
+ expect(baseConfigKeys).to.contain('bookreader');
219
+ expect(baseConfigKeys).to.contain('item');
220
+ expect(baseConfigKeys).to.contain('signedIn');
221
+ expect(baseConfigKeys).to.contain('isAdmin');
222
+ expect(baseConfigKeys).to.contain('onProviderChange');
223
+ });
224
+ });
225
+
226
+ describe('Controlling Menu Side Panel & Shortcuts', () => {
227
+ describe('Side Menu Panels', () => {
228
+ describe('Control which side menu to toggle open by using: `this.updateSideMenu`', () => {
229
+ it('Emits `@updateSideMenu` to signal which menu gets the update', async () => {
230
+ const el = fixtureSync(container());
231
+ const brStub = {
232
+ resize: sinon.fake(),
233
+ currentIndex: sinon.fake(),
234
+ jumpToIndex: sinon.fake(),
235
+ options: { enableMultipleBooks: true }
236
+ };
237
+ el.bookreader = brStub;
238
+ await elementUpdated(el);
239
+
240
+ let initEventFired = false;
241
+ let eventDetails = {};
242
+ el.addEventListener('updateSideMenu', (e) => {
243
+ eventDetails = e.detail;
244
+ initEventFired = true;
245
+ });
246
+
247
+ el.updateSideMenu('foo', 'open');
248
+ expect(initEventFired).to.equal(true);
249
+ expect(eventDetails.menuId).to.equal('foo');
250
+ expect(eventDetails.action).to.equal('open');
251
+ });
252
+ it('Will Not Emit `@updateSideMenu` if menu ID is missing', async() => {
253
+ const el = fixtureSync(container());
254
+ const brStub = {
255
+ resize: sinon.fake(),
256
+ currentIndex: sinon.fake(),
257
+ jumpToIndex: sinon.fake(),
258
+ options: { enableMultipleBooks: true }
259
+ };
260
+ el.bookreader = brStub;
261
+ await elementUpdated(el);
262
+
263
+ let initEventFired = false;
264
+ el.addEventListener('updateSideMenu', (e) => {
265
+ initEventFired = true;
266
+ });
267
+
268
+ el.updateSideMenu('', 'open');
269
+ expect(initEventFired).to.equal(false);
270
+ });
271
+ });
272
+ });
273
+
274
+ describe('Shortcuts', () => {
275
+ it('has specific order of menu shortcuts to show', () => {
276
+ const el = fixtureSync(container());
277
+ expect(el.shortcutOrder[0]).to.equal('fullscreen');
278
+ expect(el.shortcutOrder[1]).to.equal('volumes');
279
+ expect(el.shortcutOrder[2]).to.equal('search');
280
+ expect(el.shortcutOrder[3]).to.equal('bookmarks');
281
+ });
282
+ });
283
+
284
+ describe('Behaviors for specific menus', () => {
285
+ describe('Search menu - ref: plugin.search.js', () => {
286
+ it('Event: listens for `BookReader:ToggleSearchMenu to open search side panel', async () => {
287
+ const el = fixtureSync(container());
288
+ const brStub = {
289
+ resize: sinon.fake(),
290
+ currentIndex: sinon.fake(),
291
+ jumpToIndex: sinon.fake(),
292
+ options: { enableMultipleBooks: true }
293
+ };
294
+ el.bookreader = brStub;
295
+ await elementUpdated(el);
296
+
297
+ let sidePanelConfig = {};
298
+ el.addEventListener('updateSideMenu', (e) => {
299
+ console.log();
300
+ sidePanelConfig = e.detail;
301
+ });
302
+ const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
303
+ window.dispatchEvent(toggleSearchMenuEvent);
304
+
305
+ await elementUpdated(el);
306
+ expect(sidePanelConfig.menuId).to.equal('search');
307
+ expect(sidePanelConfig.action).to.equal('toggle');
308
+ });
309
+ });
310
+ });
311
+ });
134
312
  });
135
313
 
136
- describe(`this.updateSideMenu`, () => {
137
- it('emits custom event', async () => {
314
+ describe('Resizing',() => {
315
+ it('keeps track of `brWidth` and `brHeight`', async () => {
138
316
  const el = fixtureSync(container());
139
317
  const brStub = {
140
318
  resize: sinon.fake(),
319
+ };
320
+ el.bookreader = brStub;
321
+ await elementUpdated(el);
322
+ expect(el.brWidth).to.equal(0);
323
+ expect(el.brHeight).to.equal(0);
324
+
325
+ const mockResizeEvent = {
326
+ contentRect: {
327
+ height: 500,
328
+ width: 900
329
+ },
330
+ target: el.mainBRContainer
331
+ };
332
+ el.handleResize(mockResizeEvent);
333
+
334
+ await elementUpdated(el);
335
+ await promise0();
336
+
337
+ expect(el.brHeight).to.equal(500);
338
+ expect(el.brWidth).to.equal(900);
339
+ });
340
+ it('resizes if height/width changes && is not animating', async () => {
341
+ const el = fixtureSync(container());
342
+ const brStub = {
343
+ animating: false,
344
+ resize: sinon.fake(),
345
+ };
346
+ el.bookreader = brStub;
347
+ await elementUpdated(el);
348
+ expect(el.brWidth).to.equal(0);
349
+ expect(el.brHeight).to.equal(0);
350
+
351
+ const mockResizeEvent = {
352
+ contentRect: {
353
+ height: 500,
354
+ width: 900
355
+ },
356
+ target: el.mainBRContainer
357
+ };
358
+ el.handleResize(mockResizeEvent);
359
+
360
+ await elementUpdated(el);
361
+ await promise0();
362
+
363
+ expect(brStub.resize.callCount).to.equal(1);
364
+ });
365
+ it('does not resize bookreader if animating', async () => {
366
+ const el = fixtureSync(container());
367
+ const brStub = {
368
+ animating: true, // <-- testing for this
369
+ resize: sinon.fake(),
141
370
  currentIndex: sinon.fake(),
142
371
  jumpToIndex: sinon.fake(),
143
372
  options: { enableMultipleBooks: true }
144
373
  };
374
+
145
375
  el.bookreader = brStub;
146
376
  await elementUpdated(el);
147
377
 
148
- let initEventFired = false;
149
- let eventDetails = {};
150
- el.addEventListener('updateSideMenu', (e) => {
151
- eventDetails = e.detail;
152
- initEventFired = true;
153
- });
378
+ expect(el.bookreader.resize.callCount).to.equal(0);
379
+ expect(el.bookreader.currentIndex.callCount).to.equal(0);
380
+ expect(el.bookreader.jumpToIndex.callCount).to.equal(0);
381
+ });
382
+ });
383
+
384
+ describe('Fullscreen Management', () => {
385
+ it('needs option: `enableFSLogoShortcut` to use FS logo', async () => {
386
+ const el = fixtureSync(container());
387
+ const brStub = {
388
+ isFullscreen: () => true,
389
+ options: {
390
+ enableFSLogoShortcut: false,
391
+ }
392
+ };
393
+
394
+ el.bookreader = brStub;
395
+ el.emitMenuShortcutsUpdated = sinon.fake();
396
+ await elementUpdated(el);
397
+
398
+ el.manageFullScreenBehavior();
399
+ await elementUpdated(el);
400
+ expect(el.menuShortcuts.length).to.equal(0);
401
+ });
402
+ it('sets fullscreen shortcut when entering Fullscreen', async () => {
403
+ const el = fixtureSync(container());
404
+ const brStub = {
405
+ isFullscreen: () => true,
406
+ options: {
407
+ enableFSLogoShortcut: true,
408
+ }
409
+ };
410
+
411
+ el.bookreader = brStub;
412
+ el.emitMenuShortcutsUpdated = sinon.fake();
413
+ await elementUpdated(el);
414
+
415
+ el.manageFullScreenBehavior();
416
+ await elementUpdated(el);
417
+ expect(el.menuShortcuts.length).to.equal(1);
418
+ expect(el.menuShortcuts[0].id).to.equal('fullscreen');
419
+ expect(el.menuShortcuts[0].icon).to.exist;
420
+ expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
421
+ });
422
+ it('clicking Fullscreen shortcut closes fullscreen', async () => {
423
+ const el = fixtureSync(container());
424
+ const brStub = {
425
+ isFullscreen: () => true,
426
+ options: {
427
+ enableFSLogoShortcut: true,
428
+ }
429
+ };
430
+
431
+ el.bookreader = brStub;
432
+ el.emitMenuShortcutsUpdated = sinon.fake();
433
+ el.closeFullscreen = sinon.fake();
434
+ await elementUpdated(el);
435
+
436
+ el.manageFullScreenBehavior();
437
+ await elementUpdated(el);
438
+
439
+ fixtureSync(el.menuShortcuts[0].icon).click();
440
+ await elementUpdated(el);
154
441
 
155
- el.updateSideMenu('foo', 'open');
156
- expect(initEventFired).to.equal(true);
157
- expect(eventDetails.menuId).to.equal('foo');
158
- expect(eventDetails.action).to.equal('open');
442
+ expect(el.closeFullscreen.callCount).to.equal(1);
159
443
  });
160
- it('does not emit event if missing an arg', async() => {
444
+ it('removes Fullscreen shortcut when leaving fullscreen', async() => {
161
445
  const el = fixtureSync(container());
162
446
  const brStub = {
447
+ isFullscreen: () => false,
448
+ options: {
449
+ enableFSLogoShortcut: true,
450
+ }
451
+ };
452
+
453
+ el.bookreader = brStub;
454
+ el.emitMenuShortcutsUpdated = sinon.fake();
455
+ await elementUpdated(el);
456
+
457
+ el.manageFullScreenBehavior();
458
+ await elementUpdated(el);
459
+ expect(el.menuShortcuts.length).to.equal(0);
460
+ expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
461
+ });
462
+ it('Event: Listens for `BookReader:FullscreenToggled', async() => {
463
+ const el = fixtureSync(container());
464
+ const brStub = {
465
+ isFullscreen: () => true,
163
466
  resize: sinon.fake(),
164
467
  currentIndex: sinon.fake(),
165
468
  jumpToIndex: sinon.fake(),
166
- options: { enableMultipleBooks: true }
469
+ options: {
470
+ enableFSLogoShortcut: true,
471
+ }
167
472
  };
168
473
  el.bookreader = brStub;
474
+ el.manageFullScreenBehavior = sinon.fake();
169
475
  await elementUpdated(el);
170
476
 
171
- let initEventFired = false;
172
- el.addEventListener('updateSideMenu', (e) => {
173
- initEventFired = true;
174
- });
477
+ window.dispatchEvent(new CustomEvent('BookReader:fullscreenToggled', {
478
+ detail: { props: brStub }
479
+ }));
480
+ await elementUpdated(el);
175
481
 
176
- el.updateSideMenu('', 'open');
177
- expect(initEventFired).to.equal(false);
482
+ expect(el.manageFullScreenBehavior.callCount).to.equal(1);
178
483
  });
179
484
  });
180
485
  });
@@ -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
+ });
@@ -1,4 +1,4 @@
1
- import { expect } from '@open-wc/testing';
1
+ import { expect, fixtureCleanup, fixtureSync } from '@open-wc/testing';
2
2
  import sinon from 'sinon';
3
3
  import DownloadsProvider from '../../../../src/BookNavigator/downloads/downloads-provider';
4
4
 
@@ -25,6 +25,7 @@ const downloads = [
25
25
 
26
26
  afterEach(() => {
27
27
  sinon.restore();
28
+ fixtureCleanup();
28
29
  });
29
30
 
30
31
  describe('Downloads Provider', () => {
@@ -34,6 +35,7 @@ describe('Downloads Provider', () => {
34
35
 
35
36
  expect(provider.id).to.equal('downloads');
36
37
  expect(provider.icon).to.exist;
38
+ expect(fixtureSync(provider.icon).tagName).to.equal('IA-ICON-DL');
37
39
  expect(provider.label).to.equal('Downloadable files');
38
40
  expect(provider.menuDetails).to.exist;
39
41
  expect(provider.component).to.exist;
@@ -49,8 +51,9 @@ describe('Downloads Provider', () => {
49
51
  });
50
52
 
51
53
  it('render view if book is protected', () => {
52
- const isBookProtected = true;
53
- const provider = new DownloadsProvider(isBookProtected);
54
+ const provider = new DownloadsProvider({
55
+ bookreader: { options: { isProtected: true } }
56
+ });
54
57
 
55
58
  expect(provider.isBookProtected).to.equal(true);
56
59