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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (389) 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 +1 -1
  8. package/BookReader/BookReader.js.LICENSE.txt +45 -0
  9. package/BookReader/BookReader.js.map +1 -1
  10. package/BookReader/ia-bookreader-bundle.js +1458 -0
  11. package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +10 -9
  12. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  13. package/BookReader/icons/close-circle-dark.svg +1 -0
  14. package/BookReader/icons/voice.svg +1 -0
  15. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  16. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  17. package/BookReader/plugins/plugin.autoplay.js +1 -1
  18. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  19. package/BookReader/plugins/plugin.chapters.js +1 -1
  20. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  21. package/BookReader/plugins/plugin.iframe.js +1 -1
  22. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  23. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  24. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  25. package/BookReader/plugins/plugin.resume.js +1 -1
  26. package/BookReader/plugins/plugin.resume.js.map +1 -1
  27. package/BookReader/plugins/plugin.search.js +1 -1
  28. package/BookReader/plugins/plugin.search.js.map +1 -1
  29. package/BookReader/plugins/plugin.text_selection.js +1 -1
  30. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  31. package/BookReader/plugins/plugin.tts.js +1 -1
  32. package/BookReader/plugins/plugin.tts.js.map +1 -1
  33. package/BookReader/plugins/plugin.url.js +1 -1
  34. package/BookReader/plugins/plugin.url.js.map +1 -1
  35. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  36. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  37. package/BookReader/webcomponents-bundle.js +3 -0
  38. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  39. package/BookReader/webcomponents-bundle.js.map +1 -0
  40. package/BookReaderDemo/BookReaderDemo.css +14 -1
  41. package/BookReaderDemo/IADemoBr.js +107 -0
  42. package/BookReaderDemo/demo-advanced.html +1 -1
  43. package/BookReaderDemo/demo-autoplay.html +1 -0
  44. package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
  45. package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
  46. package/BookReaderDemo/demo-fullscreen.html +1 -0
  47. package/BookReaderDemo/demo-iiif.html +1 -0
  48. package/BookReaderDemo/demo-internetarchive.html +66 -18
  49. package/BookReaderDemo/demo-multiple.html +1 -0
  50. package/BookReaderDemo/demo-preview-pages.html +1 -0
  51. package/BookReaderDemo/demo-simple.html +1 -0
  52. package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
  53. package/BookReaderDemo/immersion-1up.html +1 -0
  54. package/BookReaderDemo/immersion-mode.html +1 -0
  55. package/BookReaderDemo/toggle_controls.html +1 -0
  56. package/BookReaderDemo/view_mode.html +1 -0
  57. package/BookReaderDemo/viewmode-cycle.html +1 -2
  58. package/CHANGELOG.md +114 -0
  59. package/babel.config.js +18 -0
  60. package/index.html +3 -0
  61. package/jsconfig.json +19 -0
  62. package/package.json +45 -27
  63. package/src/BookNavigator/assets/button-base.js +8 -1
  64. package/src/BookNavigator/assets/ia-logo.js +17 -0
  65. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  66. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  67. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  68. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  69. package/src/BookNavigator/book-navigator.js +528 -0
  70. package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
  71. package/src/BookNavigator/bookmarks/bookmark-edit.js +2 -1
  72. package/src/BookNavigator/bookmarks/bookmarks-list.js +1 -0
  73. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  74. package/src/BookNavigator/bookmarks/bookmarks-provider.js +32 -11
  75. package/src/BookNavigator/bookmarks/ia-bookmarks.js +88 -43
  76. package/src/BookNavigator/downloads/downloads-provider.js +22 -16
  77. package/src/BookNavigator/downloads/downloads.js +16 -23
  78. package/src/BookNavigator/search/a-search-result.js +1 -0
  79. package/src/BookNavigator/search/search-provider.js +54 -20
  80. package/src/BookNavigator/search/search-results.js +7 -18
  81. package/src/BookNavigator/sharing.js +27 -0
  82. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +10 -12
  83. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +1 -0
  84. package/src/BookNavigator/volumes/volumes-provider.js +114 -0
  85. package/src/BookNavigator/volumes/volumes.js +189 -0
  86. package/src/BookReader/DebugConsole.js +3 -3
  87. package/src/BookReader/DragScrollable.js +233 -0
  88. package/src/BookReader/Mode1Up.js +50 -351
  89. package/src/BookReader/Mode1UpLit.js +434 -0
  90. package/src/BookReader/Mode2Up.js +94 -72
  91. package/src/BookReader/ModeSmoothZoom.js +177 -0
  92. package/src/BookReader/ModeThumb.js +16 -8
  93. package/src/BookReader/Navbar/Navbar.js +2 -31
  94. package/src/BookReader/PageContainer.js +47 -2
  95. package/src/BookReader/ReduceSet.js +1 -1
  96. package/src/BookReader/Toolbar/Toolbar.js +5 -5
  97. package/src/BookReader/options.js +10 -0
  98. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  99. package/src/BookReader/utils.js +68 -13
  100. package/src/BookReader.js +316 -232
  101. package/src/assets/icons/close-circle-dark.svg +1 -0
  102. package/src/assets/icons/voice.svg +1 -0
  103. package/src/css/BookReader.scss +0 -12
  104. package/src/css/_BRComponent.scss +1 -1
  105. package/src/css/_BRmain.scss +19 -24
  106. package/src/css/_BRnav.scss +4 -26
  107. package/src/css/_BRpages.scss +35 -0
  108. package/src/css/_BRsearch.scss +11 -215
  109. package/src/css/_TextSelection.scss +1 -17
  110. package/src/css/_controls.scss +16 -3
  111. package/src/css/_icons.scss +6 -0
  112. package/src/ia-bookreader/ia-bookreader.js +205 -0
  113. package/src/plugins/plugin.chapters.js +15 -18
  114. package/src/plugins/plugin.mobile_nav.js +11 -10
  115. package/src/plugins/plugin.resume.js +3 -3
  116. package/src/plugins/plugin.text_selection.js +17 -29
  117. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  118. package/src/plugins/search/plugin.search.js +113 -104
  119. package/src/plugins/search/view.js +48 -163
  120. package/src/plugins/tts/AbstractTTSEngine.js +7 -0
  121. package/src/plugins/tts/FestivalTTSEngine.js +2 -2
  122. package/src/plugins/tts/WebTTSEngine.js +5 -0
  123. package/src/plugins/tts/plugin.tts.js +67 -102
  124. package/src/plugins/url/UrlPlugin.js +184 -0
  125. package/src/plugins/url/plugin.url.js +220 -0
  126. package/{src → stat}/BookNavigator/BookModel.js +0 -0
  127. package/{src → stat}/BookNavigator/BookNavigator.js +151 -104
  128. package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
  129. package/stat/BookNavigator/assets/button-base.js +61 -0
  130. package/stat/BookNavigator/assets/ia-logo.js +17 -0
  131. package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
  132. package/stat/BookNavigator/assets/icon_close.js +3 -0
  133. package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
  134. package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
  135. package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
  136. package/stat/BookNavigator/assets/icon_volumes.js +11 -0
  137. package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
  138. package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
  139. package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
  140. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
  141. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
  142. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
  143. package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
  144. package/stat/BookNavigator/delete-modal-actions.js +49 -0
  145. package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
  146. package/stat/BookNavigator/downloads/downloads.js +139 -0
  147. package/stat/BookNavigator/provider-config.js +0 -0
  148. package/stat/BookNavigator/search/a-search-result.js +55 -0
  149. package/stat/BookNavigator/search/search-provider.js +180 -0
  150. package/stat/BookNavigator/search/search-results.js +360 -0
  151. package/stat/BookNavigator/sharing.js +31 -0
  152. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
  153. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
  154. package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
  155. package/stat/BookNavigator/volumes/volumes.js +178 -0
  156. package/stat/BookReader/BookModel.js +518 -0
  157. package/stat/BookReader/DebugConsole.js +54 -0
  158. package/stat/BookReader/DragScrollable.js +233 -0
  159. package/stat/BookReader/ImageCache.js +116 -0
  160. package/stat/BookReader/Mode1Up.js +102 -0
  161. package/stat/BookReader/Mode1UpLit.js +434 -0
  162. package/stat/BookReader/Mode2Up.js +1372 -0
  163. package/stat/BookReader/ModeSmoothZoom.js +177 -0
  164. package/stat/BookReader/ModeThumb.js +344 -0
  165. package/stat/BookReader/Navbar/Navbar.js +310 -0
  166. package/stat/BookReader/PageContainer.js +120 -0
  167. package/stat/BookReader/ReduceSet.js +26 -0
  168. package/stat/BookReader/Toolbar/Toolbar.js +384 -0
  169. package/stat/BookReader/events.js +20 -0
  170. package/stat/BookReader/options.js +324 -0
  171. package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  172. package/stat/BookReader/utils/classes.js +36 -0
  173. package/stat/BookReader/utils.js +240 -0
  174. package/stat/BookReader.js +2550 -0
  175. package/{src → stat}/BookReaderComponent/BookReaderComponent.js +16 -11
  176. package/stat/assets/icons/1up.svg +12 -0
  177. package/stat/assets/icons/2up.svg +15 -0
  178. package/stat/assets/icons/advance.svg +26 -0
  179. package/stat/assets/icons/chevron-right.svg +1 -0
  180. package/stat/assets/icons/close-circle-dark.svg +1 -0
  181. package/stat/assets/icons/close-circle.svg +1 -0
  182. package/stat/assets/icons/fullscreen.svg +17 -0
  183. package/stat/assets/icons/fullscreen_exit.svg +17 -0
  184. package/stat/assets/icons/hamburger.svg +15 -0
  185. package/stat/assets/icons/left-arrow.svg +12 -0
  186. package/stat/assets/icons/magnify-minus.svg +16 -0
  187. package/stat/assets/icons/magnify-plus.svg +17 -0
  188. package/stat/assets/icons/magnify.svg +15 -0
  189. package/stat/assets/icons/pause.svg +23 -0
  190. package/stat/assets/icons/play.svg +22 -0
  191. package/stat/assets/icons/playback-speed.svg +34 -0
  192. package/stat/assets/icons/read-aloud.svg +22 -0
  193. package/stat/assets/icons/review.svg +22 -0
  194. package/stat/assets/icons/thumbnails.svg +17 -0
  195. package/stat/assets/icons/voice.svg +1 -0
  196. package/stat/assets/icons/volume-full.svg +22 -0
  197. package/stat/assets/images/BRicons.png +0 -0
  198. package/stat/assets/images/BRicons.svg +94 -0
  199. package/stat/assets/images/BRicons_ia.png +0 -0
  200. package/stat/assets/images/back_pages.png +0 -0
  201. package/stat/assets/images/book_bottom_icon.png +0 -0
  202. package/stat/assets/images/book_down_icon.png +0 -0
  203. package/stat/assets/images/book_left_icon.png +0 -0
  204. package/stat/assets/images/book_leftmost_icon.png +0 -0
  205. package/stat/assets/images/book_right_icon.png +0 -0
  206. package/stat/assets/images/book_rightmost_icon.png +0 -0
  207. package/stat/assets/images/book_top_icon.png +0 -0
  208. package/stat/assets/images/book_up_icon.png +0 -0
  209. package/stat/assets/images/books_graphic.svg +177 -0
  210. package/stat/assets/images/booksplit.png +0 -0
  211. package/stat/assets/images/control_pause_icon.png +0 -0
  212. package/stat/assets/images/control_play_icon.png +0 -0
  213. package/stat/assets/images/embed_icon.png +0 -0
  214. package/stat/assets/images/icon-home-ia.png +0 -0
  215. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  216. package/stat/assets/images/icon_alert-xs.png +0 -0
  217. package/stat/assets/images/icon_book.svg +12 -0
  218. package/stat/assets/images/icon_bookmark.svg +12 -0
  219. package/stat/assets/images/icon_close-pop.png +0 -0
  220. package/stat/assets/images/icon_download.png +0 -0
  221. package/stat/assets/images/icon_gear.svg +14 -0
  222. package/stat/assets/images/icon_hamburger.svg +20 -0
  223. package/stat/assets/images/icon_home.png +0 -0
  224. package/stat/assets/images/icon_home.svg +21 -0
  225. package/stat/assets/images/icon_home_ia.png +0 -0
  226. package/stat/assets/images/icon_indicator.png +0 -0
  227. package/stat/assets/images/icon_info.svg +11 -0
  228. package/stat/assets/images/icon_one_page.svg +8 -0
  229. package/stat/assets/images/icon_pause.svg +1 -0
  230. package/stat/assets/images/icon_play.svg +1 -0
  231. package/stat/assets/images/icon_playback-rate.svg +15 -0
  232. package/stat/assets/images/icon_return.png +0 -0
  233. package/stat/assets/images/icon_search_button.svg +8 -0
  234. package/stat/assets/images/icon_share.svg +9 -0
  235. package/stat/assets/images/icon_skip-ahead.svg +6 -0
  236. package/stat/assets/images/icon_skip-back.svg +13 -0
  237. package/stat/assets/images/icon_speaker.svg +18 -0
  238. package/stat/assets/images/icon_speaker_open.svg +10 -0
  239. package/stat/assets/images/icon_thumbnails.svg +12 -0
  240. package/stat/assets/images/icon_toc.svg +5 -0
  241. package/stat/assets/images/icon_two_pages.svg +9 -0
  242. package/stat/assets/images/icon_zoomer.png +0 -0
  243. package/stat/assets/images/loading.gif +0 -0
  244. package/stat/assets/images/logo_icon.png +0 -0
  245. package/stat/assets/images/marker_chap-off.png +0 -0
  246. package/stat/assets/images/marker_chap-off.svg +11 -0
  247. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  248. package/stat/assets/images/marker_chap-on.png +0 -0
  249. package/stat/assets/images/marker_chap-on.svg +11 -0
  250. package/stat/assets/images/marker_srch-on.svg +11 -0
  251. package/stat/assets/images/marker_srchchap-off.png +0 -0
  252. package/stat/assets/images/marker_srchchap-on.png +0 -0
  253. package/stat/assets/images/nav_control-dn.png +0 -0
  254. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  255. package/stat/assets/images/nav_control-up.png +0 -0
  256. package/stat/assets/images/nav_control-up_ia.png +0 -0
  257. package/stat/assets/images/nav_control.png +0 -0
  258. package/stat/assets/images/one_page_mode_icon.png +0 -0
  259. package/stat/assets/images/paper-badge.png +0 -0
  260. package/stat/assets/images/print_icon.png +0 -0
  261. package/stat/assets/images/progressbar.gif +0 -0
  262. package/stat/assets/images/right_edges.png +0 -0
  263. package/stat/assets/images/slider.png +0 -0
  264. package/stat/assets/images/slider_ia.png +0 -0
  265. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  266. package/stat/assets/images/transparent.png +0 -0
  267. package/stat/assets/images/two_page_mode_icon.png +0 -0
  268. package/stat/assets/images/zoom_in_icon.png +0 -0
  269. package/stat/assets/images/zoom_out_icon.png +0 -0
  270. package/stat/css/BookReader.scss +89 -0
  271. package/stat/css/_BRBookmarks.scss +29 -0
  272. package/stat/css/_BRComponent.scss +13 -0
  273. package/stat/css/_BRfloat.scss +197 -0
  274. package/stat/css/_BRicon.scss +48 -0
  275. package/stat/css/_BRmain.scss +251 -0
  276. package/stat/css/_BRnav.scss +359 -0
  277. package/stat/css/_BRpages.scss +139 -0
  278. package/stat/css/_BRsearch.scss +226 -0
  279. package/stat/css/_BRtoolbar.scss +84 -0
  280. package/stat/css/_BRvendor.scss +5 -0
  281. package/stat/css/_MobileNav.scss +194 -0
  282. package/stat/css/_TextSelection.scss +32 -0
  283. package/stat/css/_colorbox.scss +52 -0
  284. package/stat/css/_controls.scss +253 -0
  285. package/stat/css/_icons.scss +121 -0
  286. package/stat/jquery-wrapper.js +4 -0
  287. package/stat/plugins/plugin.archive_analytics.js +86 -0
  288. package/stat/plugins/plugin.autoplay.js +129 -0
  289. package/stat/plugins/plugin.chapters.js +248 -0
  290. package/stat/plugins/plugin.iframe.js +48 -0
  291. package/stat/plugins/plugin.mobile_nav.js +288 -0
  292. package/stat/plugins/plugin.resume.js +68 -0
  293. package/stat/plugins/plugin.text_selection.js +291 -0
  294. package/{src → stat}/plugins/plugin.url.js +4 -4
  295. package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
  296. package/stat/plugins/search/plugin.search.js +439 -0
  297. package/stat/plugins/search/view.js +439 -0
  298. package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
  299. package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
  300. package/stat/plugins/tts/PageChunk.js +107 -0
  301. package/stat/plugins/tts/PageChunkIterator.js +163 -0
  302. package/stat/plugins/tts/WebTTSEngine.js +357 -0
  303. package/stat/plugins/tts/plugin.tts.js +357 -0
  304. package/stat/plugins/tts/tooltip_dict.js +15 -0
  305. package/stat/plugins/tts/utils.js +91 -0
  306. package/stat/util/browserSniffing.js +30 -0
  307. package/stat/util/debouncer.js +26 -0
  308. package/stat/util/docCookies.js +67 -0
  309. package/stat/util/strings.js +34 -0
  310. package/tests/e2e/README.md +37 -0
  311. package/tests/e2e/autoplay.test.js +2 -2
  312. package/tests/e2e/base.test.js +5 -7
  313. package/tests/e2e/helpers/base.js +8 -3
  314. package/tests/e2e/helpers/debug.js +1 -1
  315. package/tests/e2e/helpers/desktopSearch.js +1 -1
  316. package/tests/e2e/helpers/mobileSearch.js +3 -3
  317. package/tests/e2e/helpers/params.js +17 -0
  318. package/tests/e2e/rightToLeft.test.js +4 -5
  319. package/tests/e2e/viewmode.test.js +30 -31
  320. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
  321. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  322. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  323. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  324. package/tests/jest/BookReader/Mode1UpLit.test.js +87 -0
  325. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
  326. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  327. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  328. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  329. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +74 -2
  330. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  331. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  332. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  333. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  334. package/tests/jest/BookReader/utils.test.js +136 -0
  335. package/tests/jest/BookReader.keyboard.test.js +190 -0
  336. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  337. package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
  338. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  339. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
  340. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
  341. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  342. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  343. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  344. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +14 -24
  345. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  346. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +12 -5
  347. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
  348. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +3 -3
  349. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  350. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  351. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  352. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  353. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
  354. package/tests/jest/plugins/url/UrlPlugin.test.js +175 -0
  355. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  356. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  357. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  358. package/tests/{util → jest/util}/strings.test.js +1 -1
  359. package/tests/{utils.js → jest/utils.js} +38 -0
  360. package/tests/karma/BookNavigator/book-navigator.test.js +485 -0
  361. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  362. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
  363. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +1 -2
  364. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
  365. package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
  366. package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
  367. package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
  368. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
  369. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
  370. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
  371. package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
  372. package/webpack.config.js +10 -4
  373. package/.babelrc +0 -12
  374. package/.dependabot/config.yml +0 -6
  375. package/.testcaferc.json +0 -5
  376. package/BookReader/bookreader-component-bundle.js +0 -1450
  377. package/BookReader/bookreader-component-bundle.js.map +0 -1
  378. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  379. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  380. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  381. package/src/BookNavigator/assets/book-loader.js +0 -27
  382. package/src/ItemNavigator/ItemNavigator.js +0 -372
  383. package/src/ItemNavigator/providers/sharing.js +0 -29
  384. package/src/dragscrollable-br.js +0 -261
  385. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  386. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  387. package/tests/BookReader/Mode1Up.test.js +0 -164
  388. package/tests/BookReader/utils.test.js +0 -109
  389. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,291 @@
1
+ //@ts-check
2
+ import { createSVGPageLayer } from '../BookReader/PageContainer.js';
3
+ import { isFirefox, isSafari } from '../util/browserSniffing.js';
4
+ import { applyVariables } from '../util/strings.js';
5
+ /** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */
6
+ /** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */
7
+
8
+ const BookReader = /** @type {typeof import('../BookReader').default} */(window.BookReader);
9
+
10
+ export const DEFAULT_OPTIONS = {
11
+ enabled: true,
12
+ /** @type {StringWithVars} The URL to fetch the entire DJVU xml. Supports options.vars */
13
+ fullDjvuXmlUrl: null,
14
+ /** @type {StringWithVars} The URL to fetch a single page of the DJVU xml. Supports options.vars. Also has {{pageIndex}} */
15
+ singlePageDjvuXmlUrl: null,
16
+ };
17
+ /** @typedef {typeof DEFAULT_OPTIONS} TextSelectionPluginOptions */
18
+
19
+ /**
20
+ * @template T
21
+ */
22
+ export class Cache {
23
+ constructor(maxSize = 10) {
24
+ this.maxSize = maxSize;
25
+ /** @type {T[]} */
26
+ this.entries = [];
27
+ }
28
+
29
+ /**
30
+ * @param {T} entry
31
+ */
32
+ add(entry) {
33
+ if (this.entries.length >= this.maxSize) {
34
+ this.entries.shift();
35
+ }
36
+ this.entries.push(entry);
37
+ }
38
+ }
39
+
40
+ export class TextSelectionPlugin {
41
+
42
+ constructor(options = DEFAULT_OPTIONS, optionVariables, avoidTspans = isFirefox(), pointerEventsOnParagraph = isSafari()) {
43
+ this.options = options;
44
+ this.optionVariables = optionVariables;
45
+ /**@type {PromiseLike<JQuery<HTMLElement>|undefined>} */
46
+ this.djvuPagesPromise = null;
47
+ // Using text elements instead of tspans for words because Firefox does not allow svg tspan stretch.
48
+ // Tspans are necessary on Chrome because they prevent newline character after every word when copying
49
+ this.svgParagraphElement = "text";
50
+ this.svgWordElement = "tspan";
51
+ this.insertNewlines = avoidTspans;
52
+ // Safari has a bug where `pointer-events` doesn't work on `<tspans>`. So
53
+ // there we will set `pointer-events: all` on the paragraph element. We don't
54
+ // do this everywhere, because it's a worse experience. Thanks Safari :/
55
+ this.pointerEventsOnParagraph = pointerEventsOnParagraph;
56
+ if (avoidTspans) {
57
+ this.svgParagraphElement = "g";
58
+ this.svgWordElement = "text";
59
+ }
60
+
61
+ /** @type {Cache<{index: number, response: any}>} */
62
+ this.pageTextCache = new Cache();
63
+
64
+ /**
65
+ * Sometimes there are too many words on a page, and the browser becomes near
66
+ * unusable. For now don't render text layer for pages with too many words.
67
+ */
68
+ this.maxWordRendered = 2500;
69
+ }
70
+
71
+ init() {
72
+ // Only fetch the full djvu xml if the single page url isn't there
73
+ if (this.options.singlePageDjvuXmlUrl) return;
74
+ this.djvuPagesPromise = $.ajax({
75
+ type: "GET",
76
+ url: applyVariables(this.options.fullDjvuXmlUrl, this.optionVariables),
77
+ dataType: "html",
78
+ error: (e) => undefined
79
+ }).then((res) => {
80
+ try {
81
+ const xmlMap = $.parseXML(res);
82
+ return xmlMap && $(xmlMap).find("OBJECT");
83
+ } catch (e) {
84
+ return undefined;
85
+ }
86
+ });
87
+ }
88
+
89
+ /**
90
+ * @param {number} index
91
+ * @returns {Promise<HTMLElement|undefined>}
92
+ */
93
+ async getPageText(index) {
94
+ if (this.options.singlePageDjvuXmlUrl) {
95
+ const cachedEntry = this.pageTextCache.entries.find(x => x.index == index);
96
+ if (cachedEntry) {
97
+ return cachedEntry.response;
98
+ }
99
+ return $.ajax({
100
+ type: "GET",
101
+ url: applyVariables(this.options.singlePageDjvuXmlUrl, this.optionVariables, { pageIndex: index }),
102
+ dataType: "html",
103
+ error: (e) => undefined,
104
+ }).then((res) => {
105
+ try {
106
+ const xmlDoc = $.parseXML(res);
107
+ const result = xmlDoc && $(xmlDoc).find("OBJECT")[0];
108
+ this.pageTextCache.add({ index, response: result });
109
+ return result;
110
+ } catch (e) {
111
+ return undefined;
112
+ }
113
+ });
114
+ } else {
115
+ const XMLpagesArr = await this.djvuPagesPromise;
116
+ if (XMLpagesArr) return XMLpagesArr[index];
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Intercept copied text to remove any styling applied to it
122
+ * @param {JQuery} $container
123
+ */
124
+ interceptCopy($container) {
125
+ $container[0].addEventListener('copy', (event) => {
126
+ const selection = document.getSelection();
127
+ event.clipboardData.setData('text/plain', selection.toString());
128
+ event.preventDefault();
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Applies mouse events when in default mode
134
+ * @param {SVGElement} svg
135
+ */
136
+ defaultMode(svg) {
137
+ svg.classList.remove("selectingSVG");
138
+ $(svg).on("mousedown.textSelectPluginHandler", (event) => {
139
+ if (!$(event.target).is(".BRwordElement")) return;
140
+ event.stopPropagation();
141
+ svg.classList.add("selectingSVG");
142
+ $(svg).one("mouseup.textSelectPluginHandler", (event) => {
143
+ if (window.getSelection().toString() != "") {
144
+ event.stopPropagation();
145
+ $(svg).off(".textSelectPluginHandler");
146
+ this.textSelectingMode(svg);
147
+ }
148
+ else svg.classList.remove("selectingSVG");
149
+ });
150
+ });
151
+ }
152
+
153
+ /**
154
+ * Applies mouse events when in textSelecting mode
155
+ * @param {SVGElement} svg
156
+ */
157
+ textSelectingMode(svg) {
158
+ $(svg).on('mousedown.textSelectPluginHandler', (event) => {
159
+ if (!$(event.target).is(".BRwordElement")) {
160
+ if (window.getSelection().toString() != "") window.getSelection().removeAllRanges();
161
+ }
162
+ event.stopPropagation();
163
+ });
164
+ $(svg).on('mouseup.textSelectPluginHandler', (event) => {
165
+ event.stopPropagation();
166
+ if (window.getSelection().toString() == "") {
167
+ $(svg).off(".textSelectPluginHandler");
168
+ this.defaultMode(svg); }
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Initializes text selection modes if there is an svg on the page
174
+ * @param {JQuery} $container
175
+ */
176
+ stopPageFlip($container) {
177
+ /** @type {JQuery<SVGElement>} */
178
+ const $svg = $container.find('svg.textSelectionSVG');
179
+ if (!$svg.length) return;
180
+ $svg.each((i, s) => this.defaultMode(s));
181
+ this.interceptCopy($container);
182
+ }
183
+
184
+ /**
185
+ * @param {PageContainer} pageContainer
186
+ */
187
+ async createTextLayer(pageContainer) {
188
+ const pageIndex = pageContainer.page.index;
189
+ const $container = pageContainer.$container;
190
+ const $svgLayers = $container.find('.textSelectionSVG');
191
+ if ($svgLayers.length) return;
192
+ const XMLpage = await this.getPageText(pageIndex);
193
+ if (!XMLpage) return;
194
+
195
+ const totalWords = $(XMLpage).find("WORD").length;
196
+ if (totalWords > this.maxWordRendered) {
197
+ console.log(`Page ${pageIndex} has too many words (${totalWords} > ${this.maxWordRendered}). Not rendering text layer.`);
198
+ return;
199
+ }
200
+
201
+ const svg = createSVGPageLayer(pageContainer.page, 'textSelectionSVG');
202
+ $container.append(svg);
203
+
204
+ $(XMLpage).find("PARAGRAPH").each((i, paragraph) => {
205
+ // Adding text element for each paragraph in the page
206
+ const words = $(paragraph).find("WORD");
207
+ if (!words.length) return;
208
+ const paragSvg = document.createElementNS("http://www.w3.org/2000/svg", this.svgParagraphElement);
209
+ paragSvg.setAttribute("class", "BRparagElement");
210
+ if (this.pointerEventsOnParagraph) {
211
+ paragSvg.style.pointerEvents = "all";
212
+ }
213
+
214
+ const wordHeightArr = [];
215
+
216
+ for (let i = 0; i < words.length; i++) {
217
+ // Adding tspan for each word in paragraph
218
+ const currWord = words[i];
219
+ // eslint-disable-next-line no-unused-vars
220
+ const [left, bottom, right, top] = $(currWord).attr("coords").split(',').map(parseFloat);
221
+ const wordHeight = bottom - top;
222
+ wordHeightArr.push(wordHeight);
223
+
224
+ const wordTspan = document.createElementNS("http://www.w3.org/2000/svg", this.svgWordElement);
225
+ wordTspan.setAttribute("class", "BRwordElement");
226
+ wordTspan.setAttribute("x", left.toString());
227
+ wordTspan.setAttribute("y", bottom.toString());
228
+ wordTspan.setAttribute("textLength", (right - left).toString());
229
+ wordTspan.setAttribute("lengthAdjust", "spacingAndGlyphs");
230
+ wordTspan.textContent = currWord.textContent;
231
+ paragSvg.appendChild(wordTspan);
232
+
233
+ // Adding spaces after words except at the end of the paragraph
234
+ // TODO: assumes left-to-right text
235
+ if (i < words.length - 1) {
236
+ const nextWord = words[i + 1];
237
+ // eslint-disable-next-line no-unused-vars
238
+ const [leftNext, bottomNext, rightNext, topNext] = $(nextWord).attr("coords").split(',').map(parseFloat);
239
+ const spaceTspan = document.createElementNS("http://www.w3.org/2000/svg", this.svgWordElement);
240
+ spaceTspan.setAttribute("class", "BRwordElement");
241
+ spaceTspan.setAttribute("x", right.toString());
242
+ spaceTspan.setAttribute("y", bottom.toString());
243
+ if ((leftNext - right) > 0) spaceTspan.setAttribute("textLength", (leftNext - right).toString());
244
+ spaceTspan.setAttribute("lengthAdjust", "spacingAndGlyphs");
245
+ spaceTspan.textContent = " ";
246
+ paragSvg.appendChild(spaceTspan);
247
+ }
248
+
249
+ // Adds newline at the end of paragraph on Firefox
250
+ if ((i == words.length - 1 && (this.insertNewlines))) {
251
+ paragSvg.appendChild(document.createTextNode("\n"));
252
+ }
253
+ }
254
+
255
+ wordHeightArr.sort();
256
+ const paragWordHeight = wordHeightArr[Math.floor(wordHeightArr.length * 0.85)];
257
+ paragSvg.setAttribute("font-size", paragWordHeight.toString());
258
+ svg.appendChild(paragSvg);
259
+ });
260
+ this.stopPageFlip($container);
261
+ }
262
+ }
263
+
264
+ export class BookreaderWithTextSelection extends BookReader {
265
+ init() {
266
+ const options = Object.assign({}, DEFAULT_OPTIONS, this.options.plugins.textSelection);
267
+ if (options.enabled) {
268
+ this.textSelectionPlugin = new TextSelectionPlugin(options, this.options.vars);
269
+ // Write this back; this way the plugin is the source of truth, and BR just
270
+ // contains a reference to it.
271
+ this.options.plugins.textSelection = options;
272
+ this.textSelectionPlugin.init();
273
+ }
274
+ super.init();
275
+ }
276
+
277
+ /**
278
+ * @param {number} index
279
+ */
280
+ _createPageContainer(index) {
281
+ const pageContainer = super._createPageContainer(index);
282
+ // Disable if thumb mode; it's too janky
283
+ // .page can be null for "pre-cover" region
284
+ if (this.mode !== this.constModeThumb && pageContainer.page) {
285
+ this.textSelectionPlugin?.createTextLayer(pageContainer);
286
+ }
287
+ return pageContainer;
288
+ }
289
+ }
290
+ window.BookReader = BookreaderWithTextSelection;
291
+ export default BookreaderWithTextSelection;
@@ -22,7 +22,7 @@ jQuery.extend(BookReader.defaultOptions, {
22
22
  urlHistoryBasePath: '/',
23
23
 
24
24
  /** Only these params will be reflected onto the URL */
25
- urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight'],
25
+ urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view'],
26
26
 
27
27
  /** If true, don't update the URL when `page == n0 (eg "/page/n0")` */
28
28
  urlTrackIndex0: false,
@@ -110,7 +110,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
110
110
  updateParams();
111
111
  }
112
112
  this.oldUserHash = newFragment;
113
- }
113
+ };
114
114
 
115
115
  this.locationPollId = setInterval(updateHash, 500);
116
116
  };
@@ -134,7 +134,7 @@ BookReader.prototype.urlUpdateFragment = function() {
134
134
  if (paramName in allParams) {
135
135
  validParams[paramName] = allParams[paramName];
136
136
  }
137
- return validParams
137
+ return validParams;
138
138
  }, {});
139
139
 
140
140
  const newFragment = this.fragmentFromParams(params, urlMode);
@@ -173,7 +173,7 @@ BookReader.prototype.urlUpdateFragment = function() {
173
173
  BookReader.prototype.urlParamsFiltersOnlySearch = function(url) {
174
174
  const params = new URLSearchParams(url);
175
175
  return params.has('q') ? `?${new URLSearchParams({ q: params.get('q') })}` : '';
176
- }
176
+ };
177
177
 
178
178
 
179
179
  /**
@@ -0,0 +1,247 @@
1
+ /* global BookReader */
2
+
3
+ /**
4
+ * Toggles browser's native fullscreen mode if available device is not mobile
5
+ */
6
+ if (!isMobile()) {
7
+ const EVENT_NAMESPACE = '.bookreader_vendor-fullscreen';
8
+
9
+ jQuery.extend(BookReader.defaultOptions, {
10
+ /** @type {boolean} */
11
+ enableVendorFullscreenPlugin: true
12
+ });
13
+
14
+ /** @override */
15
+ BookReader.prototype.setup = (function(super_) {
16
+ return function(options) {
17
+ super_.call(this, options);
18
+
19
+ this.isVendorFullscreenActive = false;
20
+ };
21
+ })(BookReader.prototype.setup);
22
+
23
+ /** @override */
24
+ BookReader.prototype.getInitialMode = (function(super_) {
25
+ return function(params) {
26
+ let nextMode = super_.call(this, params);
27
+ if (this.isVendorFullscreenActive) {
28
+ nextMode = this.constMode1up;
29
+ }
30
+ return nextMode;
31
+ };
32
+ })(BookReader.prototype.getInitialMode);
33
+
34
+ /** @override */
35
+ BookReader.prototype.init = (function(super_) {
36
+ return function() {
37
+ super_.call(this);
38
+
39
+ if (!fullscreenAllowed()) {
40
+ return;
41
+ }
42
+ // In fullscreen mode the colorbox and overlay need to be inside the fullscreen element to display properly.
43
+ bindFullscreenChangeListener(this, (e) => {
44
+ e.data.resize();
45
+ e.data.updateBrClasses();
46
+ const cboxOverlay = $('#cboxOverlay');
47
+ const cbox = $('#colorbox');
48
+ if (isFullscreenActive()) {
49
+ // In full screen mode, the colorbox and overlay need
50
+ // to be children of the fullscreen element to display properly.
51
+ const $fullscreen = $(getFullscreenElement());
52
+ $fullscreen.append(cboxOverlay).append(cbox);
53
+ } else {
54
+ // In non-fullscreen mode, the colorbox and overlay need
55
+ // to be children of the main document body.
56
+ $(document.body).append(cboxOverlay).append(cbox);
57
+ }
58
+ });
59
+ };
60
+ })(BookReader.prototype.init);
61
+
62
+ /**
63
+ * Start fullscreen mode
64
+ */
65
+ BookReader.prototype.enterFullWindow = function() {
66
+ this.refs.$brContainer.css('opacity', 0);
67
+
68
+ const windowWidth = $(window).width();
69
+ if (windowWidth <= this.onePageMinBreakpoint) {
70
+ this.switchMode(this.constMode1up);
71
+ }
72
+
73
+ this.isVendorFullscreenActive = true;
74
+ this.updateBrClasses();
75
+
76
+ this.resize();
77
+ this.jumpToIndex(this.currentIndex());
78
+
79
+ this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
80
+
81
+ $(document).on(`keyup.${EVENT_NAMESPACE}`, e => {
82
+ if (e.keyCode === 27) this.exitFullScreen();
83
+ });
84
+ };
85
+
86
+ /**
87
+ * Exit from fullscreen mode
88
+ */
89
+ BookReader.prototype.exitFullWindow = function() {
90
+ this.refs.$brContainer.css('opacity', 0);
91
+
92
+ $(document).off('keyup' + EVENT_NAMESPACE);
93
+
94
+ this.isFullscreenActive = false;
95
+ this.updateBrClasses();
96
+
97
+ this.resize();
98
+ this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
99
+ };
100
+
101
+ /**
102
+ * Returns true if fullscreen mode is enabled
103
+ *
104
+ * @returns {boolean}
105
+ */
106
+ BookReader.prototype.isFullscreen = function() {
107
+ return isFullscreenActive() || this.isVendorFullscreenActive;
108
+ };
109
+
110
+ /**
111
+ * Toggle screen
112
+ */
113
+ BookReader.prototype.toggleFullscreen = function() {
114
+ if (this.isFullscreen()) {
115
+ if (fullscreenAllowed()) {
116
+ exitFullscreen();
117
+ } else {
118
+ this.exitFullWindow();
119
+ }
120
+ } else {
121
+ if (fullscreenAllowed()) {
122
+ requestFullscreen(this.refs.$br[0]);
123
+ } else {
124
+ this.enterFullWindow();
125
+ }
126
+ }
127
+ };
128
+
129
+ /** @deprecated */
130
+ BookReader.util.isMobile = isMobile;
131
+
132
+ /** @deprecated */
133
+ BookReader.util.getFullscreenElement = getFullscreenElement;
134
+
135
+ /** @deprecated */
136
+ BookReader.util.bindFullscreenChangeListener = bindFullscreenChangeListener;
137
+
138
+ /** @deprecated */
139
+ BookReader.util.fullscreenAllowed = fullscreenAllowed;
140
+
141
+ /** @deprecated */
142
+ BookReader.util.requestFullscreen = requestFullscreen;
143
+
144
+ /** @deprecated */
145
+ BookReader.util.exitFullscreen = exitFullscreen;
146
+
147
+ /** @deprecated */
148
+ BookReader.util.isFullscreenActive = isFullscreenActive;
149
+ }
150
+
151
+
152
+ /**
153
+ * Returns the DOM element being used for fullscreen.
154
+ *
155
+ * @returns {HTMLElement}
156
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/fullscreenElement
157
+ */
158
+ export function getFullscreenElement() {
159
+ return document.fullscreenElement ||
160
+ document.webkitFullscreenElement ||
161
+ document.mozFullScreenElement ||
162
+ document.msFullscreenElement;
163
+ }
164
+
165
+ /**
166
+ * Returns true if the document is in fullscreen mode.
167
+ *
168
+ * @returns {boolean}
169
+ */
170
+ export function isFullscreenActive() {
171
+ const fullscreenElement = getFullscreenElement();
172
+ return fullscreenElement !== null && fullscreenElement !== undefined;
173
+ }
174
+
175
+ /**
176
+ * Exits fullscreen mode.
177
+ *
178
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen
179
+ */
180
+ export function exitFullscreen() {
181
+ if (document.exitFullscreen) {
182
+ document.exitFullscreen();
183
+ } else if (document.webkitExitFullscreen) {
184
+ document.webkitExitFullscreen();
185
+ } else if (document.mozCancelFullScreen) {
186
+ document.mozCancelFullScreen();
187
+ } else if (document.msExitFullscreen) {
188
+ document.msExitFullscreen();
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Requests fullscreen mode for the given element
194
+ *
195
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen
196
+ */
197
+ export function requestFullscreen(element) {
198
+ if (element.requestFullscreen) {
199
+ element.requestFullscreen();
200
+ } else if (element.webkitRequestFullscreen) {
201
+ element.webkitRequestFullscreen();
202
+ } else if (element.mozRequestFullScreen) {
203
+ element.mozRequestFullScreen();
204
+ } else if (element.msRequestFullscreen) {
205
+ element.msRequestFullscreen();
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Returns true if fullscreen mode is allowed on this device and document.
211
+ *
212
+ * @returns {boolean}
213
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled
214
+ */
215
+ export function fullscreenAllowed() {
216
+ return (document.fullscreenEnabled ||
217
+ document.webkitFullscreenEnabled ||
218
+ document.mozFullScreenEnabled ||
219
+ document.msFullScreenEnabled);
220
+ }
221
+
222
+ /**
223
+ * jQuery-style binding to a fullscreenchange event.
224
+ *
225
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event
226
+ */
227
+ export function bindFullscreenChangeListener(
228
+ data, fullscreenchangeListener
229
+ ) {
230
+ const event = 'fullscreenchange ';
231
+ const vendor_prefixes = [
232
+ 'webkit',
233
+ 'moz',
234
+ 'ms'
235
+ ];
236
+ const all_events = (event + vendor_prefixes.join(event) + event).trim();
237
+ $(document).on(all_events, data, fullscreenchangeListener);
238
+ }
239
+
240
+ /**
241
+ * Returns true if current device is mobile
242
+ *
243
+ * @returns {boolean}
244
+ */
245
+ export function isMobile() {
246
+ return (typeof window.orientation !== 'undefined') || (navigator.userAgent.indexOf('IEMobile') !== -1);
247
+ }