@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,200 @@
1
+ import {
2
+ html,
3
+ fixture,
4
+ oneEvent,
5
+ } from '@open-wc/testing-helpers';
6
+ import sinon from 'sinon';
7
+ import { IABookVisualAdjustments } from '@/src/BookNavigator/visual-adjustments/visual-adjustments.js';
8
+
9
+ const options = [{
10
+ id: 'contrast',
11
+ name: 'Adjust contrast',
12
+ active: true,
13
+ min: 0,
14
+ max: 150,
15
+ step: 1,
16
+ value: 100,
17
+ }, {
18
+ id: 'invert',
19
+ name: 'Invert colors',
20
+ active: false,
21
+ }, {
22
+ id: 'brightness',
23
+ name: 'Adjust brightness',
24
+ active: false,
25
+ value: 100,
26
+ }];
27
+
28
+ const container = (renderHeader = false) => (
29
+ html`<ia-book-visual-adjustments .options=${options} ?renderHeader=${renderHeader}></ia-book-visual-adjustments>`
30
+ );
31
+
32
+ describe('<ia-book-visual-adjustments>', () => {
33
+ afterEach(() => {
34
+ sinon.restore();
35
+ });
36
+
37
+ test('sets default properties', async () => {
38
+ const el = await fixture(container());
39
+
40
+ expect(el.options).toBeDefined();
41
+ expect(el.options.length).toEqual(options.length);
42
+ expect(el.renderHeader).toBeDefined();
43
+ expect(el.renderHeader).toBeFalsy();
44
+ expect(el.activeCount).toBeDefined();
45
+ expect(el.showZoomControls).toBeTruthy();
46
+ });
47
+
48
+ test('renders all properties of a visual adjustment option', async () => {
49
+ const el = await fixture(container());
50
+
51
+ await el.updateComplete;
52
+
53
+ const label = el.shadowRoot.querySelector('label');
54
+ const name = label.querySelector('.name');
55
+ const checkbox = label.querySelector('input');
56
+ expect(name.textContent).toEqual(options[0].name);
57
+ expect(checkbox.checked).toEqual(true);
58
+ });
59
+
60
+ test('can render header with active options count', async () => {
61
+ const renderHeader = true;
62
+ const el = await fixture(container(renderHeader));
63
+ expect(el.shadowRoot.querySelector('header p').textContent).toContain('1');
64
+ });
65
+
66
+ test('does not render active options count element when none are selected', async () => {
67
+ const el = await fixture(container());
68
+
69
+ el.options = [options[1]];
70
+ await el.updateComplete;
71
+
72
+ expect(el.shadowRoot.querySelector('header p')).toBe(null);
73
+ });
74
+
75
+ test('changes option\'s active state when input changed', async () => {
76
+ const el = await fixture(container());
77
+
78
+ el.shadowRoot.querySelector('li input').dispatchEvent(new Event('change'));
79
+ await el.updateComplete;
80
+
81
+ expect(el.options[0].active).toEqual(false);
82
+ });
83
+
84
+ test('renders zoom in and out controls when enabled', async () => {
85
+ const el = await fixture(container());
86
+
87
+ expect(el.shadowRoot.querySelector('.zoom_out')).toBeDefined();
88
+ expect(el.shadowRoot.querySelector('.zoom_in')).toBeDefined();
89
+ });
90
+
91
+ test('does not render zoom controls when disabled', async () => {
92
+ const el = await fixture(container());
93
+
94
+ el.showZoomControls = false;
95
+ await el.updateComplete;
96
+
97
+ expect(el.shadowRoot.querySelector('.zoom_out')).toBe(null);
98
+ expect(el.shadowRoot.querySelector('.zoom_in')).toBe(null);
99
+ });
100
+
101
+ describe('Custom events', () => {
102
+ test('prepareEventDetails returns proper params', async () => {
103
+ const el = await fixture(container());
104
+ await el.updateComplete;
105
+ const params = el.prepareEventDetails();
106
+
107
+ expect(params.activeCount).toBeDefined();
108
+ expect(typeof (params.activeCount)).toEqual('number');
109
+ expect(params.changedOptionId).toBeDefined();
110
+ expect(typeof (params.changedOptionId)).toEqual('string');
111
+ expect(params.options).toBeDefined();
112
+ expect(params.options.length).toBeDefined();
113
+ expect(params.options.length).toBeGreaterThan(0);
114
+ });
115
+ test('emitOptionChangedEvent calls for the params', async () => {
116
+ IABookVisualAdjustments.prototype.prepareEventDetails = sinon.fake();
117
+ const el = await fixture(container());
118
+ await el.updateComplete;
119
+
120
+ expect(el.prepareEventDetails.callCount).toEqual(1);
121
+ });
122
+ test('triggers an emitOptionChangedEvent event at firstUpdate', async () => {
123
+ IABookVisualAdjustments.prototype.emitOptionChangedEvent = sinon.fake();
124
+ const el = await fixture(container());
125
+
126
+ expect(el.emitOptionChangedEvent.callCount).toEqual(1);
127
+ });
128
+
129
+ test('triggers an emitOptionChangedEvent event when a checkbox\'s change event fires', async () => {
130
+ IABookVisualAdjustments.prototype.emitOptionChangedEvent = sinon.fake();
131
+ const el = await fixture(container());
132
+
133
+ expect(el.emitOptionChangedEvent.callCount).toEqual(1); // firstUpdate fire
134
+
135
+ el.shadowRoot.querySelector('li input').dispatchEvent(new Event('change'));
136
+ expect(el.emitOptionChangedEvent.callCount).toEqual(2);
137
+ });
138
+
139
+ test('triggers an emitOptionChangedEvent event when a range\'s change event fires', async () => {
140
+ IABookVisualAdjustments.prototype.emitOptionChangedEvent = sinon.fake();
141
+
142
+ const el = await fixture(container());
143
+ expect(el.emitOptionChangedEvent.callCount).toEqual(1); // firstUpdate fire
144
+
145
+ el.shadowRoot.querySelector('[name="brightness_range"]').dispatchEvent(new Event('change'));
146
+ expect(el.emitOptionChangedEvent.callCount).toEqual(2);
147
+ });
148
+
149
+ test('emits a zoom out event when zoom out button clicked', async () => {
150
+ const el = await fixture(container());
151
+
152
+ setTimeout(() => (
153
+ el.shadowRoot.querySelector('.zoom_out').click()
154
+ ));
155
+ const response = await oneEvent(el, 'visualAdjustmentZoomOut');
156
+
157
+ expect(response).toBeDefined();
158
+ });
159
+
160
+ test('emits a zoom in event when zoom in button clicked', async () => {
161
+ const el = await fixture(container());
162
+
163
+ setTimeout(() => (
164
+ el.shadowRoot.querySelector('.zoom_in').click()
165
+ ));
166
+ const response = await oneEvent(el, 'visualAdjustmentZoomIn');
167
+
168
+ expect(response).toBeDefined();
169
+ });
170
+ });
171
+
172
+ test('sets range defaults when none supplied', async () => {
173
+ const el = await fixture(container());
174
+ const brightnessRange = el.shadowRoot.querySelector('[name="brightness_range"]');
175
+
176
+ expect(brightnessRange.getAttribute('min')).toEqual('0');
177
+ expect(brightnessRange.getAttribute('max')).toEqual('100');
178
+ expect(brightnessRange.getAttribute('step')).toEqual('1');
179
+ });
180
+
181
+ test('sets the updated range value on the options prop', async () => {
182
+ const el = await fixture(container());
183
+ const { id } = options[0];
184
+ const newValue = 120;
185
+
186
+ el.setRangeValue(id, newValue);
187
+ await el.updateComplete;
188
+
189
+ expect(el.options[0].value).toEqual(newValue);
190
+ });
191
+
192
+ test('triggers a setRangeValue event when a range\'s input event fires', async () => {
193
+ IABookVisualAdjustments.prototype.setRangeValue = sinon.fake();
194
+
195
+ const el = await fixture(container());
196
+
197
+ el.shadowRoot.querySelector('[name="brightness_range"]').dispatchEvent(new Event('input'));
198
+ expect(el.setRangeValue.callCount).toEqual(1);
199
+ });
200
+ });
@@ -0,0 +1,184 @@
1
+ import { fixture, fixtureCleanup, fixtureSync } from '@open-wc/testing-helpers';
2
+ import sinon from 'sinon';
3
+ import volumesProvider from '@/src/BookNavigator/volumes/volumes-provider';
4
+
5
+ const brOptions = {
6
+ "options": {
7
+ "enableMultipleBooks": true,
8
+ "multipleBooksList": {
9
+ "by_subprefix": {
10
+ "/details/SubBookTest": {
11
+ "url_path": "/details/SubBookTest",
12
+ "file_subprefix": "book1/GPORFP",
13
+ "orig_sort": 1,
14
+ "title": "book1/GPORFP.pdf",
15
+ "file_source": "/book1/GPORFP_jp2.zip"
16
+ },
17
+ "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive": {
18
+ "url_path": "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive",
19
+ "file_subprefix": "subdir/book2/brewster_kahle_internet_archive",
20
+ "orig_sort": 2,
21
+ "title": "subdir/book2/brewster_kahle_internet_archive.pdf",
22
+ "file_source": "/subdir/book2/brewster_kahle_internet_archive_jp2.zip"
23
+ },
24
+ "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume": {
25
+ "url_path": "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
26
+ "file_subprefix": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
27
+ "orig_sort": 3,
28
+ "title": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume.pdf",
29
+ "file_source": "/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume_jp2.zip"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ };
35
+
36
+ afterEach(() => {
37
+ sinon.restore();
38
+ fixtureCleanup();
39
+ });
40
+
41
+ describe('Volumes Provider', () => {
42
+ test('constructor', () => {
43
+ const onProviderChange = sinon.fake();
44
+ const baseHost = "https://archive.org";
45
+ const provider = new volumesProvider({
46
+ baseHost,
47
+ bookreader: brOptions,
48
+ onProviderChange
49
+ });
50
+
51
+ const files = brOptions.options.multipleBooksList.by_subprefix;
52
+ const volumeCount = Object.keys(files).length;
53
+
54
+ expect(provider.onProviderChange).toEqual(onProviderChange);
55
+ expect(provider.id).toEqual('volumes');
56
+ expect(provider.icon).toBeDefined();
57
+ expect(fixtureSync(provider.icon).tagName).toEqual('svg');
58
+ expect(provider.label).toEqual(`Viewable files (${volumeCount})`);
59
+ expect(provider.viewableFiles).toBeDefined();
60
+ expect(provider.viewableFiles.length).toEqual(3);
61
+
62
+ expect(provider.component.hostUrl).toBeDefined();
63
+ expect(provider.component.hostUrl).toEqual(baseHost);
64
+ expect(provider.component).toBeDefined();
65
+ });
66
+
67
+ test('sorting cycles - render sort actionButton', async () => {
68
+ const onProviderChange = sinon.fake();
69
+ const baseHost = "https://archive.org";
70
+ const provider = new volumesProvider({
71
+ baseHost,
72
+ bookreader: brOptions,
73
+ onProviderChange
74
+ });
75
+
76
+ expect(provider.sortOrderBy).toEqual("default");
77
+
78
+ provider.sortVolumes("title_asc");
79
+ expect(provider.sortOrderBy).toEqual("title_asc");
80
+ expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by asc-icon");
81
+
82
+ provider.sortVolumes("title_desc");
83
+ expect(provider.sortOrderBy).toEqual("title_desc");
84
+ expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by desc-icon");
85
+
86
+ provider.sortVolumes("default");
87
+ expect(provider.sortOrderBy).toEqual("default");
88
+ expect(fixtureSync(provider.sortButton).outerHTML).toContain("sort-by neutral-icon");
89
+ });
90
+
91
+ test('sort volumes in initial order', async () => {
92
+ const onProviderChange = sinon.fake();
93
+ const baseHost = "https://archive.org";
94
+ const provider = new volumesProvider({
95
+ baseHost,
96
+ bookreader: brOptions,
97
+ onProviderChange
98
+ });
99
+
100
+ const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
101
+ const files = Object.keys(parsedFiles).map(item => parsedFiles[item]).sort((a, b) => a.orig_sort - b.orig_sort);
102
+ const origSortTitles = files.map(item => item.title);
103
+
104
+ provider.sortVolumes("default");
105
+
106
+ expect(provider.sortOrderBy).toEqual("default");
107
+ expect(provider.actionButton).toBeDefined();
108
+
109
+ const providerFileTitles = provider.viewableFiles.map(item => item.title);
110
+ // use `.eql` for "lose equality" in order to deeply compare values.
111
+ expect(providerFileTitles).toEqual([...origSortTitles]);
112
+ });
113
+
114
+ test('sort volumes in ascending title order', async () => {
115
+ const onProviderChange = sinon.fake();
116
+ const baseHost = "https://archive.org";
117
+ const provider = new volumesProvider({
118
+ baseHost,
119
+ bookreader: brOptions,
120
+ onProviderChange
121
+ });
122
+
123
+ const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
124
+ const files = Object.keys(parsedFiles).map(item => parsedFiles[item]);
125
+ const ascendingTitles = files.map(item => item.title).sort((a, b) => a.localeCompare(b));
126
+
127
+ provider.sortVolumes("title_asc");
128
+
129
+ expect(provider.sortOrderBy).toEqual("title_asc");
130
+ expect(provider.actionButton).toBeDefined();
131
+
132
+ const providerFileTitles = provider.viewableFiles.map(item => item.title);
133
+ // use `.eql` for "lose equality" in order to deeply compare values.
134
+ expect(providerFileTitles).toEqual([...ascendingTitles]);
135
+ });
136
+
137
+ test('sort volumes in descending title order', async () => {
138
+ const onProviderChange = sinon.fake();
139
+ const baseHost = "https://archive.org";
140
+ const provider = new volumesProvider({
141
+ baseHost,
142
+ bookreader: brOptions,
143
+ onProviderChange
144
+ });
145
+ provider.isSortAscending = false;
146
+
147
+ const parsedFiles = brOptions.options.multipleBooksList.by_subprefix;
148
+ const files = Object.keys(parsedFiles).map(item => parsedFiles[item]);
149
+ const descendingTitles = files.map(item => item.title).sort((a, b) => b.localeCompare(a));
150
+
151
+ provider.sortVolumes("title_desc");
152
+
153
+ expect(provider.sortOrderBy).toEqual("title_desc");
154
+ expect(provider.actionButton).toBeDefined();
155
+
156
+ const providerFileTitles = provider.viewableFiles.map(item => item.title);
157
+ // use `.eql` for "lose equality" in order to deeply compare values.
158
+ expect(providerFileTitles).toEqual([...descendingTitles]);
159
+ });
160
+
161
+ describe('Sorting icons', () => {
162
+ test('has 3 icons', async () => {
163
+ const onProviderChange = sinon.fake();
164
+ const baseHost = "https://archive.org";
165
+ const provider = new volumesProvider({
166
+ baseHost,
167
+ bookreader: brOptions,
168
+ onProviderChange
169
+ });
170
+ provider.sortOrderBy = 'default';
171
+
172
+ const origSortButton = await fixture(provider.sortButton);
173
+ expect(origSortButton.classList.contains('neutral-icon')).toBeTruthy();
174
+
175
+ provider.sortOrderBy = 'title_asc';
176
+ const ascButton = await fixture(provider.sortButton);
177
+ expect(ascButton.classList.contains('asc-icon')).toBeTruthy();
178
+
179
+ provider.sortOrderBy = 'title_desc';
180
+ const descButton = await fixture(provider.sortButton);
181
+ expect(descButton.classList.contains('desc-icon')).toBeTruthy();
182
+ });
183
+ });
184
+ });
@@ -0,0 +1,97 @@
1
+ import {
2
+ html,
3
+ fixture,
4
+ fixtureCleanup,
5
+ } from '@open-wc/testing-helpers';
6
+ import sinon from 'sinon';
7
+ import '@/src/BookNavigator/volumes/volumes.js';
8
+
9
+
10
+ const brOptions = {
11
+ "options": {
12
+ "enableMultipleBooks": true,
13
+ "multipleBooksList": {
14
+ "by_subprefix": {
15
+ "/details/SubBookTest": {
16
+ "url_path": "/details/SubBookTest",
17
+ "file_subprefix": "book1/GPORFP",
18
+ "orig_sort": 0,
19
+ "title": "book1/GPORFP.pdf",
20
+ "file_source": "/book1/GPORFP_jp2.zip"
21
+ },
22
+ "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive": {
23
+ "url_path": "/details/SubBookTest/subdir/book2/brewster_kahle_internet_archive",
24
+ "file_subprefix": "subdir/book2/brewster_kahle_internet_archive",
25
+ "orig_sort": 1,
26
+ "title": "subdir/book2/brewster_kahle_internet_archive.pdf",
27
+ "file_source": "/subdir/book2/brewster_kahle_internet_archive_jp2.zip"
28
+ },
29
+ "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume": {
30
+ "url_path": "/details/SubBookTest/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
31
+ "file_subprefix": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume",
32
+ "orig_sort": 2,
33
+ "title": "subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume.pdf",
34
+ "file_source": "/subdir/subsubdir/book3/Rfp008011ResponseInternetArchive-without-resume_jp2.zip"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ };
40
+
41
+ const container = (brOptions, prefix) => (
42
+ html`
43
+ <viewable-files .viewableFiles=${brOptions} .hostUrl="https://archive.org" .subPrefix=${prefix}></viewable-files>
44
+ `
45
+ );
46
+
47
+ beforeEach(() => {
48
+ const body = document.querySelector('body');
49
+ const brHook = document.createElement('div');
50
+ brHook.setAttribute('id', 'BookReader');
51
+ body.appendChild(brHook);
52
+ });
53
+
54
+ afterEach(() => {
55
+ sinon.restore();
56
+ fixtureCleanup();
57
+ });
58
+
59
+ describe('<viewable-files>', () => {
60
+ test('sets default properties', async () => {
61
+ const files = brOptions.options.multipleBooksList?.by_subprefix;
62
+ const viewableFiles = Object.keys(files).map(item => files[item]);
63
+ const el = await fixture(container(viewableFiles));
64
+ await el.updateComplete;
65
+
66
+ expect(el.viewableFiles).toEqual(viewableFiles);
67
+ expect(el.viewableFiles.length).toEqual(3);
68
+ expect(el.shadowRoot.querySelectorAll("ul li").length).toEqual(3);
69
+
70
+ expect(el.shadowRoot.querySelector(".item-title").textContent).toContain(`${viewableFiles[0].title}`);
71
+ });
72
+
73
+ test('render empty volumes', async () => {
74
+ const viewableFiles = [];
75
+ const el = await fixture(container(viewableFiles));
76
+ await el.updateComplete;
77
+
78
+ expect(el.viewableFiles).toEqual(viewableFiles);
79
+ expect(el.viewableFiles.length).toEqual(0);
80
+ expect(el.shadowRoot.childElementCount).not.toEqual(0);
81
+ });
82
+
83
+ test('render active volume item set as first viewable item ', async () => {
84
+ const files = brOptions.options.multipleBooksList?.by_subprefix;
85
+ const viewableFiles = Object.keys(files).map(item => files[item]);
86
+ const prefix = viewableFiles[0].file_subprefix;
87
+
88
+ const el = await fixture(container(viewableFiles, prefix));
89
+ await el.updateComplete;
90
+
91
+ expect(el.viewableFiles).toEqual(viewableFiles);
92
+ expect(el.viewableFiles.length).toEqual(3);
93
+
94
+ expect(el.shadowRoot.querySelectorAll("ul li div")[1].className).toEqual("content active");
95
+ });
96
+
97
+ });
@@ -1,7 +1,8 @@
1
1
  import sinon from 'sinon';
2
2
  import { deepCopy } from '../utils.js';
3
- import { BookModel } from '../../src/BookReader/BookModel.js';
4
- /** @typedef {import('../../src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
3
+ import { BookModel } from '@/src/BookReader/BookModel.js';
4
+ import { NAMED_REDUCE_SETS } from '@/src/BookReader/ReduceSet.js';
5
+ /** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
5
6
 
6
7
  afterEach(() => {
7
8
  sinon.restore();
@@ -21,10 +22,10 @@ const SAMPLE_DATA = [
21
22
  ],
22
23
  ];
23
24
 
24
- describe('getMedianPageSize', () => {
25
+ describe('getMedianPageSizeInches', () => {
25
26
  test('handles single page data', () => {
26
- const bm = new BookModel({ data: SAMPLE_DATA.slice(0, 1) });
27
- expect(bm.getMedianPageSize()).toEqual({ width: 123, height: 123 });
27
+ const bm = new BookModel({ data: SAMPLE_DATA.slice(0, 1), options: {ppi: 1} });
28
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 123, height: 123 });
28
29
  });
29
30
 
30
31
  test('handles odd pages data', () => {
@@ -38,8 +39,8 @@ describe('getMedianPageSize', () => {
38
39
  Object.assign(data[0][0], sizes[0]);
39
40
  Object.assign(data[1][0], sizes[1]);
40
41
  Object.assign(data[1][1], sizes[2]);
41
- const bm = new BookModel({ data });
42
- expect(bm.getMedianPageSize()).toEqual({ width: 200, height: 2200 });
42
+ const bm = new BookModel({ data, options: {ppi: 1} });
43
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 200, height: 2200 });
43
44
  });
44
45
 
45
46
 
@@ -55,16 +56,16 @@ describe('getMedianPageSize', () => {
55
56
  Object.assign(data[1][0], sizes[1]);
56
57
  Object.assign(data[1][1], sizes[2]);
57
58
  Object.assign(data[2][0], sizes[3]);
58
- const bm = new BookModel({ data });
59
- expect(bm.getMedianPageSize()).toEqual({ width: 300, height: 2300 });
59
+ const bm = new BookModel({ data, options: {ppi: 1} });
60
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 300, height: 2300 });
60
61
  });
61
62
 
62
63
  test('caches result', () => {
63
64
  const bm = new BookModel({ data: SAMPLE_DATA });
64
- const firstResult = bm.getMedianPageSize();
65
- expect(bm.getMedianPageSize()).toBe(firstResult);
66
- expect(bm.getMedianPageSize()).toBe(firstResult);
67
- expect(bm.getMedianPageSize()).toBe(firstResult);
65
+ const firstResult = bm.getMedianPageSizeInches();
66
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
67
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
68
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
68
69
  });
69
70
  });
70
71
 
@@ -190,7 +191,7 @@ describe('pagesIterator', () => {
190
191
  describe('_getDataFlattened', () => {
191
192
  test('Assigns correct page sides', () => {
192
193
  const bm = new BookModel({ data: SAMPLE_DATA });
193
- expect(bm._getDataFlattened().map(page => page.pageSide)).toEqual(['R', 'L', 'R', 'L'])
194
+ expect(bm._getDataFlattened().map(page => page.pageSide)).toEqual(['R', 'L', 'R', 'L']);
194
195
  });
195
196
 
196
197
  test('Memoized based on data length', () => {
@@ -309,4 +310,48 @@ describe('PageModel', () => {
309
310
  expect(bm.getPage(0).findPrev({ combineConsecutiveUnviewables: true })).toBeUndefined();
310
311
  });
311
312
  });
313
+
314
+ describe('findLeft/findRight', () => {
315
+ const data = deepCopy(SAMPLE_DATA);
316
+
317
+ test('Calls findNext/findPrev based on progression', () => {
318
+ const bm = new BookModel({ data });
319
+ const page = bm.getPage(0);
320
+ const findNextStub = sinon.stub(page, 'findNext');
321
+ const findPrevStub = sinon.stub(page, 'findPrev');
322
+ bm.pageProgression = 'lr';
323
+ page.findLeft();
324
+ expect(findPrevStub.callCount).toBe(1);
325
+ expect(findNextStub.callCount).toBe(0);
326
+ page.findRight();
327
+ expect(findPrevStub.callCount).toBe(1);
328
+ expect(findNextStub.callCount).toBe(1);
329
+ bm.pageProgression = 'rl';
330
+ page.findLeft();
331
+ expect(findPrevStub.callCount).toBe(1);
332
+ expect(findNextStub.callCount).toBe(2);
333
+ page.findRight();
334
+ expect(findPrevStub.callCount).toBe(2);
335
+ expect(findNextStub.callCount).toBe(2);
336
+ });
337
+ });
338
+
339
+ describe('getURISrcSet', () => {
340
+ const data = deepCopy(SAMPLE_DATA);
341
+ const bm = new BookModel({ data, reduceSet: NAMED_REDUCE_SETS.pow2 });
342
+ bm.getPageURI = (index, scale, rotate) => `correctURL.png?scale=${scale}`;
343
+ const page = bm.getPage(0);
344
+
345
+ test('with 0 elements in srcset', () => {
346
+ expect(page.getURISrcSet(1)).toBe("");
347
+ });
348
+
349
+ test('with 2 elements in srcset', () => {
350
+ expect(page.getURISrcSet(5)).toBe("correctURL.png?scale=2 2x, correctURL.png?scale=1 4x");
351
+ });
352
+
353
+ test('with the most elements in srcset', () => {
354
+ expect(page.getURISrcSet(35)).toBe("correctURL.png?scale=16 2x, correctURL.png?scale=8 4x, correctURL.png?scale=4 8x, correctURL.png?scale=2 16x, correctURL.png?scale=1 32x");
355
+ });
356
+ });
312
357
  });