@internetarchive/bookreader 5.0.0-9 → 5.0.0-90

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 (324) hide show
  1. package/.eslintrc.js +21 -19
  2. package/.github/workflows/node.js.yml +76 -11
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +404 -1125
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -1
  13. package/BookReader/icons/2up.svg +1 -1
  14. package/BookReader/icons/advance.svg +1 -1
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -1
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -1
  19. package/BookReader/icons/fullscreen_exit.svg +1 -1
  20. package/BookReader/icons/hamburger.svg +1 -1
  21. package/BookReader/icons/left-arrow.svg +1 -1
  22. package/BookReader/icons/magnify-minus.svg +1 -1
  23. package/BookReader/icons/magnify-plus.svg +1 -1
  24. package/BookReader/icons/magnify.svg +1 -1
  25. package/BookReader/icons/pause.svg +1 -1
  26. package/BookReader/icons/play.svg +1 -1
  27. package/BookReader/icons/playback-speed.svg +1 -1
  28. package/BookReader/icons/read-aloud.svg +1 -1
  29. package/BookReader/icons/review.svg +1 -1
  30. package/BookReader/icons/thumbnails.svg +1 -1
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -1
  33. package/BookReader/images/BRicons.svg +3 -3
  34. package/BookReader/images/books_graphic.svg +1 -1
  35. package/BookReader/images/icon_book.svg +1 -1
  36. package/BookReader/images/icon_bookmark.svg +1 -1
  37. package/BookReader/images/icon_gear.svg +1 -1
  38. package/BookReader/images/icon_hamburger.svg +1 -1
  39. package/BookReader/images/icon_home.svg +1 -1
  40. package/BookReader/images/icon_info.svg +1 -1
  41. package/BookReader/images/icon_one_page.svg +1 -1
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -1
  45. package/BookReader/images/icon_search_button.svg +1 -1
  46. package/BookReader/images/icon_share.svg +1 -1
  47. package/BookReader/images/icon_skip-ahead.svg +1 -1
  48. package/BookReader/images/icon_skip-back.svg +1 -1
  49. package/BookReader/images/icon_speaker.svg +1 -1
  50. package/BookReader/images/icon_speaker_open.svg +1 -1
  51. package/BookReader/images/icon_thumbnails.svg +1 -1
  52. package/BookReader/images/icon_toc.svg +1 -1
  53. package/BookReader/images/icon_two_pages.svg +1 -1
  54. package/BookReader/images/marker_chap-off.svg +1 -1
  55. package/BookReader/images/marker_chap-on.svg +1 -1
  56. package/BookReader/images/marker_srch-on.svg +1 -1
  57. package/BookReader/images/unviewable_page.png +0 -0
  58. package/BookReader/jquery-3.js +2 -0
  59. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  60. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  61. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js +1 -1
  63. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  64. package/BookReader/plugins/plugin.chapters.js +25 -1
  65. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  66. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  67. package/BookReader/plugins/plugin.iframe.js +1 -1
  68. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  69. package/BookReader/plugins/plugin.iiif.js +2 -0
  70. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  71. package/BookReader/plugins/plugin.resume.js +1 -1
  72. package/BookReader/plugins/plugin.resume.js.map +1 -1
  73. package/BookReader/plugins/plugin.search.js +2 -1
  74. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.search.js.map +1 -1
  76. package/BookReader/plugins/plugin.text_selection.js +2 -1
  77. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  78. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  79. package/BookReader/plugins/plugin.tts.js +1 -1
  80. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  81. package/BookReader/plugins/plugin.tts.js.map +1 -1
  82. package/BookReader/plugins/plugin.url.js +1 -1
  83. package/BookReader/plugins/plugin.url.js.map +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  85. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  86. package/BookReader/webcomponents-bundle.js +3 -0
  87. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  88. package/BookReader/webcomponents-bundle.js.map +1 -0
  89. package/BookReaderDemo/BookReaderDemo.css +18 -19
  90. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +144 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  95. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  96. package/BookReaderDemo/demo-fullscreen.html +2 -4
  97. package/BookReaderDemo/demo-iiif.html +99 -12
  98. package/BookReaderDemo/demo-internetarchive.html +214 -18
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +526 -525
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +584 -33
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +5 -2
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +70 -62
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +0 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +5 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/book-navigator.js +590 -0
  125. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  126. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  127. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  128. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  129. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  130. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  131. package/src/BookNavigator/delete-modal-actions.js +1 -1
  132. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  133. package/src/BookNavigator/downloads/downloads.js +29 -25
  134. package/src/BookNavigator/search/search-provider.js +50 -28
  135. package/src/BookNavigator/search/search-results.js +24 -10
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/viewable-files.js +95 -0
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
  140. package/src/BookReader/BookModel.js +76 -41
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/ImageCache.js +48 -15
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +777 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +19 -13
  150. package/src/BookReader/Navbar/Navbar.js +70 -54
  151. package/src/BookReader/PageContainer.js +116 -22
  152. package/src/BookReader/ReduceSet.js +3 -3
  153. package/src/BookReader/Toolbar/Toolbar.js +14 -41
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +73 -15
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils/classes.js +1 -1
  160. package/src/BookReader/utils.js +128 -13
  161. package/src/BookReader.js +544 -1078
  162. package/src/BookReaderPlugin.js +44 -0
  163. package/src/assets/icons/magnify-minus.svg +3 -7
  164. package/src/assets/icons/magnify-plus.svg +3 -7
  165. package/src/assets/icons/voice.svg +1 -0
  166. package/src/assets/images/unviewable_page.png +0 -0
  167. package/src/css/BookReader.scss +1 -5
  168. package/src/css/_BRBookmarks.scss +1 -1
  169. package/src/css/_BRComponent.scss +1 -1
  170. package/src/css/_BRicon.scss +8 -2
  171. package/src/css/_BRmain.scss +16 -3
  172. package/src/css/_BRnav.scss +12 -42
  173. package/src/css/_BRpages.scss +170 -42
  174. package/src/css/_BRsearch.scss +68 -25
  175. package/src/css/_BRtoolbar.scss +5 -5
  176. package/src/css/_TextSelection.scss +87 -27
  177. package/src/css/_colorbox.scss +2 -2
  178. package/src/css/_controls.scss +24 -7
  179. package/src/css/_icons.scss +1 -1
  180. package/src/ia-bookreader/ia-bookreader.js +224 -0
  181. package/src/plugins/plugin.archive_analytics.js +84 -78
  182. package/src/plugins/plugin.autoplay.js +99 -104
  183. package/src/plugins/plugin.chapters.js +237 -191
  184. package/src/plugins/plugin.iframe.js +1 -1
  185. package/src/plugins/plugin.iiif.js +141 -0
  186. package/src/plugins/plugin.resume.js +53 -50
  187. package/src/plugins/plugin.text_selection.js +503 -175
  188. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  189. package/src/plugins/search/plugin.search.js +151 -127
  190. package/src/plugins/search/utils.js +43 -0
  191. package/src/plugins/search/view.js +37 -59
  192. package/src/plugins/tts/AbstractTTSEngine.js +75 -45
  193. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  194. package/src/plugins/tts/PageChunk.js +16 -23
  195. package/src/plugins/tts/PageChunkIterator.js +11 -17
  196. package/src/plugins/tts/WebTTSEngine.js +88 -72
  197. package/src/plugins/tts/plugin.tts.js +310 -350
  198. package/src/plugins/tts/utils.js +16 -26
  199. package/src/plugins/url/UrlPlugin.js +191 -0
  200. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  201. package/src/util/browserSniffing.js +22 -0
  202. package/src/util/docCookies.js +21 -2
  203. package/src/util/strings.js +1 -0
  204. package/tests/e2e/README.md +37 -0
  205. package/tests/e2e/autoplay.test.js +9 -6
  206. package/tests/e2e/base.test.js +8 -16
  207. package/tests/e2e/helpers/base.js +55 -50
  208. package/tests/e2e/helpers/debug.js +1 -1
  209. package/tests/e2e/helpers/mockSearch.js +19 -22
  210. package/tests/e2e/helpers/params.js +17 -0
  211. package/tests/e2e/helpers/rightToLeft.js +8 -14
  212. package/tests/e2e/helpers/search.js +73 -0
  213. package/tests/e2e/models/Navigation.js +20 -37
  214. package/tests/e2e/rightToLeft.test.js +4 -5
  215. package/tests/e2e/viewmode.test.js +40 -33
  216. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  217. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  218. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  219. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  220. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  221. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  222. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  223. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  224. package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
  225. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  226. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  227. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  228. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  229. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  230. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  231. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  232. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  233. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  234. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  235. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  236. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  237. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +42 -29
  238. package/tests/jest/BookReader/PageContainer.test.js +238 -0
  239. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  240. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
  241. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  242. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  243. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  244. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  245. package/tests/jest/BookReader/utils.test.js +250 -0
  246. package/tests/jest/BookReader.keyboard.test.js +190 -0
  247. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
  248. package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
  249. package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
  250. package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
  251. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  252. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
  253. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
  254. package/tests/jest/plugins/plugin.text_selection.test.js +316 -0
  255. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  256. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +19 -47
  257. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +42 -9
  258. package/tests/jest/plugins/search/utils.js +25 -0
  259. package/tests/jest/plugins/search/utils.test.js +29 -0
  260. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +30 -10
  261. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  262. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  263. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  264. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  265. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  266. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  267. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +57 -18
  268. package/tests/jest/setup.js +3 -0
  269. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  270. package/tests/jest/util/docCookies.test.js +24 -0
  271. package/tests/{util → jest/util}/strings.test.js +1 -1
  272. package/tests/{utils.js → jest/utils.js} +38 -0
  273. package/webpack.config.js +16 -10
  274. package/.babelrc +0 -12
  275. package/.dependabot/config.yml +0 -6
  276. package/.testcaferc.json +0 -5
  277. package/BookReader/bookreader-component-bundle.js +0 -1450
  278. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  279. package/BookReader/bookreader-component-bundle.js.map +0 -1
  280. package/BookReader/jquery-1.10.1.js +0 -2
  281. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  282. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  283. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  284. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  285. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  286. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  287. package/BookReaderDemo/IIIFBookReader.js +0 -207
  288. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  289. package/BookReaderDemo/demo-autoplay.html +0 -38
  290. package/BookReaderDemo/demo-iiif.js +0 -26
  291. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  292. package/karma.conf.js +0 -23
  293. package/src/BookNavigator/BookModel.js +0 -14
  294. package/src/BookNavigator/BookNavigator.js +0 -446
  295. package/src/BookNavigator/assets/book-loader.js +0 -27
  296. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  297. package/src/BookNavigator/search/a-search-result.js +0 -55
  298. package/src/BookReader/DebugConsole.js +0 -54
  299. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  300. package/src/ItemNavigator/ItemNavigator.js +0 -376
  301. package/src/ItemNavigator/providers/sharing.js +0 -29
  302. package/src/css/_MobileNav.scss +0 -194
  303. package/src/dragscrollable-br.js +0 -261
  304. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  305. package/src/plugins/plugin.mobile_nav.js +0 -287
  306. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  307. package/tests/BookReader/DebugConsole.test.js +0 -25
  308. package/tests/BookReader/Mode1Up.test.js +0 -164
  309. package/tests/BookReader/Mode2Up.test.js +0 -247
  310. package/tests/BookReader/PageContainer.test.js +0 -115
  311. package/tests/BookReader/utils.test.js +0 -109
  312. package/tests/e2e/helpers/desktopSearch.js +0 -72
  313. package/tests/e2e/helpers/mobileSearch.js +0 -85
  314. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  315. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  316. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  317. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  318. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  319. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  320. package/tests/plugins/plugin.autoplay.test.js +0 -52
  321. package/tests/plugins/plugin.chapters.test.js +0 -130
  322. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  323. package/tests/plugins/plugin.text_selection.test.js +0 -203
  324. 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 (dark mode)',
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
+ });
@@ -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: 10} });
28
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 12.3, height: 12.3 });
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: 10} });
43
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 20, height: 220 });
43
44
  });
44
45
 
45
46
 
@@ -55,16 +56,31 @@ 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: 10} });
60
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 30, height: 230 });
61
+ });
62
+
63
+ test('does not lexicographic sort for median', () => {
64
+ const sizes = [
65
+ {width: 100, height: 100},
66
+ {width: 20, height: 20},
67
+ {width: 30, height: 30},
68
+ ];
69
+ const data = deepCopy(SAMPLE_DATA);
70
+ delete data[2];
71
+ Object.assign(data[0][0], sizes[0]);
72
+ Object.assign(data[1][0], sizes[1]);
73
+ Object.assign(data[1][1], sizes[2]);
74
+ const bm = new BookModel({ data, options: {ppi: 10} });
75
+ expect(bm.getMedianPageSizeInches()).toEqual({ width: 3, height: 3 });
60
76
  });
61
77
 
62
78
  test('caches result', () => {
63
79
  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);
80
+ const firstResult = bm.getMedianPageSizeInches();
81
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
82
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
83
+ expect(bm.getMedianPageSizeInches()).toBe(firstResult);
68
84
  });
69
85
  });
70
86
 
@@ -190,7 +206,7 @@ describe('pagesIterator', () => {
190
206
  describe('_getDataFlattened', () => {
191
207
  test('Assigns correct page sides', () => {
192
208
  const bm = new BookModel({ data: SAMPLE_DATA });
193
- expect(bm._getDataFlattened().map(page => page.pageSide)).toEqual(['R', 'L', 'R', 'L'])
209
+ expect(bm._getDataFlattened().map(page => page.pageSide)).toEqual(['R', 'L', 'R', 'L']);
194
210
  });
195
211
 
196
212
  test('Memoized based on data length', () => {
@@ -309,4 +325,48 @@ describe('PageModel', () => {
309
325
  expect(bm.getPage(0).findPrev({ combineConsecutiveUnviewables: true })).toBeUndefined();
310
326
  });
311
327
  });
328
+
329
+ describe('findLeft/findRight', () => {
330
+ const data = deepCopy(SAMPLE_DATA);
331
+
332
+ test('Calls findNext/findPrev based on progression', () => {
333
+ const bm = new BookModel({ data });
334
+ const page = bm.getPage(0);
335
+ const findNextStub = sinon.stub(page, 'findNext');
336
+ const findPrevStub = sinon.stub(page, 'findPrev');
337
+ bm.pageProgression = 'lr';
338
+ page.findLeft();
339
+ expect(findPrevStub.callCount).toBe(1);
340
+ expect(findNextStub.callCount).toBe(0);
341
+ page.findRight();
342
+ expect(findPrevStub.callCount).toBe(1);
343
+ expect(findNextStub.callCount).toBe(1);
344
+ bm.pageProgression = 'rl';
345
+ page.findLeft();
346
+ expect(findPrevStub.callCount).toBe(1);
347
+ expect(findNextStub.callCount).toBe(2);
348
+ page.findRight();
349
+ expect(findPrevStub.callCount).toBe(2);
350
+ expect(findNextStub.callCount).toBe(2);
351
+ });
352
+ });
353
+
354
+ describe('getURISrcSet', () => {
355
+ const data = deepCopy(SAMPLE_DATA);
356
+ const bm = new BookModel({ data, reduceSet: NAMED_REDUCE_SETS.pow2 });
357
+ bm.getPageURI = (index, scale, rotate) => `correctURL.png?scale=${scale}`;
358
+ const page = bm.getPage(0);
359
+
360
+ test('with 0 elements in srcset', () => {
361
+ expect(page.getURISrcSet(1)).toBe("");
362
+ });
363
+
364
+ test('with 2 elements in srcset', () => {
365
+ expect(page.getURISrcSet(5)).toBe("correctURL.png?scale=2 2x, correctURL.png?scale=1 4x");
366
+ });
367
+
368
+ test('with the most elements in srcset', () => {
369
+ 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");
370
+ });
371
+ });
312
372
  });
@@ -0,0 +1,193 @@
1
+ import BookReader from '@/src/BookReader';
2
+ import { sleep } from '@/src/BookReader/utils.js';
3
+ import sinon from 'sinon';
4
+
5
+ beforeAll(() => {
6
+ global.alert = sinon.fake();
7
+ });
8
+ afterEach(() => {
9
+ sinon.restore();
10
+ });
11
+
12
+ describe('BookReader.prototype.toggleFullscreen', () => {
13
+ test('uses `isFullscreen` to check fullscreen state', () => {
14
+ const isFSmock = sinon.fake();
15
+ // isFSmock.mockReturnValueOnce(false);
16
+ const br = new BookReader();
17
+ br.mode = br.constMode1up;
18
+ br.enterFullscreen = sinon.fake();
19
+ br.isFullscreen = isFSmock;
20
+
21
+ br.toggleFullscreen();
22
+ expect(br.isFullscreen.callCount).toEqual(1);
23
+ });
24
+
25
+ test('will always emit an event', async () => {
26
+ const br = new BookReader();
27
+ br.mode = br.constMode2up;
28
+ br.trigger = sinon.fake();
29
+ br.switchMode = sinon.fake();
30
+ br.updateBrClasses = sinon.fake();
31
+ br.jumpToIndex = sinon.fake();
32
+ br.refs.$brContainer = {
33
+ css: sinon.fake(),
34
+ animate: (options, speed, style, callback) => callback(),
35
+ };
36
+ br.refs.$br = {
37
+ updateBrClasses: sinon.fake(),
38
+ removeClass: sinon.fake(),
39
+ addClass: sinon.fake(),
40
+ css: sinon.fake(),
41
+ animate: (options, speed, style, callback) => callback(),
42
+ };
43
+
44
+ await br.toggleFullscreen();
45
+ expect(br.trigger.callCount).toBeGreaterThan(0);
46
+ });
47
+
48
+ test('will start with opening fullscreen', () => {
49
+ const br = new BookReader();
50
+ br.mode = br.constMode2up;
51
+ br.enterFullscreen = sinon.fake();
52
+
53
+ br.toggleFullscreen();
54
+ expect(br.enterFullscreen.callCount).toEqual(1);
55
+ });
56
+
57
+ test('will close fullscreen if BookReader is in fullscreen', () => {
58
+ const br = new BookReader();
59
+ br.mode = br.constMode1up;
60
+ br.exitFullScreen = sinon.fake();
61
+ br.isFullscreenActive = true;
62
+
63
+ br.toggleFullscreen();
64
+ expect(br.exitFullScreen.callCount).toEqual(1);
65
+ });
66
+ });
67
+
68
+ describe('BookReader.prototype.enterFullscreen', () => {
69
+ test('will bind `_fullscreenCloseHandler` by default', () => {
70
+ const br = new BookReader();
71
+ br.mode = br.constMode1up;
72
+ br.switchMode = sinon.fake();
73
+ br.updateBrClasses = sinon.fake();
74
+ br.refs.$br = {
75
+ css: sinon.fake(),
76
+ animate: sinon.fake(),
77
+ addClass: sinon.fake(),
78
+ };
79
+ expect(br._fullscreenCloseHandler).toBeUndefined();
80
+
81
+ br.enterFullscreen();
82
+ expect(br._fullscreenCloseHandler).toBeDefined();
83
+ });
84
+
85
+ test('fires certain events when called', async () => {
86
+ const br = new BookReader();
87
+ br.mode = br.constMode2up;
88
+ br.switchMode = sinon.fake();
89
+ br.updateBrClasses = sinon.fake();
90
+ br.trigger = sinon.fake();
91
+ br.resize = sinon.fake();
92
+ br.jumpToIndex = sinon.fake();
93
+ br.refs.$br = {
94
+ addClass: sinon.fake(),
95
+ removeClass: sinon.fake(),
96
+ };
97
+ br.refs.$brContainer = {
98
+ css: sinon.fake(),
99
+ animate: (options, speed, style, callback) => callback(),
100
+ };
101
+
102
+ await br.enterFullscreen();
103
+ expect(br.switchMode.callCount).toEqual(1);
104
+ expect(br.updateBrClasses.callCount).toEqual(1);
105
+ expect(br.trigger.callCount).toEqual(2); // fragmentChange, fullscreenToggled
106
+ expect(br.jumpToIndex.callCount).toEqual(1);
107
+
108
+ await sleep(0);
109
+ expect(br.resize.callCount).toEqual(1);
110
+ });
111
+ });
112
+
113
+ describe('BookReader.prototype.exitFullScreen', () => {
114
+ test('fires certain events when called', async () => {
115
+ const br = new BookReader();
116
+ br.mode = br.constMode2up;
117
+ br.switchMode = sinon.fake();
118
+ br.updateBrClasses = sinon.fake();
119
+ br.trigger = sinon.fake();
120
+ br.resize = sinon.fake();
121
+ br.refs.$br = {
122
+ addClass: sinon.fake(),
123
+ removeClass: sinon.fake(),
124
+ };
125
+ br.refs.$brContainer = {
126
+ css: sinon.fake(),
127
+ animate: (options, speed, style, callback) => callback(),
128
+ };
129
+ await br.exitFullScreen();
130
+ expect(br.switchMode.callCount).toEqual(1);
131
+ expect(br.updateBrClasses.callCount).toEqual(1);
132
+ expect(br.trigger.callCount).toEqual(2); // fragmentChange, fullscreenToggled
133
+ expect(br.resize.callCount).toEqual(1);
134
+ });
135
+ });
136
+
137
+ describe('BookReader.prototype.trigger', () => {
138
+ test('fires custom event', () => {
139
+ const br = new BookReader();
140
+ global.br = br;
141
+ global.dispatchEvent = sinon.fake();
142
+
143
+ const props = {bar: 1};
144
+ br.trigger('foo', props);
145
+ expect(global.dispatchEvent.callCount).toBe(1);
146
+ });
147
+ });
148
+
149
+ describe('`BookReader.prototype.prev`', () => {
150
+ let br;
151
+ let flipAnimationStub;
152
+ beforeEach(() => {
153
+ br = new BookReader();
154
+ global.br = br;
155
+ br.trigger = sinon.fake();
156
+ br.jumpToIndex = sinon.fake();
157
+ flipAnimationStub = sinon.stub(br._modes.mode2Up.mode2UpLit, 'flipAnimation');
158
+ });
159
+
160
+ afterEach(() => {
161
+ sinon.restore();
162
+ });
163
+
164
+ test('does not take action if user is on front page', () => {
165
+ br.firstIndex = 0;
166
+ br.prev();
167
+ expect(br.trigger.callCount).toBe(0);
168
+ expect(flipAnimationStub.callCount).toBe(0);
169
+ expect(br.jumpToIndex.callCount).toBe(0);
170
+ });
171
+
172
+ describe('2up mode', () => {
173
+ test('fires event and turns the page', () => {
174
+ br.firstIndex = 10;
175
+ br.mode = br.constMode2up;
176
+ br.prev();
177
+ expect(br.jumpToIndex.callCount).toBe(0); // <-- does not get called
178
+ expect(br.trigger.callCount).toBe(1);
179
+ expect(flipAnimationStub.callCount).toBe(1);
180
+ });
181
+ });
182
+
183
+ describe('non 2up mode', () => {
184
+ test('jumps to provided index', () => {
185
+ br.firstIndex = 100;
186
+ br.mode = br.constMode1up;
187
+ br.prev();
188
+ expect(br.jumpToIndex.callCount).toBe(1); // <-- gets called
189
+ expect(flipAnimationStub.callCount).toBe(0); // <-- gets called by `jumpToIndex` internally
190
+ });
191
+ });
192
+ });
193
+
@@ -1,8 +1,8 @@
1
1
  import sinon from 'sinon';
2
- import { BookModel } from '../../src/BookReader/BookModel.js';
3
- import { ImageCache } from '../../src/BookReader/ImageCache.js';
4
- import { Pow2ReduceSet } from '../../src/BookReader/ReduceSet.js';
5
- /** @typedef {import('../../src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
2
+ import { BookModel } from '@/src/BookReader/BookModel.js';
3
+ import { ImageCache } from '@/src/BookReader/ImageCache.js';
4
+ import { Pow2ReduceSet } from '@/src/BookReader/ReduceSet.js';
5
+ /** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
6
6
 
7
7
  afterEach(() => {
8
8
  jest.restoreAllMocks();
@@ -0,0 +1,73 @@
1
+ import { BookModel } from '@/src/BookReader/BookModel.js';
2
+ import { Mode1UpLit } from '@/src/BookReader/Mode1UpLit.js';
3
+
4
+ /** @type {import('@/src/BookReader/options.js').BookReaderOptions['data']} */
5
+ const SAMPLE_DATA = [
6
+ [
7
+ { width: 123, height: 123, uri: 'https://archive.org/image0.jpg', pageNum: '1' },
8
+ ],
9
+ [
10
+ { width: 123, height: 123, uri: 'https://archive.org/image1.jpg', pageNum: '2' },
11
+ { width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '3' },
12
+ ],
13
+ [
14
+ { width: 123, height: 123, uri: 'https://archive.org/image3.jpg', pageNum: '4' },
15
+ { width: 123, height: 123, uri: 'https://archive.org/image4.jpg', pageNum: '5' },
16
+ ],
17
+ [
18
+ { width: 123, height: 123, uri: 'https://archive.org/image5.jpg', pageNum: '6' },
19
+ ],
20
+ ];
21
+
22
+ function make_dummy_br(overrides = {}) {
23
+ return Object.assign({
24
+ updateFirstIndex() {},
25
+ _components: {
26
+ navbar: {
27
+ updateNavIndexThrottled() {},
28
+ },
29
+ },
30
+ data: [],
31
+ }, overrides);
32
+ }
33
+
34
+ describe('pageTops', () => {
35
+ afterEach(() => document.body.innerHTML = '');
36
+
37
+ test('Works with empty book', async () => {
38
+ const br = make_dummy_br({ data: [] });
39
+ const book = new BookModel(br);
40
+ const mode = new Mode1UpLit(book, br);
41
+ document.body.appendChild(mode);
42
+ mode.requestUpdate();
43
+ await mode.updateComplete;
44
+ expect(mode.pageTops).toEqual({});
45
+ });
46
+
47
+ test('Iterates all pages', async () => {
48
+ const br = make_dummy_br({ data: SAMPLE_DATA });
49
+ const book = new BookModel(br);
50
+ const mode = new Mode1UpLit(book, br);
51
+ document.body.appendChild(mode);
52
+ await mode.requestUpdate();
53
+ expect(Object.values(mode.pageTops)).toHaveLength(6);
54
+ });
55
+
56
+ test('Computes tops', async () => {
57
+ const br = make_dummy_br({ data: SAMPLE_DATA });
58
+ const book = new BookModel(br);
59
+ const mode = new Mode1UpLit(book, br);
60
+ document.body.appendChild(mode);
61
+ await mode.requestUpdate();
62
+ const tops = Object.entries(mode.pageTops);
63
+ expect(tops.map(([index, top]) => [index, top.toFixed(1)])).toEqual([
64
+ // Recall these are in inches
65
+ ['0', '0.2'],
66
+ ['1', '0.6'],
67
+ ['2', '1.1'],
68
+ ['3', '1.5'],
69
+ ['4', '2.0'],
70
+ ['5', '2.4'],
71
+ ]);
72
+ });
73
+ });