@internetarchive/bookreader 5.0.0-3 → 5.0.0-30-d

Sign up to get free protection for your applications and to get access to all the features.
Files changed (391) hide show
  1. package/.eslintrc.js +17 -5
  2. package/.github/dependabot.yml +8 -0
  3. package/.github/workflows/node.js.yml +10 -1
  4. package/.husky/_/husky.sh +30 -0
  5. package/.testcaferc.js +10 -0
  6. package/BookReader/BookReader.css +75 -323
  7. package/BookReader/BookReader.js +32261 -2
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +15235 -0
  10. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  11. package/BookReader/icons/close-circle-dark.svg +1 -0
  12. package/BookReader/icons/voice.svg +1 -0
  13. package/BookReader/jquery-1.10.1.js +108 -2
  14. package/BookReader/plugins/plugin.archive_analytics.js +170 -1
  15. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  16. package/BookReader/plugins/plugin.autoplay.js +163 -1
  17. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  18. package/BookReader/plugins/plugin.chapters.js +333 -1
  19. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  20. package/BookReader/plugins/plugin.iframe.js +72 -1
  21. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  22. package/BookReader/plugins/plugin.mobile_nav.js +332 -1
  23. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  24. package/BookReader/plugins/plugin.resume.js +241 -1
  25. package/BookReader/plugins/plugin.resume.js.map +1 -1
  26. package/BookReader/plugins/plugin.search.js +1261 -1
  27. package/BookReader/plugins/plugin.search.js.map +1 -1
  28. package/BookReader/plugins/plugin.text_selection.js +839 -1
  29. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  30. package/BookReader/plugins/plugin.tts.js +9115 -2
  31. package/BookReader/plugins/plugin.tts.js.map +1 -1
  32. package/BookReader/plugins/plugin.url.js +811 -1
  33. package/BookReader/plugins/plugin.url.js.map +1 -1
  34. package/BookReader/plugins/plugin.vendor-fullscreen.js +326 -1
  35. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  36. package/BookReader/webcomponents-bundle.js +412 -0
  37. package/BookReader/webcomponents-bundle.js.map +1 -0
  38. package/BookReaderDemo/BookReaderDemo.css +14 -1
  39. package/BookReaderDemo/IADemoBr.js +107 -0
  40. package/BookReaderDemo/demo-advanced.html +1 -1
  41. package/BookReaderDemo/demo-autoplay.html +1 -0
  42. package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
  43. package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
  44. package/BookReaderDemo/demo-fullscreen.html +1 -0
  45. package/BookReaderDemo/demo-iiif.html +1 -0
  46. package/BookReaderDemo/demo-internetarchive.html +66 -18
  47. package/BookReaderDemo/demo-multiple.html +1 -0
  48. package/BookReaderDemo/demo-preview-pages.html +1 -0
  49. package/BookReaderDemo/demo-simple.html +1 -0
  50. package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
  51. package/BookReaderDemo/immersion-1up.html +1 -0
  52. package/BookReaderDemo/immersion-mode.html +1 -0
  53. package/BookReaderDemo/toggle_controls.html +1 -0
  54. package/BookReaderDemo/view_mode.html +1 -0
  55. package/BookReaderDemo/viewmode-cycle.html +1 -2
  56. package/CHANGELOG.md +114 -0
  57. package/babel.config.js +18 -0
  58. package/index.html +3 -0
  59. package/jsconfig.json +19 -0
  60. package/package.json +45 -27
  61. package/src/BookNavigator/assets/button-base.js +8 -1
  62. package/src/BookNavigator/assets/ia-logo.js +17 -0
  63. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  64. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  65. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  66. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  67. package/src/BookNavigator/book-navigator.js +528 -0
  68. package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
  69. package/src/BookNavigator/bookmarks/bookmark-edit.js +2 -1
  70. package/src/BookNavigator/bookmarks/bookmarks-list.js +1 -0
  71. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  72. package/src/BookNavigator/bookmarks/bookmarks-provider.js +32 -11
  73. package/src/BookNavigator/bookmarks/ia-bookmarks.js +88 -43
  74. package/src/BookNavigator/downloads/downloads-provider.js +22 -16
  75. package/src/BookNavigator/downloads/downloads.js +16 -23
  76. package/src/BookNavigator/search/a-search-result.js +1 -0
  77. package/src/BookNavigator/search/search-provider.js +54 -20
  78. package/src/BookNavigator/search/search-results.js +7 -18
  79. package/src/BookNavigator/sharing.js +27 -0
  80. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +10 -12
  81. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +1 -0
  82. package/src/BookNavigator/volumes/volumes-provider.js +114 -0
  83. package/src/BookNavigator/volumes/volumes.js +189 -0
  84. package/src/BookReader/DebugConsole.js +3 -3
  85. package/src/BookReader/DragScrollable.js +233 -0
  86. package/src/BookReader/Mode1Up.js +50 -351
  87. package/src/BookReader/Mode1UpLit.js +434 -0
  88. package/src/BookReader/Mode2Up.js +94 -72
  89. package/src/BookReader/ModeSmoothZoom.js +177 -0
  90. package/src/BookReader/ModeThumb.js +16 -8
  91. package/src/BookReader/Navbar/Navbar.js +2 -31
  92. package/src/BookReader/PageContainer.js +47 -2
  93. package/src/BookReader/ReduceSet.js +1 -1
  94. package/src/BookReader/Toolbar/Toolbar.js +5 -5
  95. package/src/BookReader/options.js +10 -0
  96. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  97. package/src/BookReader/utils.js +68 -13
  98. package/src/BookReader.js +316 -232
  99. package/src/assets/icons/close-circle-dark.svg +1 -0
  100. package/src/assets/icons/voice.svg +1 -0
  101. package/src/css/BookReader.scss +0 -12
  102. package/src/css/_BRComponent.scss +1 -1
  103. package/src/css/_BRmain.scss +19 -24
  104. package/src/css/_BRnav.scss +4 -26
  105. package/src/css/_BRpages.scss +35 -0
  106. package/src/css/_BRsearch.scss +11 -215
  107. package/src/css/_TextSelection.scss +1 -17
  108. package/src/css/_controls.scss +16 -3
  109. package/src/css/_icons.scss +6 -0
  110. package/src/ia-bookreader/ia-bookreader.js +206 -0
  111. package/src/plugins/plugin.chapters.js +15 -18
  112. package/src/plugins/plugin.mobile_nav.js +11 -10
  113. package/src/plugins/plugin.resume.js +3 -3
  114. package/src/plugins/plugin.text_selection.js +17 -29
  115. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  116. package/src/plugins/search/plugin.search.js +113 -104
  117. package/src/plugins/search/view.js +48 -163
  118. package/src/plugins/tts/AbstractTTSEngine.js +7 -0
  119. package/src/plugins/tts/FestivalTTSEngine.js +2 -2
  120. package/src/plugins/tts/WebTTSEngine.js +5 -0
  121. package/src/plugins/tts/plugin.tts.js +67 -102
  122. package/src/plugins/url/UrlPlugin.js +184 -0
  123. package/src/plugins/url/plugin.url.js +220 -0
  124. package/{src → stat}/BookNavigator/BookModel.js +0 -0
  125. package/{src → stat}/BookNavigator/BookNavigator.js +151 -104
  126. package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
  127. package/stat/BookNavigator/assets/button-base.js +61 -0
  128. package/stat/BookNavigator/assets/ia-logo.js +17 -0
  129. package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
  130. package/stat/BookNavigator/assets/icon_close.js +3 -0
  131. package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
  132. package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
  133. package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
  134. package/stat/BookNavigator/assets/icon_volumes.js +11 -0
  135. package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
  136. package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
  137. package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
  138. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
  139. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
  140. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
  141. package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
  142. package/stat/BookNavigator/delete-modal-actions.js +49 -0
  143. package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
  144. package/stat/BookNavigator/downloads/downloads.js +139 -0
  145. package/stat/BookNavigator/provider-config.js +0 -0
  146. package/stat/BookNavigator/search/a-search-result.js +55 -0
  147. package/stat/BookNavigator/search/search-provider.js +180 -0
  148. package/stat/BookNavigator/search/search-results.js +360 -0
  149. package/stat/BookNavigator/sharing.js +31 -0
  150. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
  151. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
  152. package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
  153. package/stat/BookNavigator/volumes/volumes.js +178 -0
  154. package/stat/BookReader/BookModel.js +518 -0
  155. package/stat/BookReader/DebugConsole.js +54 -0
  156. package/stat/BookReader/DragScrollable.js +233 -0
  157. package/stat/BookReader/ImageCache.js +116 -0
  158. package/stat/BookReader/Mode1Up.js +102 -0
  159. package/stat/BookReader/Mode1UpLit.js +434 -0
  160. package/stat/BookReader/Mode2Up.js +1372 -0
  161. package/stat/BookReader/ModeSmoothZoom.js +177 -0
  162. package/stat/BookReader/ModeThumb.js +344 -0
  163. package/stat/BookReader/Navbar/Navbar.js +310 -0
  164. package/stat/BookReader/PageContainer.js +120 -0
  165. package/stat/BookReader/ReduceSet.js +26 -0
  166. package/stat/BookReader/Toolbar/Toolbar.js +384 -0
  167. package/stat/BookReader/events.js +20 -0
  168. package/stat/BookReader/options.js +324 -0
  169. package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  170. package/stat/BookReader/utils/classes.js +36 -0
  171. package/stat/BookReader/utils.js +240 -0
  172. package/stat/BookReader.js +2550 -0
  173. package/{src → stat}/BookReaderComponent/BookReaderComponent.js +16 -11
  174. package/stat/assets/icons/1up.svg +12 -0
  175. package/stat/assets/icons/2up.svg +15 -0
  176. package/stat/assets/icons/advance.svg +26 -0
  177. package/stat/assets/icons/chevron-right.svg +1 -0
  178. package/stat/assets/icons/close-circle-dark.svg +1 -0
  179. package/stat/assets/icons/close-circle.svg +1 -0
  180. package/stat/assets/icons/fullscreen.svg +17 -0
  181. package/stat/assets/icons/fullscreen_exit.svg +17 -0
  182. package/stat/assets/icons/hamburger.svg +15 -0
  183. package/stat/assets/icons/left-arrow.svg +12 -0
  184. package/stat/assets/icons/magnify-minus.svg +16 -0
  185. package/stat/assets/icons/magnify-plus.svg +17 -0
  186. package/stat/assets/icons/magnify.svg +15 -0
  187. package/stat/assets/icons/pause.svg +23 -0
  188. package/stat/assets/icons/play.svg +22 -0
  189. package/stat/assets/icons/playback-speed.svg +34 -0
  190. package/stat/assets/icons/read-aloud.svg +22 -0
  191. package/stat/assets/icons/review.svg +22 -0
  192. package/stat/assets/icons/thumbnails.svg +17 -0
  193. package/stat/assets/icons/voice.svg +1 -0
  194. package/stat/assets/icons/volume-full.svg +22 -0
  195. package/stat/assets/images/BRicons.png +0 -0
  196. package/stat/assets/images/BRicons.svg +94 -0
  197. package/stat/assets/images/BRicons_ia.png +0 -0
  198. package/stat/assets/images/back_pages.png +0 -0
  199. package/stat/assets/images/book_bottom_icon.png +0 -0
  200. package/stat/assets/images/book_down_icon.png +0 -0
  201. package/stat/assets/images/book_left_icon.png +0 -0
  202. package/stat/assets/images/book_leftmost_icon.png +0 -0
  203. package/stat/assets/images/book_right_icon.png +0 -0
  204. package/stat/assets/images/book_rightmost_icon.png +0 -0
  205. package/stat/assets/images/book_top_icon.png +0 -0
  206. package/stat/assets/images/book_up_icon.png +0 -0
  207. package/stat/assets/images/books_graphic.svg +177 -0
  208. package/stat/assets/images/booksplit.png +0 -0
  209. package/stat/assets/images/control_pause_icon.png +0 -0
  210. package/stat/assets/images/control_play_icon.png +0 -0
  211. package/stat/assets/images/embed_icon.png +0 -0
  212. package/stat/assets/images/icon-home-ia.png +0 -0
  213. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  214. package/stat/assets/images/icon_alert-xs.png +0 -0
  215. package/stat/assets/images/icon_book.svg +12 -0
  216. package/stat/assets/images/icon_bookmark.svg +12 -0
  217. package/stat/assets/images/icon_close-pop.png +0 -0
  218. package/stat/assets/images/icon_download.png +0 -0
  219. package/stat/assets/images/icon_gear.svg +14 -0
  220. package/stat/assets/images/icon_hamburger.svg +20 -0
  221. package/stat/assets/images/icon_home.png +0 -0
  222. package/stat/assets/images/icon_home.svg +21 -0
  223. package/stat/assets/images/icon_home_ia.png +0 -0
  224. package/stat/assets/images/icon_indicator.png +0 -0
  225. package/stat/assets/images/icon_info.svg +11 -0
  226. package/stat/assets/images/icon_one_page.svg +8 -0
  227. package/stat/assets/images/icon_pause.svg +1 -0
  228. package/stat/assets/images/icon_play.svg +1 -0
  229. package/stat/assets/images/icon_playback-rate.svg +15 -0
  230. package/stat/assets/images/icon_return.png +0 -0
  231. package/stat/assets/images/icon_search_button.svg +8 -0
  232. package/stat/assets/images/icon_share.svg +9 -0
  233. package/stat/assets/images/icon_skip-ahead.svg +6 -0
  234. package/stat/assets/images/icon_skip-back.svg +13 -0
  235. package/stat/assets/images/icon_speaker.svg +18 -0
  236. package/stat/assets/images/icon_speaker_open.svg +10 -0
  237. package/stat/assets/images/icon_thumbnails.svg +12 -0
  238. package/stat/assets/images/icon_toc.svg +5 -0
  239. package/stat/assets/images/icon_two_pages.svg +9 -0
  240. package/stat/assets/images/icon_zoomer.png +0 -0
  241. package/stat/assets/images/loading.gif +0 -0
  242. package/stat/assets/images/logo_icon.png +0 -0
  243. package/stat/assets/images/marker_chap-off.png +0 -0
  244. package/stat/assets/images/marker_chap-off.svg +11 -0
  245. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  246. package/stat/assets/images/marker_chap-on.png +0 -0
  247. package/stat/assets/images/marker_chap-on.svg +11 -0
  248. package/stat/assets/images/marker_srch-on.svg +11 -0
  249. package/stat/assets/images/marker_srchchap-off.png +0 -0
  250. package/stat/assets/images/marker_srchchap-on.png +0 -0
  251. package/stat/assets/images/nav_control-dn.png +0 -0
  252. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  253. package/stat/assets/images/nav_control-up.png +0 -0
  254. package/stat/assets/images/nav_control-up_ia.png +0 -0
  255. package/stat/assets/images/nav_control.png +0 -0
  256. package/stat/assets/images/one_page_mode_icon.png +0 -0
  257. package/stat/assets/images/paper-badge.png +0 -0
  258. package/stat/assets/images/print_icon.png +0 -0
  259. package/stat/assets/images/progressbar.gif +0 -0
  260. package/stat/assets/images/right_edges.png +0 -0
  261. package/stat/assets/images/slider.png +0 -0
  262. package/stat/assets/images/slider_ia.png +0 -0
  263. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  264. package/stat/assets/images/transparent.png +0 -0
  265. package/stat/assets/images/two_page_mode_icon.png +0 -0
  266. package/stat/assets/images/zoom_in_icon.png +0 -0
  267. package/stat/assets/images/zoom_out_icon.png +0 -0
  268. package/stat/css/BookReader.scss +89 -0
  269. package/stat/css/_BRBookmarks.scss +29 -0
  270. package/stat/css/_BRComponent.scss +13 -0
  271. package/stat/css/_BRfloat.scss +197 -0
  272. package/stat/css/_BRicon.scss +48 -0
  273. package/stat/css/_BRmain.scss +251 -0
  274. package/stat/css/_BRnav.scss +359 -0
  275. package/stat/css/_BRpages.scss +139 -0
  276. package/stat/css/_BRsearch.scss +226 -0
  277. package/stat/css/_BRtoolbar.scss +84 -0
  278. package/stat/css/_BRvendor.scss +5 -0
  279. package/stat/css/_MobileNav.scss +194 -0
  280. package/stat/css/_TextSelection.scss +32 -0
  281. package/stat/css/_colorbox.scss +52 -0
  282. package/stat/css/_controls.scss +253 -0
  283. package/stat/css/_icons.scss +121 -0
  284. package/stat/jquery-wrapper.js +4 -0
  285. package/stat/plugins/plugin.archive_analytics.js +86 -0
  286. package/stat/plugins/plugin.autoplay.js +129 -0
  287. package/stat/plugins/plugin.chapters.js +248 -0
  288. package/stat/plugins/plugin.iframe.js +48 -0
  289. package/stat/plugins/plugin.mobile_nav.js +288 -0
  290. package/stat/plugins/plugin.resume.js +68 -0
  291. package/stat/plugins/plugin.text_selection.js +291 -0
  292. package/{src → stat}/plugins/plugin.url.js +4 -4
  293. package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
  294. package/stat/plugins/search/plugin.search.js +439 -0
  295. package/stat/plugins/search/view.js +439 -0
  296. package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
  297. package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
  298. package/stat/plugins/tts/PageChunk.js +107 -0
  299. package/stat/plugins/tts/PageChunkIterator.js +163 -0
  300. package/stat/plugins/tts/WebTTSEngine.js +357 -0
  301. package/stat/plugins/tts/plugin.tts.js +357 -0
  302. package/stat/plugins/tts/tooltip_dict.js +15 -0
  303. package/stat/plugins/tts/utils.js +91 -0
  304. package/stat/util/browserSniffing.js +30 -0
  305. package/stat/util/debouncer.js +26 -0
  306. package/stat/util/docCookies.js +67 -0
  307. package/stat/util/strings.js +34 -0
  308. package/tests/e2e/README.md +37 -0
  309. package/tests/e2e/autoplay.test.js +2 -2
  310. package/tests/e2e/base.test.js +5 -7
  311. package/tests/e2e/helpers/base.js +8 -3
  312. package/tests/e2e/helpers/debug.js +1 -1
  313. package/tests/e2e/helpers/desktopSearch.js +1 -1
  314. package/tests/e2e/helpers/mobileSearch.js +3 -3
  315. package/tests/e2e/helpers/params.js +17 -0
  316. package/tests/e2e/rightToLeft.test.js +4 -5
  317. package/tests/e2e/viewmode.test.js +30 -31
  318. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
  319. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  320. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  321. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  322. package/tests/jest/BookReader/Mode1UpLit.test.js +87 -0
  323. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
  324. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  325. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  326. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  327. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +74 -2
  328. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  329. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  330. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  331. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  332. package/tests/jest/BookReader/utils.test.js +136 -0
  333. package/tests/jest/BookReader.keyboard.test.js +190 -0
  334. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  335. package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
  336. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  337. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
  338. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
  339. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  340. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  341. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  342. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +14 -24
  343. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  344. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +12 -5
  345. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
  346. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +3 -3
  347. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  348. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  349. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  350. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  351. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
  352. package/tests/jest/plugins/url/UrlPlugin.test.js +175 -0
  353. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  354. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  355. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  356. package/tests/{util → jest/util}/strings.test.js +1 -1
  357. package/tests/{utils.js → jest/utils.js} +38 -0
  358. package/tests/karma/BookNavigator/book-navigator.test.js +485 -0
  359. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  360. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
  361. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +1 -2
  362. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
  363. package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
  364. package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
  365. package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
  366. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
  367. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
  368. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
  369. package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
  370. package/webpack.config.js +11 -5
  371. package/.babelrc +0 -12
  372. package/.dependabot/config.yml +0 -6
  373. package/.testcaferc.json +0 -5
  374. package/BookReader/BookReader.js.LICENSE.txt +0 -72
  375. package/BookReader/bookreader-component-bundle.js +0 -1450
  376. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  377. package/BookReader/bookreader-component-bundle.js.map +0 -1
  378. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  379. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  380. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  381. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +0 -27
  382. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  383. package/src/BookNavigator/assets/book-loader.js +0 -27
  384. package/src/ItemNavigator/ItemNavigator.js +0 -372
  385. package/src/ItemNavigator/providers/sharing.js +0 -29
  386. package/src/dragscrollable-br.js +0 -261
  387. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  388. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  389. package/tests/BookReader/Mode1Up.test.js +0 -164
  390. package/tests/BookReader/utils.test.js +0 -109
  391. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,324 @@
1
+ /** @typedef {import('./BookModel.js').PageNumString} PageNumString */
2
+ /** @typedef {import('./BookModel.js').LeafNum} LeafNum */
3
+
4
+ export const DEFAULT_OPTIONS = {
5
+ /**
6
+ * @type {string} A string, such as "mode/1up". See
7
+ * http://openlibrary.org/dev/docs/bookurls for valid syntax
8
+ */
9
+ defaults: null,
10
+
11
+ /** Padding in 1up */
12
+ padding: 10,
13
+
14
+ /** @type {'full' | 'embed' | 'responsive'} UI mode */
15
+ ui: 'full',
16
+
17
+ /** Controls whether nav/toolbar will autohide */
18
+ uiAutoHide: false,
19
+
20
+ /** thumbnail mode */
21
+ /** number of rows to pre-cache out a view */
22
+ thumbRowBuffer: 1,
23
+ thumbColumns: 6,
24
+ /** number of thumbnails to load at once */
25
+ thumbMaxLoading: 4,
26
+ /** spacing between thumbnails */
27
+ thumbPadding: 10,
28
+ /** min zoom in columns */
29
+ thumbMinZoomColumns: 2,
30
+ /** max zoom out columns */
31
+ thumbMaxZoomColumns: 8,
32
+
33
+ /** @type {number | 'fast' | 'slow'} speed for flip animation */
34
+ flipSpeed: 'fast',
35
+
36
+ showToolbar: true,
37
+ showNavbar: true,
38
+ navBarTitle: '',
39
+
40
+ showLogo: true,
41
+ /** Where the logo links to */
42
+ logoURL: 'https://archive.org',
43
+
44
+ /**
45
+ * Base URL for UI images - should be overridden (before init) by
46
+ * custom implementations.
47
+ * $$$ This is the same directory as the images referenced by relative
48
+ * path in the CSS. Would be better to automagically find that path.
49
+ */
50
+ imagesBaseURL: '/BookReader/images/',
51
+
52
+ /** @type {'pow2' | 'integer'} What reduces are valid for getURI. */
53
+ reduceSet: 'pow2',
54
+
55
+ /**
56
+ * Zoom levels
57
+ * @type {ReductionFactor[]}
58
+ * $$$ provide finer grained zooming, {reduce: 8, autofit: null}, {reduce: 16, autofit: null}
59
+ * The autofit code ensures that fit to width and fit to height will be available
60
+ */
61
+ reductionFactors: [
62
+ {reduce: 0.25, autofit: null},
63
+ {reduce: 0.5, autofit: null},
64
+ {reduce: 1, autofit: null},
65
+ {reduce: 2, autofit: null},
66
+ {reduce: 3, autofit: null},
67
+ {reduce: 4, autofit: null},
68
+ {reduce: 6, autofit: null}
69
+ ],
70
+
71
+ /** Object to hold parameters related to 1up mode */
72
+ onePage: {
73
+ /** @type {AutoFitValues} */
74
+ autofit: 'auto',
75
+ },
76
+
77
+ /** Object to hold parameters related to 2up mode */
78
+ twoPage: {
79
+ /** Width of cover */
80
+ coverInternalPadding: 0,
81
+ /** Padding outside of cover */
82
+ coverExternalPadding: 0,
83
+ /** Width of book spine $$$ consider sizing based on book length */
84
+ bookSpineDivWidth: 64,
85
+ /** @type {AutoFitValues} */
86
+ autofit: 'auto'
87
+ },
88
+
89
+ onePageMinBreakpoint: 800,
90
+
91
+ bookTitle: '',
92
+ /** @type {string} */
93
+ bookUrl: null,
94
+ /** @type {string} */
95
+ bookUrlText: null,
96
+ /** @type {string} */
97
+ bookUrlTitle: null,
98
+ enableBookTitleLink: true,
99
+ /**
100
+ * @type {string} language in ISO 639-1 (PRIVATE: Will also
101
+ * handle language name in English, native name, 639-2/T, or 639-2/B . (archive.org books
102
+ * appear to use 639-2/B ? But I don't think that's a guarantee). See
103
+ * https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes ) */
104
+ bookLanguage: null,
105
+
106
+ /**
107
+ * @type {Array<{label: string, value: *, extraValueClass: string?}>}
108
+ * Fields used to populate the info window
109
+ * @example [
110
+ * {label: 'Title', value: 'Open Library BookReader Presentation'},
111
+ * {label: 'Author', value: 'Internet Archive'},
112
+ * {label: 'Demo Info', value: 'This demo shows how one could use BookReader with their own content.'},
113
+ * ]
114
+ **/
115
+ metadata: [],
116
+ /** @type {string} */
117
+ thumbnail: null,
118
+ /** @type {string} */
119
+ bookUrlMoreInfo: null,
120
+
121
+ /** Experimental Controls (eg b/w) */
122
+ enableExperimentalControls: false,
123
+
124
+ /** CSS selectors */
125
+ /** Where BookReader mounts to */
126
+ el: '#BookReader',
127
+
128
+ /** @type {'lr' | 'rl'} Page progression */
129
+ pageProgression: 'lr',
130
+
131
+ /** The PPI the book is scanned at **/
132
+ ppi: 500,
133
+
134
+ /** Should image downloads be blocked */
135
+ protected: false,
136
+
137
+ /**
138
+ * Settings for individual plugins. Note they have to be imported first.
139
+ * WIP: Most plugins just put their options anywhere in this global options file,
140
+ * but going forward we'll keep them here.
141
+ **/
142
+ plugins: {
143
+ /** @type {import('../plugins/plugin.text_selection.js').TextSelectionPluginOptions} */
144
+ textSelection: null,
145
+ },
146
+
147
+ /**
148
+ * Any variables you want to define. If an option has a StringWithVars type, or
149
+ * has something like `{{server}}/foo.com` in its value, these variables replace
150
+ * the `{{foo}}`.
151
+ * @type { {[var_name: string]: any } }
152
+ */
153
+ vars: {},
154
+
155
+ /**
156
+ * @type {Array<[PageData, PageData]|[PageData]>}
157
+ * Data is a simple way to populate the bookreader
158
+ *
159
+ * Example:
160
+ * ```
161
+ * [
162
+ * // Each child is a spread
163
+ * [
164
+ * {
165
+ * width: 123,
166
+ * height: 123,
167
+ * // Optional: If not provided, include a getPageURI
168
+ * uri: 'https://archive.org/image.jpg',
169
+ * // Optional: Shown instead of leaf number if present.
170
+ * pageNum: '1'
171
+ * },
172
+ * {width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '2'},
173
+ * ]
174
+ * ],
175
+ * ```
176
+ *
177
+ * Note if URI is omitted, a custom getPageURI can be provided. This allows the page
178
+ * URI to the result of a function, which allows for things such as dynamic
179
+ * page scaling.
180
+ */
181
+ data: [],
182
+
183
+ /** Advanced methods for page rendering */
184
+ /** @type {() => number} */
185
+ getNumLeafs: null,
186
+ /** @type {(index: number) => number} */
187
+ getPageWidth: null,
188
+ /** @type {(index: number) => number} */
189
+ getPageHeight: null,
190
+ /** @type {(index: number, reduce: number, rotate: number) => *} */
191
+ getPageURI: null,
192
+
193
+ /**
194
+ * @type {(index: number) => 'L' | 'R'}
195
+ * Return which side, left or right, that a given page should be displayed on
196
+ */
197
+ getPageSide: null,
198
+
199
+ /**
200
+ * @type {(pindex: number) => [number, number]}
201
+ * This function returns the left and right indices for the user-visible
202
+ * spread that contains the given index. The return values may be
203
+ * null if there is no facing page or the index is invalid.
204
+ */
205
+ getSpreadIndices: null,
206
+
207
+ /** @type {(index: number) => string} */
208
+ getPageNum: null,
209
+ /** @type {(index: number) => *} */
210
+ getPageProp: null,
211
+ /** @type {(index: number) => number} */
212
+ leafNumToIndex: null,
213
+
214
+ /**
215
+ * @type {(frameWidth: number|string, frameHeight: number|string, viewParams) => *}
216
+ * Optional: if present, and embed code will be shown in the share dialog
217
+ */
218
+ getEmbedCode: null,
219
+
220
+ controls: {
221
+ bookLeft: {
222
+ visible: true,
223
+ label: 'Flip left',
224
+ className: 'book_left',
225
+ iconClassName: 'left-arrow'
226
+ },
227
+ bookRight: {
228
+ visible: true,
229
+ label: 'Flip right',
230
+ className: 'book_right',
231
+ iconClassName: 'left-arrow hflip'
232
+ },
233
+ onePage: {
234
+ visible: true,
235
+ label: 'One-page view',
236
+ className: 'onepg',
237
+ iconClassName: 'onepg'
238
+ },
239
+ twoPage: {
240
+ visible: true,
241
+ label: 'Two-page view',
242
+ className: 'twopg',
243
+ iconClassName: 'twopg'
244
+ },
245
+ thumbnail: {
246
+ visible: true,
247
+ label: 'Thumbnail view',
248
+ className: 'thumb',
249
+ iconClassName: 'thumb'
250
+ },
251
+ viewmode: {
252
+ visible: true,
253
+ className: 'viewmode',
254
+ excludedModes: [],
255
+ },
256
+ zoomOut: {
257
+ visible: true,
258
+ label: 'Zoom out',
259
+ className: 'zoom_out',
260
+ iconClassName: 'magnify'
261
+ },
262
+ zoomIn: {
263
+ visible: true,
264
+ label: 'Zoom in',
265
+ className: 'zoom_in',
266
+ iconClassName: 'magnify plus'
267
+ },
268
+ fullScreen: {
269
+ visible: true,
270
+ label: 'Toggle fullscreen',
271
+ className: 'full',
272
+ iconClassName: 'fullscreen'
273
+ },
274
+ },
275
+
276
+ /**
277
+ * @type {Boolean}
278
+ * Optional: if true, starts in fullscreen mode
279
+ */
280
+ startFullscreen: false,
281
+
282
+ /**
283
+ * @type {Boolean}
284
+ * On init, by default, we want to handle resizing bookreader
285
+ * when browser window changes size (inc. `orientationchange` event)
286
+ * toggle off if you want to handle this outside of bookreader
287
+ */
288
+ autoResize: true,
289
+
290
+ /**
291
+ * @type {Boolean}
292
+ * On init, by default, we want to use srcSet for images
293
+ */
294
+ useSrcSet: false,
295
+ };
296
+
297
+ /** @typedef {'width' | 'height' | 'auto' | 'none'} AutoFitValues */
298
+
299
+ /**
300
+ * @typedef {object} ReductionFactor
301
+ * @property {number} reduce
302
+ * @property {AutoFitValues} [autofit] If set, the corresponding reduction factors
303
+ * are what will be used when the user tries to autofit by width/height.
304
+ */
305
+
306
+ /**
307
+ * @typedef {Object} PageData
308
+ * @property {number} width
309
+ * @property {number} height
310
+ * @property {string} [uri] If not provided, include a getPageURI
311
+ * @property {PageNumString} [pageNum] Shown instead of leaf number if present
312
+ * @property {LeafNum} [leafNum] Sometimes specified in Internet Archive books
313
+ * @property {number} [ppi] The resolution of the page if different from {@see BookReaderOptions.ppi}
314
+ * @property {'L' | 'R'} [pageSide] PRIVATE; computed automatically
315
+ * @property {boolean} [viewable=true] Set false if page is not viewable. Displays a dummy preview image.
316
+ * @property {number} [unviewablesStart] PRIVATE; index where the chunk of unviewable pages started
317
+ *
318
+ * Note if URI is omitted, a custom getPageURI can be provided. This allows the page
319
+ * URI to the result of a function, which allows for things such as dynamic
320
+ * page scaling.
321
+ */
322
+
323
+ /** @typedef {typeof DEFAULT_OPTIONS} BookReaderOptions */
324
+
@@ -0,0 +1,44 @@
1
+ // @ts-check
2
+ import { debounce } from '../utils';
3
+
4
+ /**
5
+ * Computing these things repeatedly is expensive (the browser needs to
6
+ * do a lot of computations/redrawing to make sure these are correct),
7
+ * so we store them here, and only recompute them when necessary:
8
+ * - window resize could have cause the container to change size
9
+ * - zoom could have cause scrollbars to appear/disappear, changing
10
+ * the client size.
11
+ */
12
+ export class HTMLDimensionsCacher {
13
+ clientWidth = 100;
14
+ clientHeight = 100;
15
+
16
+ boundingClientRect = { top: 0, left: 0 };
17
+
18
+ /**
19
+ * @param {HTMLElement} element
20
+ */
21
+ constructor(element) {
22
+ /** @type {HTMLElement} */
23
+ this.element = element;
24
+ }
25
+
26
+ updateClientSizes = () => {
27
+ const bc = this.element.getBoundingClientRect();
28
+ this.clientWidth = this.element.clientWidth;
29
+ this.clientHeight = this.element.clientHeight;
30
+ this.boundingClientRect.top = bc.top;
31
+ this.boundingClientRect.left = bc.left;
32
+ }
33
+ debouncedUpdateClientSizes = debounce(this.updateClientSizes, 150, false);
34
+
35
+ /** @param {EventTarget} win */
36
+ attachResizeListener(win = window) {
37
+ win.addEventListener('resize', this.debouncedUpdateClientSizes);
38
+ }
39
+
40
+ /** @param {EventTarget} win */
41
+ detachResizeListener(win = window) {
42
+ win.removeEventListener('resize', this.debouncedUpdateClientSizes);
43
+ }
44
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Exposes a function from one class (FromClass) to another (ToClass), in such a way
3
+ * that if the ToClass's method is overridden, the FromClass's method is also overridden.
4
+ * WARNING: This modifies FromClass' prototype! So FromClasses cannot be shared between
5
+ * different ToClasses.
6
+ * @param {new () => TFrom} FromClass the class to get the method from
7
+ * @param {keyof TFrom} fromMethod the method's name in FromClass
8
+ * @param {function(TFrom): TTo} fromTransform how to get the TTo `this` to use when setting the method on TFrom
9
+ * @param {new () => TTo} ToClass the class to add the method to
10
+ * @param {string} toMethod the name of the method to add to TTo (likely will be equal to fromMethod)
11
+ * @param {function(TTo): TFrom} toTransform how to get the TFrom this to use when calling the new method
12
+ * @template TFrom type of FromClass for type-checking/autocomplete
13
+ * @template TTo type of ToClass for type-checking/autocomplete
14
+ */
15
+ export function exposeOverrideable(FromClass, fromMethod, fromTransform, ToClass, toMethod, toTransform) {
16
+ // Wrapper function needed to "capture" the current version of fromMethod
17
+ let wrapper = (fn => {
18
+ return function () {
19
+ return fn.apply(toTransform(this), arguments);
20
+ };
21
+ })(FromClass.prototype[fromMethod]);
22
+
23
+ Object.defineProperty(ToClass.prototype, toMethod, {
24
+ get() { return wrapper; },
25
+ set(overrideFn) {
26
+ // overrideFn expects `this` to be ToClass, so ensure as such
27
+ // But we can also call this method from FromClass; need to ensure
28
+ // it's always called with a ToClass
29
+ FromClass.prototype[fromMethod] = function () {
30
+ const newThis = this instanceof FromClass ? fromTransform(this) : this;
31
+ return overrideFn.apply(newThis, arguments);
32
+ };
33
+ wrapper = overrideFn;
34
+ }
35
+ });
36
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Bind mouse handlers
3
+ * Disable mouse click to avoid selected/highlighted page images
4
+ * @param {JQuery} jObject
5
+ */
6
+ export function disableSelect(jObject) {
7
+ // $$$ check here for right-click and don't disable. Also use jQuery style
8
+ // for stopping propagation. See https://bugs.edge.launchpad.net/gnubook/+bug/362626
9
+ jObject.bind('mousedown', () => false);
10
+ // Special hack for IE7
11
+ jObject[0].onselectstart = () => false;
12
+ }
13
+
14
+ /**
15
+ * @param {number} value
16
+ * @param {number} min
17
+ * @param {number} max
18
+ * @return {number}
19
+ */
20
+ export function clamp(value, min, max) {
21
+ return Math.min(Math.max(value, min), max);
22
+ }
23
+
24
+ /**
25
+ * Given value and maximum, calculate a percentage suitable for CSS
26
+ * @param {number} value
27
+ * @param {number} max
28
+ * @return {string}
29
+ */
30
+ export function cssPercentage(value, max) {
31
+ return ((value / max) * 100) + '%';
32
+ }
33
+
34
+ /**
35
+ * @param {*} value
36
+ * @param {Array} array
37
+ * @return {boolean}
38
+ */
39
+ export function notInArray(value, array) {
40
+ return !array.includes(value);
41
+ }
42
+
43
+ /**
44
+ * Determines the active element, going into shadow doms.
45
+ * @return {Element}
46
+ */
47
+ export function getActiveElement(doc = document, recurseShadowDom = true) {
48
+ const activeElement = doc.activeElement;
49
+ if (recurseShadowDom && activeElement?.shadowRoot) {
50
+ return getActiveElement(activeElement.shadowRoot, true);
51
+ }
52
+ return activeElement;
53
+ }
54
+
55
+ /** Check if an input field/textarea is active. Also checks shadow DOMs. */
56
+ export function isInputActive(doc = document) {
57
+ const activeEl = getActiveElement(doc);
58
+ return activeEl?.tagName == "INPUT" || activeEl?.tagName == "TEXTAREA";
59
+ }
60
+
61
+ /**
62
+ * @param {HTMLIFrameElement} iframe
63
+ * @return {Document}
64
+ */
65
+ export function getIFrameDocument(iframe) {
66
+ // Adapted from http://xkr.us/articles/dom/iframe-document/
67
+ const outer = iframe.contentWindow || iframe.contentDocument;
68
+ return outer.document || outer;
69
+ }
70
+
71
+ /**
72
+ * @param {string} str
73
+ * @return {string}
74
+ */
75
+ export function escapeHTML(str) {
76
+ return str.replace(/&/g,'&amp;')
77
+ .replace(/>/g,'&gt;')
78
+ .replace(/</g,'&lt;')
79
+ .replace(/"/g,'&quot;');
80
+ }
81
+
82
+ /**
83
+ * Decodes a URI component and converts '+' to ' '
84
+ * @param {string} value
85
+ * @return {string}
86
+ */
87
+ export function decodeURIComponentPlus(value) {
88
+ return decodeURIComponent(value).replace(/\+/g, ' ');
89
+ }
90
+
91
+ /**
92
+ * Encodes a URI component and converts ' ' to '+'
93
+ * @param {string|number|boolean} value
94
+ * @return {string};
95
+ */
96
+ export function encodeURIComponentPlus(value) {
97
+ return encodeURIComponent(value).replace(/%20/g, '+');
98
+ }
99
+
100
+ /**
101
+ * @template {Function} T
102
+ * Returns a function, that, as long as it continues to be invoked, will not
103
+ * be triggered. The function will be called after it stops being called for
104
+ * N milliseconds. If `immediate` is passed, trigger the function on the
105
+ * leading edge, instead of the trailing.
106
+ * @see https://davidwalsh.name/javascript-debounce-function
107
+ *
108
+ * @param {T} func
109
+ * @param {number} wait
110
+ * @param {boolean} immediate
111
+ * @return {T}
112
+ */
113
+ export function debounce(func, wait, immediate) {
114
+ let timeout;
115
+ return function() {
116
+ const context = this;
117
+ const args = arguments;
118
+ const later = () => {
119
+ timeout = null;
120
+ if (!immediate) func.apply(context, args);
121
+ };
122
+ const callNow = immediate && !timeout;
123
+ clearTimeout(timeout);
124
+ timeout = setTimeout(later, wait);
125
+ if (callNow) func.apply(context, args);
126
+ };
127
+ }
128
+
129
+ /**
130
+ * @template T
131
+ * Throttle function
132
+ * @see https://remysharp.com/2010/07/21/throttling-function-calls
133
+ * @param {T} fn
134
+ * @param {number} threshold
135
+ * @param {boolean} delay
136
+ * @return {T}
137
+ */
138
+ export function throttle(fn, threshold, delay) {
139
+ threshold || (threshold = 250);
140
+ let last;
141
+ let deferTimer;
142
+ if (delay) last = +new Date;
143
+ return function () {
144
+ const context = this;
145
+ const now = +new Date;
146
+ const args = arguments;
147
+ if (last && now < last + threshold) {
148
+ // hold on to it
149
+ clearTimeout(deferTimer);
150
+ deferTimer = setTimeout(() => {
151
+ last = now;
152
+ fn.apply(context, args);
153
+ }, threshold);
154
+ } else {
155
+ last = now;
156
+ fn.apply(context, args);
157
+ }
158
+ };
159
+ }
160
+
161
+ /**
162
+ * FIXME we need a better way to do this :/ This is not automatically poly-filled by
163
+ * core-js https://github.com/zloirock/core-js/issues/354
164
+ * @param {Window} window
165
+ */
166
+ export function polyfillCustomEvent(window) {
167
+ if (typeof window.CustomEvent === "function") return false;
168
+ window.CustomEvent = PolyfilledCustomEvent;
169
+ }
170
+
171
+ /**
172
+ * https://caniuse.com/customevent has issues on older browsers where it can't be
173
+ * called as a constructor, so we have to use older methods.
174
+ * @param {String} eventName
175
+ * @return {CustomEvent}
176
+ */
177
+ export function PolyfilledCustomEvent(eventName, {bubbles = false, cancelable = false, detail = null} = {}) {
178
+ const event = document.createEvent('CustomEvent');
179
+ event.initCustomEvent(eventName, bubbles, cancelable, detail);
180
+ return event;
181
+ }
182
+
183
+ /*
184
+ * Returns the number pixels something should be rendered at to be ~1n on the users
185
+ * screen when measured with a ruler.
186
+ */
187
+ export function calcScreenDPI() {
188
+ const el = document.createElement('div');
189
+ el.style.width = '1in';
190
+ document.body.appendChild(el);
191
+ const dpi = el.offsetWidth;
192
+ document.body.removeChild(el);
193
+
194
+ // Do you believe in magic... numbers? We tested on some devices, and the displayed
195
+ // size of `width: 1in` was less than desired. On @pezvi's mac, it was ~75% ; on
196
+ // @cdrini's laptop it was ~85%. Since we want to avoid things appearing too small,
197
+ // let's just use a multiplier of 1.25
198
+ const screenDPI = dpi * 1.25;
199
+ // This will return 0 in testing; never want it to be 0!
200
+ return screenDPI == 0 ? 100 : screenDPI;
201
+ }
202
+
203
+ /**
204
+ * @param {number[]} nums
205
+ * @returns {number}
206
+ */
207
+ export function sum(nums) {
208
+ return nums.reduce((cur, acc) => cur + acc, 0);
209
+ }
210
+
211
+ /**
212
+ * @template T
213
+ * @param {Generator<T>} gen
214
+ * @returns {T[]}
215
+ */
216
+ export function genToArray(gen) {
217
+ const result = [];
218
+ for (const item of gen) {
219
+ result.push(item);
220
+ }
221
+ return result;
222
+ }
223
+
224
+ /**
225
+ * Check if arrays contain the same elements. Does reference comparison.
226
+ * @param {Array} arr1
227
+ * @param {Array} arr2
228
+ */
229
+ export function arrEquals(arr1, arr2) {
230
+ return arr1.length == arr2.length && arr1.every((x, i) => x == arr2[i]);
231
+ }
232
+
233
+ /**
234
+ * Check if array has changed; namely to be used with lit's property.hasChanged
235
+ * @param {Array} [arr1]
236
+ * @param {Array} [arr2]
237
+ */
238
+ export function arrChanged(arr1, arr2) {
239
+ return arr1 && arr2 && !arrEquals(arr1, arr2);
240
+ }