@internetarchive/bookreader 5.0.0-18

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 (428) hide show
  1. package/.eslintrc.js +58 -0
  2. package/.gitattributes +2 -0
  3. package/.github/ISSUE_TEMPLATE/bug.md +32 -0
  4. package/.github/ISSUE_TEMPLATE/feature-request.md +30 -0
  5. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +15 -0
  6. package/.github/dependabot.yml +8 -0
  7. package/.github/workflows/node.js.yml +37 -0
  8. package/.github/workflows/npm-publish.yml +47 -0
  9. package/.testcaferc.json +5 -0
  10. package/BookReader/BookReader.css +2983 -0
  11. package/BookReader/BookReader.js +3 -0
  12. package/BookReader/BookReader.js.LICENSE.txt +117 -0
  13. package/BookReader/BookReader.js.map +1 -0
  14. package/BookReader/bookreader-component-bundle.js +1436 -0
  15. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +27 -0
  16. package/BookReader/bookreader-component-bundle.js.map +1 -0
  17. package/BookReader/icons/1up.svg +1 -0
  18. package/BookReader/icons/2up.svg +1 -0
  19. package/BookReader/icons/advance.svg +3 -0
  20. package/BookReader/icons/chevron-right.svg +1 -0
  21. package/BookReader/icons/close-circle-dark.svg +1 -0
  22. package/BookReader/icons/close-circle.svg +1 -0
  23. package/BookReader/icons/fullscreen.svg +1 -0
  24. package/BookReader/icons/fullscreen_exit.svg +1 -0
  25. package/BookReader/icons/hamburger.svg +1 -0
  26. package/BookReader/icons/left-arrow.svg +1 -0
  27. package/BookReader/icons/magnify-minus.svg +1 -0
  28. package/BookReader/icons/magnify-plus.svg +1 -0
  29. package/BookReader/icons/magnify.svg +1 -0
  30. package/BookReader/icons/pause.svg +1 -0
  31. package/BookReader/icons/play.svg +1 -0
  32. package/BookReader/icons/playback-speed.svg +1 -0
  33. package/BookReader/icons/read-aloud.svg +1 -0
  34. package/BookReader/icons/review.svg +3 -0
  35. package/BookReader/icons/thumbnails.svg +1 -0
  36. package/BookReader/icons/volume-full.svg +1 -0
  37. package/BookReader/images/BRicons.png +0 -0
  38. package/BookReader/images/BRicons.svg +5 -0
  39. package/BookReader/images/BRicons_ia.png +0 -0
  40. package/BookReader/images/back_pages.png +0 -0
  41. package/BookReader/images/book_bottom_icon.png +0 -0
  42. package/BookReader/images/book_down_icon.png +0 -0
  43. package/BookReader/images/book_left_icon.png +0 -0
  44. package/BookReader/images/book_leftmost_icon.png +0 -0
  45. package/BookReader/images/book_right_icon.png +0 -0
  46. package/BookReader/images/book_rightmost_icon.png +0 -0
  47. package/BookReader/images/book_top_icon.png +0 -0
  48. package/BookReader/images/book_up_icon.png +0 -0
  49. package/BookReader/images/books_graphic.svg +1 -0
  50. package/BookReader/images/booksplit.png +0 -0
  51. package/BookReader/images/control_pause_icon.png +0 -0
  52. package/BookReader/images/control_play_icon.png +0 -0
  53. package/BookReader/images/embed_icon.png +0 -0
  54. package/BookReader/images/icon-home-ia.png +0 -0
  55. package/BookReader/images/icon_OL-logo-xs.png +0 -0
  56. package/BookReader/images/icon_alert-xs.png +0 -0
  57. package/BookReader/images/icon_book.svg +1 -0
  58. package/BookReader/images/icon_bookmark.svg +1 -0
  59. package/BookReader/images/icon_close-pop.png +0 -0
  60. package/BookReader/images/icon_download.png +0 -0
  61. package/BookReader/images/icon_gear.svg +1 -0
  62. package/BookReader/images/icon_hamburger.svg +1 -0
  63. package/BookReader/images/icon_home.png +0 -0
  64. package/BookReader/images/icon_home.svg +1 -0
  65. package/BookReader/images/icon_home_ia.png +0 -0
  66. package/BookReader/images/icon_indicator.png +0 -0
  67. package/BookReader/images/icon_info.svg +1 -0
  68. package/BookReader/images/icon_one_page.svg +1 -0
  69. package/BookReader/images/icon_pause.svg +1 -0
  70. package/BookReader/images/icon_play.svg +1 -0
  71. package/BookReader/images/icon_playback-rate.svg +1 -0
  72. package/BookReader/images/icon_return.png +0 -0
  73. package/BookReader/images/icon_search_button.svg +1 -0
  74. package/BookReader/images/icon_share.svg +1 -0
  75. package/BookReader/images/icon_skip-ahead.svg +1 -0
  76. package/BookReader/images/icon_skip-back.svg +2 -0
  77. package/BookReader/images/icon_speaker.svg +1 -0
  78. package/BookReader/images/icon_speaker_open.svg +1 -0
  79. package/BookReader/images/icon_thumbnails.svg +1 -0
  80. package/BookReader/images/icon_toc.svg +1 -0
  81. package/BookReader/images/icon_two_pages.svg +1 -0
  82. package/BookReader/images/icon_zoomer.png +0 -0
  83. package/BookReader/images/loading.gif +0 -0
  84. package/BookReader/images/logo_icon.png +0 -0
  85. package/BookReader/images/marker_chap-off.png +0 -0
  86. package/BookReader/images/marker_chap-off.svg +1 -0
  87. package/BookReader/images/marker_chap-off_ia.png +0 -0
  88. package/BookReader/images/marker_chap-on.png +0 -0
  89. package/BookReader/images/marker_chap-on.svg +1 -0
  90. package/BookReader/images/marker_srch-on.svg +1 -0
  91. package/BookReader/images/marker_srchchap-off.png +0 -0
  92. package/BookReader/images/marker_srchchap-on.png +0 -0
  93. package/BookReader/images/nav_control-dn.png +0 -0
  94. package/BookReader/images/nav_control-dn_ia.png +0 -0
  95. package/BookReader/images/nav_control-up.png +0 -0
  96. package/BookReader/images/nav_control-up_ia.png +0 -0
  97. package/BookReader/images/nav_control.png +0 -0
  98. package/BookReader/images/one_page_mode_icon.png +0 -0
  99. package/BookReader/images/paper-badge.png +0 -0
  100. package/BookReader/images/print_icon.png +0 -0
  101. package/BookReader/images/progressbar.gif +0 -0
  102. package/BookReader/images/right_edges.png +0 -0
  103. package/BookReader/images/slider.png +0 -0
  104. package/BookReader/images/slider_ia.png +0 -0
  105. package/BookReader/images/thumbnail_mode_icon.png +0 -0
  106. package/BookReader/images/transparent.png +0 -0
  107. package/BookReader/images/two_page_mode_icon.png +0 -0
  108. package/BookReader/images/zoom_in_icon.png +0 -0
  109. package/BookReader/images/zoom_out_icon.png +0 -0
  110. package/BookReader/jquery-1.10.1.js +2 -0
  111. package/BookReader/jquery-1.10.1.js.LICENSE.txt +24 -0
  112. package/BookReader/plugins/plugin.archive_analytics.js +2 -0
  113. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -0
  114. package/BookReader/plugins/plugin.autoplay.js +2 -0
  115. package/BookReader/plugins/plugin.autoplay.js.map +1 -0
  116. package/BookReader/plugins/plugin.chapters.js +2 -0
  117. package/BookReader/plugins/plugin.chapters.js.map +1 -0
  118. package/BookReader/plugins/plugin.iframe.js +2 -0
  119. package/BookReader/plugins/plugin.iframe.js.map +1 -0
  120. package/BookReader/plugins/plugin.mobile_nav.js +2 -0
  121. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -0
  122. package/BookReader/plugins/plugin.resume.js +2 -0
  123. package/BookReader/plugins/plugin.resume.js.map +1 -0
  124. package/BookReader/plugins/plugin.search.js +2 -0
  125. package/BookReader/plugins/plugin.search.js.map +1 -0
  126. package/BookReader/plugins/plugin.text_selection.js +2 -0
  127. package/BookReader/plugins/plugin.text_selection.js.map +1 -0
  128. package/BookReader/plugins/plugin.tts.js +3 -0
  129. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +27 -0
  130. package/BookReader/plugins/plugin.tts.js.map +1 -0
  131. package/BookReader/plugins/plugin.url.js +2 -0
  132. package/BookReader/plugins/plugin.url.js.map +1 -0
  133. package/BookReader/plugins/plugin.vendor-fullscreen.js +2 -0
  134. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -0
  135. package/BookReaderDemo/BookReaderDemo.css +41 -0
  136. package/BookReaderDemo/BookReaderJSAdvanced.js +115 -0
  137. package/BookReaderDemo/BookReaderJSAutoplay.js +56 -0
  138. package/BookReaderDemo/BookReaderJSSimple.js +55 -0
  139. package/BookReaderDemo/IIIFBookReader.js +207 -0
  140. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +1 -0
  141. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +1 -0
  142. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  143. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  144. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  145. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +1 -0
  146. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +1 -0
  147. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  148. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  149. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  150. package/BookReaderDemo/bookreader-template-bundle.js +7178 -0
  151. package/BookReaderDemo/demo-advanced.html +32 -0
  152. package/BookReaderDemo/demo-autoplay.html +38 -0
  153. package/BookReaderDemo/demo-embed-iframe-src.html +84 -0
  154. package/BookReaderDemo/demo-embed.html +26 -0
  155. package/BookReaderDemo/demo-fullscreen-mobile.html +36 -0
  156. package/BookReaderDemo/demo-fullscreen.html +33 -0
  157. package/BookReaderDemo/demo-iiif.html +34 -0
  158. package/BookReaderDemo/demo-iiif.js +26 -0
  159. package/BookReaderDemo/demo-internetarchive.html +74 -0
  160. package/BookReaderDemo/demo-multiple.html +43 -0
  161. package/BookReaderDemo/demo-preview-pages.html +1092 -0
  162. package/BookReaderDemo/demo-simple.html +34 -0
  163. package/BookReaderDemo/demo-vendor-fullscreen.html +36 -0
  164. package/BookReaderDemo/immersion-1up.html +64 -0
  165. package/BookReaderDemo/immersion-mode.html +35 -0
  166. package/BookReaderDemo/toggle_controls.html +53 -0
  167. package/BookReaderDemo/view_mode.html +39 -0
  168. package/BookReaderDemo/viewmode-cycle.html +41 -0
  169. package/CHANGELOG.md +540 -0
  170. package/CONTRIBUTING.md +7 -0
  171. package/LICENSE +661 -0
  172. package/README.md +205 -0
  173. package/babel.config.js +18 -0
  174. package/codecov.yml +17 -0
  175. package/index.html +31 -0
  176. package/jsconfig.json +14 -0
  177. package/karma.conf.js +23 -0
  178. package/package.json +129 -0
  179. package/screenshot.png +0 -0
  180. package/scripts/postversion.js +10 -0
  181. package/scripts/preversion.js +14 -0
  182. package/scripts/version.js +26 -0
  183. package/src/BookNavigator/BookModel.js +14 -0
  184. package/src/BookNavigator/BookNavigator.js +468 -0
  185. package/src/BookNavigator/assets/book-loader.js +27 -0
  186. package/src/BookNavigator/assets/bookmark-colors.js +15 -0
  187. package/src/BookNavigator/assets/button-base.js +61 -0
  188. package/src/BookNavigator/assets/icon_checkmark.js +6 -0
  189. package/src/BookNavigator/assets/icon_close.js +3 -0
  190. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  191. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  192. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  193. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  194. package/src/BookNavigator/bookmarks/bookmark-button.js +64 -0
  195. package/src/BookNavigator/bookmarks/bookmark-edit.js +215 -0
  196. package/src/BookNavigator/bookmarks/bookmarks-list.js +285 -0
  197. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
  198. package/src/BookNavigator/bookmarks/bookmarks-provider.js +53 -0
  199. package/src/BookNavigator/bookmarks/ia-bookmarks.js +500 -0
  200. package/src/BookNavigator/br-fullscreen-mgr.js +83 -0
  201. package/src/BookNavigator/delete-modal-actions.js +49 -0
  202. package/src/BookNavigator/downloads/downloads-provider.js +76 -0
  203. package/src/BookNavigator/downloads/downloads.js +138 -0
  204. package/src/BookNavigator/search/a-search-result.js +55 -0
  205. package/src/BookNavigator/search/search-provider.js +180 -0
  206. package/src/BookNavigator/search/search-results.js +360 -0
  207. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +93 -0
  208. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
  209. package/src/BookNavigator/volumes/volumes-provider.js +83 -0
  210. package/src/BookNavigator/volumes/volumes.js +178 -0
  211. package/src/BookReader/BookModel.js +518 -0
  212. package/src/BookReader/DebugConsole.js +54 -0
  213. package/src/BookReader/ImageCache.js +116 -0
  214. package/src/BookReader/Mode1Up.js +90 -0
  215. package/src/BookReader/Mode1UpLit.js +434 -0
  216. package/src/BookReader/Mode2Up.js +1372 -0
  217. package/src/BookReader/ModeSmoothZoom.js +177 -0
  218. package/src/BookReader/ModeThumb.js +336 -0
  219. package/src/BookReader/Navbar/Navbar.js +339 -0
  220. package/src/BookReader/PageContainer.js +120 -0
  221. package/src/BookReader/ReduceSet.js +26 -0
  222. package/src/BookReader/Toolbar/Toolbar.js +384 -0
  223. package/src/BookReader/events.js +20 -0
  224. package/src/BookReader/options.js +320 -0
  225. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  226. package/src/BookReader/utils/classes.js +36 -0
  227. package/src/BookReader/utils.js +240 -0
  228. package/src/BookReader.js +2546 -0
  229. package/src/BookReaderComponent/BookReaderComponent.js +112 -0
  230. package/src/ItemNavigator/ItemNavigator.js +376 -0
  231. package/src/ItemNavigator/providers/sharing.js +33 -0
  232. package/src/assets/icons/1up.svg +12 -0
  233. package/src/assets/icons/2up.svg +15 -0
  234. package/src/assets/icons/advance.svg +26 -0
  235. package/src/assets/icons/chevron-right.svg +1 -0
  236. package/src/assets/icons/close-circle-dark.svg +1 -0
  237. package/src/assets/icons/close-circle.svg +1 -0
  238. package/src/assets/icons/fullscreen.svg +17 -0
  239. package/src/assets/icons/fullscreen_exit.svg +17 -0
  240. package/src/assets/icons/hamburger.svg +15 -0
  241. package/src/assets/icons/left-arrow.svg +12 -0
  242. package/src/assets/icons/magnify-minus.svg +16 -0
  243. package/src/assets/icons/magnify-plus.svg +17 -0
  244. package/src/assets/icons/magnify.svg +15 -0
  245. package/src/assets/icons/pause.svg +23 -0
  246. package/src/assets/icons/play.svg +22 -0
  247. package/src/assets/icons/playback-speed.svg +34 -0
  248. package/src/assets/icons/read-aloud.svg +22 -0
  249. package/src/assets/icons/review.svg +22 -0
  250. package/src/assets/icons/thumbnails.svg +17 -0
  251. package/src/assets/icons/volume-full.svg +22 -0
  252. package/src/assets/images/BRicons.png +0 -0
  253. package/src/assets/images/BRicons.svg +94 -0
  254. package/src/assets/images/BRicons_ia.png +0 -0
  255. package/src/assets/images/back_pages.png +0 -0
  256. package/src/assets/images/book_bottom_icon.png +0 -0
  257. package/src/assets/images/book_down_icon.png +0 -0
  258. package/src/assets/images/book_left_icon.png +0 -0
  259. package/src/assets/images/book_leftmost_icon.png +0 -0
  260. package/src/assets/images/book_right_icon.png +0 -0
  261. package/src/assets/images/book_rightmost_icon.png +0 -0
  262. package/src/assets/images/book_top_icon.png +0 -0
  263. package/src/assets/images/book_up_icon.png +0 -0
  264. package/src/assets/images/books_graphic.svg +177 -0
  265. package/src/assets/images/booksplit.png +0 -0
  266. package/src/assets/images/control_pause_icon.png +0 -0
  267. package/src/assets/images/control_play_icon.png +0 -0
  268. package/src/assets/images/embed_icon.png +0 -0
  269. package/src/assets/images/icon-home-ia.png +0 -0
  270. package/src/assets/images/icon_OL-logo-xs.png +0 -0
  271. package/src/assets/images/icon_alert-xs.png +0 -0
  272. package/src/assets/images/icon_book.svg +12 -0
  273. package/src/assets/images/icon_bookmark.svg +12 -0
  274. package/src/assets/images/icon_close-pop.png +0 -0
  275. package/src/assets/images/icon_download.png +0 -0
  276. package/src/assets/images/icon_gear.svg +14 -0
  277. package/src/assets/images/icon_hamburger.svg +20 -0
  278. package/src/assets/images/icon_home.png +0 -0
  279. package/src/assets/images/icon_home.svg +21 -0
  280. package/src/assets/images/icon_home_ia.png +0 -0
  281. package/src/assets/images/icon_indicator.png +0 -0
  282. package/src/assets/images/icon_info.svg +11 -0
  283. package/src/assets/images/icon_one_page.svg +8 -0
  284. package/src/assets/images/icon_pause.svg +1 -0
  285. package/src/assets/images/icon_play.svg +1 -0
  286. package/src/assets/images/icon_playback-rate.svg +15 -0
  287. package/src/assets/images/icon_return.png +0 -0
  288. package/src/assets/images/icon_search_button.svg +8 -0
  289. package/src/assets/images/icon_share.svg +9 -0
  290. package/src/assets/images/icon_skip-ahead.svg +6 -0
  291. package/src/assets/images/icon_skip-back.svg +13 -0
  292. package/src/assets/images/icon_speaker.svg +18 -0
  293. package/src/assets/images/icon_speaker_open.svg +10 -0
  294. package/src/assets/images/icon_thumbnails.svg +12 -0
  295. package/src/assets/images/icon_toc.svg +5 -0
  296. package/src/assets/images/icon_two_pages.svg +9 -0
  297. package/src/assets/images/icon_zoomer.png +0 -0
  298. package/src/assets/images/loading.gif +0 -0
  299. package/src/assets/images/logo_icon.png +0 -0
  300. package/src/assets/images/marker_chap-off.png +0 -0
  301. package/src/assets/images/marker_chap-off.svg +11 -0
  302. package/src/assets/images/marker_chap-off_ia.png +0 -0
  303. package/src/assets/images/marker_chap-on.png +0 -0
  304. package/src/assets/images/marker_chap-on.svg +11 -0
  305. package/src/assets/images/marker_srch-on.svg +11 -0
  306. package/src/assets/images/marker_srchchap-off.png +0 -0
  307. package/src/assets/images/marker_srchchap-on.png +0 -0
  308. package/src/assets/images/nav_control-dn.png +0 -0
  309. package/src/assets/images/nav_control-dn_ia.png +0 -0
  310. package/src/assets/images/nav_control-up.png +0 -0
  311. package/src/assets/images/nav_control-up_ia.png +0 -0
  312. package/src/assets/images/nav_control.png +0 -0
  313. package/src/assets/images/one_page_mode_icon.png +0 -0
  314. package/src/assets/images/paper-badge.png +0 -0
  315. package/src/assets/images/print_icon.png +0 -0
  316. package/src/assets/images/progressbar.gif +0 -0
  317. package/src/assets/images/right_edges.png +0 -0
  318. package/src/assets/images/slider.png +0 -0
  319. package/src/assets/images/slider_ia.png +0 -0
  320. package/src/assets/images/thumbnail_mode_icon.png +0 -0
  321. package/src/assets/images/transparent.png +0 -0
  322. package/src/assets/images/two_page_mode_icon.png +0 -0
  323. package/src/assets/images/zoom_in_icon.png +0 -0
  324. package/src/assets/images/zoom_out_icon.png +0 -0
  325. package/src/css/BookReader.scss +89 -0
  326. package/src/css/_BRBookmarks.scss +29 -0
  327. package/src/css/_BRComponent.scss +13 -0
  328. package/src/css/_BRfloat.scss +197 -0
  329. package/src/css/_BRicon.scss +48 -0
  330. package/src/css/_BRmain.scss +251 -0
  331. package/src/css/_BRnav.scss +382 -0
  332. package/src/css/_BRpages.scss +139 -0
  333. package/src/css/_BRsearch.scss +226 -0
  334. package/src/css/_BRtoolbar.scss +84 -0
  335. package/src/css/_BRvendor.scss +5 -0
  336. package/src/css/_MobileNav.scss +194 -0
  337. package/src/css/_TextSelection.scss +32 -0
  338. package/src/css/_colorbox.scss +52 -0
  339. package/src/css/_controls.scss +244 -0
  340. package/src/css/_icons.scss +121 -0
  341. package/src/dragscrollable-br.js +261 -0
  342. package/src/jquery-wrapper.js +4 -0
  343. package/src/plugins/plugin.archive_analytics.js +86 -0
  344. package/src/plugins/plugin.autoplay.js +129 -0
  345. package/src/plugins/plugin.chapters.js +251 -0
  346. package/src/plugins/plugin.iframe.js +48 -0
  347. package/src/plugins/plugin.mobile_nav.js +287 -0
  348. package/src/plugins/plugin.resume.js +68 -0
  349. package/src/plugins/plugin.text_selection.js +291 -0
  350. package/src/plugins/plugin.url.js +198 -0
  351. package/src/plugins/plugin.vendor-fullscreen.js +247 -0
  352. package/src/plugins/search/plugin.search.js +439 -0
  353. package/src/plugins/search/view.js +440 -0
  354. package/src/plugins/tts/AbstractTTSEngine.js +242 -0
  355. package/src/plugins/tts/FestivalTTSEngine.js +169 -0
  356. package/src/plugins/tts/PageChunk.js +107 -0
  357. package/src/plugins/tts/PageChunkIterator.js +163 -0
  358. package/src/plugins/tts/WebTTSEngine.js +352 -0
  359. package/src/plugins/tts/plugin.tts.js +335 -0
  360. package/src/plugins/tts/tooltip_dict.js +15 -0
  361. package/src/plugins/tts/utils.js +91 -0
  362. package/src/util/browserSniffing.js +30 -0
  363. package/src/util/debouncer.js +26 -0
  364. package/src/util/docCookies.js +67 -0
  365. package/src/util/strings.js +34 -0
  366. package/tests/BookReader/BookModel.test.js +312 -0
  367. package/tests/BookReader/BookReaderPublicFunctions.test.js +164 -0
  368. package/tests/BookReader/DebugConsole.test.js +25 -0
  369. package/tests/BookReader/ImageCache.test.js +150 -0
  370. package/tests/BookReader/Mode1UpLit.test.js +87 -0
  371. package/tests/BookReader/Mode2Up.test.js +245 -0
  372. package/tests/BookReader/ModeSmoothZoom.test.js +149 -0
  373. package/tests/BookReader/Navbar/Navbar.test.js +169 -0
  374. package/tests/BookReader/PageContainer.test.js +187 -0
  375. package/tests/BookReader/ReduceSet.test.js +38 -0
  376. package/tests/BookReader/Toolbar/Toolbar.test.js +26 -0
  377. package/tests/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  378. package/tests/BookReader/utils/classes.test.js +88 -0
  379. package/tests/BookReader/utils.test.js +136 -0
  380. package/tests/BookReader.options.test.js +39 -0
  381. package/tests/BookReader.test.js +301 -0
  382. package/tests/e2e/README.md +75 -0
  383. package/tests/e2e/autoplay.test.js +13 -0
  384. package/tests/e2e/base.test.js +35 -0
  385. package/tests/e2e/helpers/base.js +263 -0
  386. package/tests/e2e/helpers/debug.js +13 -0
  387. package/tests/e2e/helpers/desktopSearch.js +72 -0
  388. package/tests/e2e/helpers/mobileSearch.js +85 -0
  389. package/tests/e2e/helpers/mockSearch.js +93 -0
  390. package/tests/e2e/helpers/rightToLeft.js +29 -0
  391. package/tests/e2e/ia-production/ia-prod-base.js +17 -0
  392. package/tests/e2e/models/BookReader.js +11 -0
  393. package/tests/e2e/models/Navigation.js +56 -0
  394. package/tests/e2e/rightToLeft.test.js +20 -0
  395. package/tests/e2e/viewmode.test.js +37 -0
  396. package/tests/karma/BookNavigator/book-navigator.test.js +180 -0
  397. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +133 -0
  398. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +222 -0
  399. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +64 -0
  400. package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
  401. package/tests/karma/BookNavigator/search/search-provider.test.js +23 -0
  402. package/tests/karma/BookNavigator/search/search-results.test.js +240 -0
  403. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +40 -0
  404. package/tests/karma/BookNavigator/visual-adjustments.test.js +201 -0
  405. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +160 -0
  406. package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
  407. package/tests/plugins/plugin.archive_analytics.test.js +23 -0
  408. package/tests/plugins/plugin.autoplay.test.js +52 -0
  409. package/tests/plugins/plugin.chapters.test.js +130 -0
  410. package/tests/plugins/plugin.iframe.test.js +42 -0
  411. package/tests/plugins/plugin.mobile_nav.test.js +66 -0
  412. package/tests/plugins/plugin.resume.test.js +98 -0
  413. package/tests/plugins/plugin.text_selection.test.js +193 -0
  414. package/tests/plugins/plugin.url.test.js +129 -0
  415. package/tests/plugins/plugin.vendor-fullscreen.test.js +65 -0
  416. package/tests/plugins/search/plugin.search.test.js +173 -0
  417. package/tests/plugins/search/plugin.search.view.test.js +106 -0
  418. package/tests/plugins/tts/AbstractTTSEngine.test.js +153 -0
  419. package/tests/plugins/tts/FestivalTTSEngine.test.js +59 -0
  420. package/tests/plugins/tts/PageChunk.test.js +57 -0
  421. package/tests/plugins/tts/PageChunkIterator.test.js +179 -0
  422. package/tests/plugins/tts/WebTTSEngine.test.js +126 -0
  423. package/tests/plugins/tts/utils.test.js +133 -0
  424. package/tests/util/browserSniffing.test.js +56 -0
  425. package/tests/util/docCookies.test.js +15 -0
  426. package/tests/util/strings.test.js +63 -0
  427. package/tests/utils.js +80 -0
  428. package/webpack.config.js +85 -0
@@ -0,0 +1,335 @@
1
+ /* global BookReader */
2
+ /**
3
+ * Plugin for Text to Speech in BookReader
4
+ */
5
+ import FestivalTTSEngine from './FestivalTTSEngine.js';
6
+ import WebTTSEngine from './WebTTSEngine.js';
7
+ import { toISO6391, approximateWordCount } from './utils.js';
8
+ import { en as tooltips } from './tooltip_dict.js';
9
+ import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
10
+ /** @typedef {import('./PageChunk.js').default} PageChunk */
11
+ /** @typedef {import("./AbstractTTSEngine.js").default} AbstractTTSEngine */
12
+
13
+ // Default options for TTS
14
+ jQuery.extend(BookReader.defaultOptions, {
15
+ server: 'ia600609.us.archive.org',
16
+ bookPath: '',
17
+ enableTtsPlugin: true,
18
+ });
19
+
20
+ // Extend the constructor to add TTS properties
21
+ BookReader.prototype.setup = (function (super_) {
22
+ return function (options) {
23
+ super_.call(this, options);
24
+
25
+ if (this.options.enableTtsPlugin) {
26
+ /** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */
27
+ this._ttsBoxesByIndex = {};
28
+
29
+ let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :
30
+ FestivalTTSEngine.isSupported() ? FestivalTTSEngine :
31
+ null;
32
+
33
+ if (/_forceTTSEngine=(festival|web)/.test(location.toString())) {
34
+ const engineName = location.toString().match(/_forceTTSEngine=(festival|web)/)[1];
35
+ TTSEngine = { festival: FestivalTTSEngine, web: WebTTSEngine }[engineName];
36
+ }
37
+
38
+ if (TTSEngine) {
39
+ /** @type {AbstractTTSEngine} */
40
+ this.ttsEngine = new TTSEngine({
41
+ server: options.server,
42
+ bookPath: options.bookPath,
43
+ bookLanguage: toISO6391(options.bookLanguage),
44
+ onLoadingStart: this.showProgressPopup.bind(this, 'Loading audio...'),
45
+ onLoadingComplete: this.removeProgressPopup.bind(this),
46
+ onDone: this.ttsStop.bind(this),
47
+ beforeChunkPlay: this.ttsBeforeChunkPlay.bind(this),
48
+ afterChunkPlay: this.ttsSendChunkFinishedAnalyticsEvent.bind(this),
49
+ });
50
+ }
51
+ }
52
+ };
53
+ })(BookReader.prototype.setup);
54
+
55
+ BookReader.prototype.init = (function(super_) {
56
+ return function() {
57
+ if (this.options.enableTtsPlugin) {
58
+ // Bind to events
59
+
60
+ this.bind(BookReader.eventNames.PostInit, () => {
61
+ this.$('.BRicon.read').click(() => {
62
+ this.ttsToggle();
63
+ return false;
64
+ });
65
+ if (this.ttsEngine) {
66
+ this.ttsEngine.init();
67
+ if (/[?&]_autoReadAloud=show/.test(location.toString())) {
68
+ this.ttsStart(false); // false flag is to initiate read aloud controls
69
+ }
70
+ }
71
+ });
72
+
73
+ // This is fired when the hash changes by one of the other plugins!
74
+ // i.e. it will fire every time the page changes -_-
75
+ // this.bind(BookReader.eventNames.stop, function(e, br) {
76
+ // this.ttsStop();
77
+ // }.bind(this));
78
+ }
79
+ super_.call(this);
80
+ };
81
+ })(BookReader.prototype.init);
82
+
83
+ /** @override */
84
+ BookReader.prototype._createPageContainer = (function (super_) {
85
+ return function (index) {
86
+ const pageContainer = super_.call(this, index);
87
+ if (this.options.enableTtsPlugin && pageContainer.page && index in this._ttsBoxesByIndex) {
88
+ const pageIndex = pageContainer.page.index;
89
+ renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);
90
+ }
91
+ return pageContainer;
92
+ };
93
+ })(BookReader.prototype._createPageContainer);
94
+
95
+ // Extend buildMobileDrawerElement
96
+ BookReader.prototype.buildMobileDrawerElement = (function (super_) {
97
+ return function () {
98
+ const $el = super_.call(this);
99
+ if (this.options.enableTtsPlugin && this.ttsEngine) {
100
+ $el.find('.BRmobileMenu__moreInfoRow').after($(`
101
+ <li>
102
+ <span>
103
+ <span class="DrawerIconWrapper"><img class="DrawerIcon" src="${this.imagesBaseURL}icon_speaker_open.svg" alt="info-speaker"/></span>
104
+ Read Aloud
105
+ </span>
106
+ <div>
107
+ <span class="larger">Press to toggle read aloud</span>
108
+ <br/>
109
+ <button class="BRicon read"></button>
110
+ </div>
111
+ </li>`));
112
+ }
113
+ return $el;
114
+ };
115
+ })(BookReader.prototype.buildMobileDrawerElement);
116
+
117
+ // Extend initNavbar
118
+ BookReader.prototype.initNavbar = (function (super_) {
119
+ return function () {
120
+ const $el = super_.call(this);
121
+ if (this.options.enableTtsPlugin && this.ttsEngine) {
122
+ this.refs.$BRReadAloudToolbar = $(`
123
+ <ul class="read-aloud">
124
+ <li>
125
+ <select class="playback-speed" name="playback-speed" title="${tooltips.playbackSpeed}">
126
+ <option value="0.25">0.25x</option>
127
+ <option value="0.5">0.5x</option>
128
+ <option value="0.75">0.75x</option>
129
+ <option value="1.0" selected>1.0x</option>
130
+ <option value="1.25">1.25x</option>
131
+ <option value="1.5">1.5x</option>
132
+ <option value="1.75">1.75x</option>
133
+ <option value="2">2x</option>
134
+ </select>
135
+ </li>
136
+ <li>
137
+ <button type="button" name="review" title="${tooltips.review}">
138
+ <div class="icon icon-review"></div>
139
+ </button>
140
+ </li>
141
+ <li>
142
+ <button type="button" name="play" title="${tooltips.play}">
143
+ <div class="icon icon-play"></div>
144
+ <div class="icon icon-pause"></div>
145
+ </button>
146
+ </li>
147
+ <li>
148
+ <button type="button" name="advance" title="${tooltips.advance}">
149
+ <div class="icon icon-advance"></div>
150
+ </button>
151
+ </li>
152
+ </ul>
153
+ `);
154
+ $el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);
155
+ this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());
156
+ this.refs.$BRReadAloudToolbar.find('[name=play]').click(this.ttsPlayPause.bind(this));
157
+ this.refs.$BRReadAloudToolbar.find('[name=advance]').click(this.ttsJumpForward.bind(this));
158
+ this.refs.$BRReadAloudToolbar.find('[name=review]').click(this.ttsJumpBackward.bind(this));
159
+ const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name="playback-speed"]');
160
+ $rateSelector.change(ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));
161
+ $(`<li>
162
+ <button class="BRicon read js-tooltip" title="${tooltips.readAloud}">
163
+ <div class="icon icon-read-aloud"></div>
164
+ <span class="tooltip">${tooltips.readAloud}</span>
165
+ </button>
166
+ </li>`).insertBefore($el.find('.BRcontrols .BRicon.zoom_out').closest('li'));
167
+ }
168
+ return $el;
169
+ };
170
+ })(BookReader.prototype.initNavbar);
171
+
172
+ // ttsToggle()
173
+ //______________________________________________________________________________
174
+ BookReader.prototype.ttsToggle = function () {
175
+ if (this.autoStop) this.autoStop();
176
+ if (this.ttsEngine.playing) {
177
+ this.ttsStop();
178
+ } else {
179
+ this.ttsStart();
180
+ }
181
+ };
182
+
183
+ // ttsStart(
184
+ //______________________________________________________________________________
185
+ BookReader.prototype.ttsStart = function (startTTSEngine = true) {
186
+ if (this.constModeThumb == this.mode)
187
+ this.switchMode(this.constMode1up);
188
+
189
+ this.refs.$BRReadAloudToolbar.addClass('visible');
190
+ this.$('.BRicon.read').addClass('unread active');
191
+ this.ttsSendAnalyticsEvent('Start');
192
+ if (startTTSEngine)
193
+ this.ttsEngine.start(this.currentIndex(), this.getNumLeafs());
194
+ };
195
+
196
+ BookReader.prototype.ttsJumpForward = function () {
197
+ if (this.ttsEngine.paused) {
198
+ this.ttsEngine.resume();
199
+ }
200
+ this.ttsEngine.jumpForward();
201
+ };
202
+
203
+ BookReader.prototype.ttsJumpBackward = function () {
204
+ if (this.ttsEngine.paused) {
205
+ this.ttsEngine.resume();
206
+ }
207
+ this.ttsEngine.jumpBackward();
208
+ };
209
+
210
+ BookReader.prototype.ttsUpdateState = function() {
211
+ const isPlaying = !(this.ttsEngine.paused || !this.ttsEngine.playing);
212
+ this.$('.read-aloud [name=play]').toggleClass('playing', isPlaying);
213
+ };
214
+
215
+ BookReader.prototype.ttsPlayPause = function() {
216
+ if (!this.ttsEngine.playing) {
217
+ this.ttsToggle();
218
+ } else {
219
+ this.ttsEngine.togglePlayPause();
220
+ this.ttsUpdateState(this.ttsEngine.paused);
221
+ }
222
+ };
223
+
224
+ // ttsStop()
225
+ //______________________________________________________________________________
226
+ BookReader.prototype.ttsStop = function () {
227
+ this.refs.$BRReadAloudToolbar.removeClass('visible');
228
+ this.$('.BRicon.read').removeClass('unread active');
229
+ this.ttsSendAnalyticsEvent('Stop');
230
+ this.ttsEngine.stop();
231
+ this.ttsRemoveHilites();
232
+ this.removeProgressPopup();
233
+ };
234
+
235
+ /**
236
+ * @param {PageChunk} chunk
237
+ * @return {PromiseLike<void>} returns once the flip is done
238
+ */
239
+ BookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {
240
+ await this.ttsMaybeFlipToIndex(chunk.leafIndex);
241
+ this.ttsHighlightChunk(chunk);
242
+ // This appears not to work; ttsMaybeFlipToIndex causes a scroll to the top of
243
+ // the active page :/ Disabling cause the extra scroll just adds an odd jitter.
244
+ // this.ttsScrollToChunk(chunk);
245
+ };
246
+
247
+ /**
248
+ * @param {PageChunk} chunk
249
+ */
250
+ BookReader.prototype.ttsSendChunkFinishedAnalyticsEvent = function(chunk) {
251
+ this.ttsSendAnalyticsEvent('ChunkFinished-Words', approximateWordCount(chunk.text));
252
+ };
253
+
254
+ /**
255
+ * Flip the page if the provided leaf index is not visible
256
+ * @param {Number} leafIndex
257
+ * @return {PromiseLike<void>} resolves once the flip animation has completed
258
+ */
259
+ BookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {
260
+ const in2PageMode = this.constMode2up == this.mode;
261
+ let resolve = null;
262
+ const promise = new Promise(res => resolve = res);
263
+
264
+ if (!in2PageMode) {
265
+ this.jumpToIndex(leafIndex);
266
+ resolve();
267
+ } else {
268
+ const leafVisible = leafIndex == this.twoPage.currentIndexR || leafIndex == this.twoPage.currentIndexL;
269
+ if (leafVisible) {
270
+ resolve();
271
+ } else {
272
+ this.animationFinishedCallback = resolve;
273
+ const mustGoNext = leafIndex > Math.max(this.twoPage.currentIndexR, this.twoPage.currentIndexL);
274
+ if (mustGoNext) this.next();
275
+ else this.prev();
276
+ promise.then(this.ttsMaybeFlipToIndex.bind(this, leafIndex));
277
+ }
278
+ }
279
+
280
+ return promise;
281
+ };
282
+
283
+ /**
284
+ * @param {PageChunk} chunk
285
+ */
286
+ BookReader.prototype.ttsHighlightChunk = function(chunk) {
287
+ // The poorly-named variable leafIndex
288
+ const pageIndex = chunk.leafIndex;
289
+
290
+ this.ttsRemoveHilites();
291
+
292
+ // group by index; currently only possible to have chunks on one page :/
293
+ this._ttsBoxesByIndex = {
294
+ [pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t}))
295
+ };
296
+
297
+ // update any already created pages
298
+ for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {
299
+ const pageIndex = parseFloat(pageIndexString);
300
+ const page = this._models.book.getPage(pageIndex);
301
+ const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
302
+ pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));
303
+ }
304
+ };
305
+
306
+ /**
307
+ * @param {PageChunk} chunk
308
+ */
309
+ BookReader.prototype.ttsScrollToChunk = function(chunk) {
310
+ if (this.constMode1up != this.mode) return;
311
+
312
+ $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`)[0]?.scrollIntoView();
313
+ };
314
+
315
+ // ttsRemoveHilites()
316
+ //______________________________________________________________________________
317
+ BookReader.prototype.ttsRemoveHilites = function () {
318
+ $(this.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();
319
+ this._ttsBoxesByIndex = {};
320
+ };
321
+
322
+ /**
323
+ * @private
324
+ * Send an analytics event with an optional value. Also attaches the book's language.
325
+ * @param {string} action
326
+ * @param {number} [value]
327
+ */
328
+ BookReader.prototype.ttsSendAnalyticsEvent = function(action, value) {
329
+ if (this.archiveAnalyticsSendEvent) {
330
+ const extraValues = {};
331
+ const mediaLanguage = this.ttsEngine.opts.bookLanguage;
332
+ if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;
333
+ this.archiveAnalyticsSendEvent('BRReadAloud', action, value, extraValues);
334
+ }
335
+ };
@@ -0,0 +1,15 @@
1
+ export const en = {
2
+ advance: 'Advance 10 seconds',
3
+ play: 'Play',
4
+ playbackSpeed: 'Playback speed',
5
+ readAloud: 'Read this book aloud',
6
+ review: 'Review 10 seconds',
7
+ };
8
+
9
+ export const es = {
10
+ advance: 'Avance 10 segundos',
11
+ play: 'Jugar',
12
+ playbackSpeed: 'Velocidad de reproducción',
13
+ readAloud: 'Lee este libro en voz alta',
14
+ review: 'Revisar 10 segundos',
15
+ };
@@ -0,0 +1,91 @@
1
+ import langs from 'iso-language-codes/js/data.js';
2
+
3
+ /**
4
+ * Convert a EventTarget style event into a promise
5
+ * @param {EventTarget} target
6
+ * @param {string} eventType
7
+ * @return {Promise<Event>}
8
+ */
9
+ export function promisifyEvent(target, eventType) {
10
+ return new Promise(res => {
11
+ const resolver = ev => {
12
+ target.removeEventListener(eventType, resolver);
13
+ res(ev);
14
+ };
15
+ target.addEventListener(eventType, resolver);
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Use regex to approximate word count in a string
21
+ * @param {string} text
22
+ * @return {number}
23
+ */
24
+ export function approximateWordCount(text) {
25
+ const m = text.match(/\S+/g);
26
+ return m ? m.length : 0;
27
+ }
28
+
29
+ /**
30
+ * Waits the provided number of ms and then resolves with a promise
31
+ * @param {number} ms
32
+ * @return {Promise}
33
+ */
34
+ export function sleep(ms) {
35
+ return new Promise(res => setTimeout(res, ms));
36
+ }
37
+
38
+ /**
39
+ * Checks whether the current browser is on android
40
+ * @param {string} [userAgent]
41
+ * @return {boolean}
42
+ */
43
+ export function isAndroid(userAgent = navigator.userAgent) {
44
+ return /android/i.test(userAgent);
45
+ }
46
+
47
+ /**
48
+ * @typedef {string} ISO6391
49
+ * Language code in ISO 639-1 format. e.g. en, fr, zh
50
+ **/
51
+
52
+ /** Each lang is an array, with each index mapping to a different property */
53
+ const COLUMN_TO_LANG_INDEX = {
54
+ 'Name': 0,
55
+ 'Endonym': 1,
56
+ 'ISO 639-1': 2,
57
+ 'ISO 639-2/T': 3,
58
+ 'ISO 639-2/B': 4
59
+ };
60
+
61
+ /**
62
+ * @param {string} language in some format
63
+ * @return {ISO6391?}
64
+ */
65
+ export function toISO6391(language) {
66
+ if (!language) return null;
67
+ language = language.toLowerCase();
68
+
69
+ return searchForISO6391(language, ['ISO 639-1']) ||
70
+ searchForISO6391(language, ['ISO 639-2/B']) ||
71
+ searchForISO6391(language, ['ISO 639-2/T', 'Endonym', 'Name']);
72
+ }
73
+
74
+ /**
75
+ * Searches for the given long in the given columns.
76
+ * @param {string} language
77
+ * @param {Array<keyof COLUMN_TO_LANG_INDEX>} columnsToSearch
78
+ * @return {ISO6391?}
79
+ */
80
+ function searchForISO6391(language, columnsToSearch) {
81
+ for (let i = 0; i < langs.length; i++) {
82
+ for (let colI = 0; colI < columnsToSearch.length; colI++) {
83
+ const column = columnsToSearch[colI];
84
+ const columnValue = langs[i][COLUMN_TO_LANG_INDEX[column]];
85
+ if (columnValue.split(', ').map(x => x.toLowerCase()).indexOf(language) != -1) {
86
+ return langs[i][COLUMN_TO_LANG_INDEX['ISO 639-1']];
87
+ }
88
+ }
89
+ }
90
+ return null;
91
+ }
@@ -0,0 +1,30 @@
1
+
2
+ /**
3
+ * Checks whether the current browser is a Chrome/Chromium browser
4
+ * Code from https://stackoverflow.com/a/4565120/2317712
5
+ * @param {string} [userAgent]
6
+ * @param {string} [vendor]
7
+ * @return {boolean}
8
+ */
9
+ export function isChrome(userAgent = navigator.userAgent, vendor = navigator.vendor) {
10
+ return /chrome/i.test(userAgent) && /google inc/i.test(vendor);
11
+ }
12
+
13
+ /**
14
+ * Checks whether the current browser is firefox
15
+ * @param {string} [userAgent]
16
+ * @return {boolean}
17
+ */
18
+ export function isFirefox(userAgent = navigator.userAgent) {
19
+ return /firefox/i.test(userAgent);
20
+ }
21
+
22
+ /**
23
+ * Checks whether the current browser is safari
24
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#Browser_Name
25
+ * @param {string} [userAgent]
26
+ * @return {boolean}
27
+ */
28
+ export function isSafari(userAgent = navigator.userAgent) {
29
+ return /safari/i.test(userAgent) && !/chrome|chromium/i.test(userAgent);
30
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Wait until some time has passed before executing a callback.
3
+ *
4
+ * @param {Function} callback
5
+ * @param {Number} threshhold - in milliseconds
6
+ * @param {*} context - will be bound to callback as its "this" value
7
+ */
8
+ class Debouncer {
9
+ constructor(callback, threshhold = 250, context = undefined) {
10
+ this.callback = callback;
11
+ this.threshhold = threshhold;
12
+ this.context = context;
13
+ this.deferTimeout = undefined;
14
+ }
15
+
16
+ execute() {
17
+ clearTimeout(this.deferTimeout);
18
+ this.deferTimeout = setTimeout(this.executeCallback.bind(this), this.threshhold);
19
+ }
20
+
21
+ executeCallback() {
22
+ this.callback.apply(this.context);
23
+ }
24
+ }
25
+
26
+ export { Debouncer as default };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Helper module use to get, set and remove item from cookie
3
+ *
4
+ * See more:
5
+ * https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
6
+ * https://developer.mozilla.org/User:fusionchess
7
+ * https://github.com/madmurphy/cookies.js
8
+ * This framework is released under the GNU Public License, version 3 or later.
9
+ * http://www.gnu.org/licenses/gpl-3.0-standalone.html
10
+ */
11
+
12
+ /**
13
+ * Get specific key's value stored in cookie
14
+ *
15
+ * @param {string} sKey
16
+ *
17
+ * @returns {string|null}
18
+ */
19
+ export function getItem(sKey) {
20
+ if (!sKey) return null;
21
+
22
+ return decodeURIComponent(
23
+ // eslint-disable-next-line no-useless-escape
24
+ document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
25
+ }
26
+
27
+ /**
28
+ * Set specific key's value in cookie
29
+ *
30
+ * @param {string} sKey cookie name
31
+ * @param {string} sValue cookie value
32
+ * @param {string} [vEnd] expire|max-age
33
+ * @param {string} [sPath] path of current item
34
+ * @param {string} [sDomain] domain name
35
+ * @param {boolean} [bSecure]
36
+ *
37
+ * @returns {true}
38
+ */
39
+ export function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
40
+ document.cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue)
41
+ + (vEnd ? `; expires=${vEnd.toUTCString()}` : '')
42
+ + (sDomain ? `; domain=${sDomain}` : '')
43
+ + (sPath ? `; path=${sPath}` : '')
44
+ + (bSecure ? `; secure` : '');
45
+
46
+ return true;
47
+ }
48
+
49
+ /**
50
+ * BROKEN Remove specific key's value from cookie
51
+ * @fixme hasItem isn't even implemented! This will always error.
52
+ * @param {string} sKey cookie name
53
+ * @param {string} [sPath] path of current item
54
+ * @param {string} [sDomain]
55
+ *
56
+ * @returns {boolean}
57
+ */
58
+ export function removeItem(sKey, sPath, sDomain) {
59
+ // eslint-disable-next-line
60
+ if (!hasItem(sKey)) return false;
61
+
62
+ document.cookie = encodeURIComponent(sKey) + `=; expires=Thu, 01 Jan 1970 00:00:00 GMT`
63
+ + (sDomain ? `; domain=${sDomain}` : '')
64
+ + (sPath ? `; path=${sPath}` : '');
65
+
66
+ return true;
67
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @typedef {String} StringWithVars
3
+ * A template string with {{foo}} style variables
4
+ * Also supports filters, like {{bookPath|urlencode}} (See APPLY_FILTERS for the
5
+ * supported list of filters)
6
+ **/
7
+
8
+ /**
9
+ * @param {StringWithVars|String} template
10
+ * @param { {[varName: string]: { toString: () => string} } } vars
11
+ * @param { {[varName: string]: { toString: () => string} } } [overrides]
12
+ */
13
+ export function applyVariables(template, vars, overrides = {}, possibleFilters = APPLY_FILTERS) {
14
+ return template?.replace(/\{\{([^}]*?)\}\}/g, ($0, $1) => {
15
+ if (!$1) return $0;
16
+ /** @type {string} */
17
+ const expression = $1;
18
+ const [varName, ...filterNames] = expression.split('|').map(x => x.trim());
19
+ const defined = varName in overrides || varName in vars;
20
+
21
+ // If it's not defined, don't expand it at all
22
+ if (!defined) return $0;
23
+
24
+ const value = varName in overrides ? overrides[varName]
25
+ : varName in vars ? vars[varName] : null;
26
+ const filters = filterNames.map(n => possibleFilters[n]);
27
+ return filters.reduce((acc, cur) => cur(acc), value && value.toString());
28
+ });
29
+ }
30
+
31
+ /** @type { {[filterName: String]:( string => string)} } */
32
+ export const APPLY_FILTERS = {
33
+ urlencode: encodeURIComponent,
34
+ };