@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,287 @@
1
+ /* global BookReader */
2
+ /**
3
+ * Adds mobile navigation at responsive breakpoint
4
+ */
5
+
6
+ import * as utils from '../BookReader/utils.js';
7
+ import 'jquery.mmenu/dist/js/jquery.mmenu.min.js';
8
+ import 'jquery.mmenu/dist/addons/navbars/jquery.mmenu.navbars.min.js';
9
+
10
+ //contains all filters and labels for checkboxs
11
+ const FILTERLIST = [
12
+ {
13
+ filter: "grayscale(100%)",
14
+ label: "Grayscale"
15
+ },
16
+ {
17
+ filter: "brightness(120%)",
18
+ label: "High brightness"
19
+ },
20
+ {
21
+ filter: "invert(100%)",
22
+ label: "Inverted (dark mode)"
23
+ },
24
+ {
25
+ filter: "contrast(120%)",
26
+ label: "High contrast"
27
+ },
28
+ ];
29
+
30
+ jQuery.extend(BookReader.defaultOptions, {
31
+ enableMobileNav: true,
32
+ mobileNavTitle: 'Internet Archive',
33
+ mobileNavFullscreenOnly: false,
34
+ });
35
+
36
+ BookReader.prototype.setup = (function(super_) {
37
+ return function (options) {
38
+ super_.call(this, options);
39
+
40
+ this.enableMobileNav = options.enableMobileNav;
41
+ this.mobileNavTitle = options.mobileNavTitle;
42
+ this.mobileNavFullscreenOnly = options.mobileNavFullscreenOnly;
43
+
44
+ this.refs.$mmenu = null;
45
+ };
46
+ })(BookReader.prototype.setup);
47
+
48
+
49
+ // Extend initToolbar
50
+ BookReader.prototype.initToolbar = (function (super_) {
51
+ return function (mode, ui) {
52
+ let $mmenuEl;
53
+ if (this.enableMobileNav) {
54
+ const $drawerEl = this.buildMobileDrawerElement();
55
+ this.refs.$br.append($drawerEl);
56
+
57
+ // Render info into mobile info before mmenu
58
+ this.buildInfoDiv(this.$('.BRmobileInfo'));
59
+ this.buildShareDiv(this.$('.BRmobileShare'));
60
+
61
+ $mmenuEl = $drawerEl;
62
+ $mmenuEl.mmenu({
63
+ navbars: [
64
+ { "position": "top" },
65
+ ],
66
+ navbar: {
67
+ add: true,
68
+ title: this.mobileNavTitle,
69
+ titleLink: 'panel'
70
+ },
71
+ extensions: [ "panelshadow" ],
72
+ }, {
73
+ offCanvas: {
74
+ wrapPageIfNeeded: false,
75
+ zposition: 'next',
76
+ pageSelector: this.el,
77
+ }
78
+ });
79
+
80
+ const $BRpageviewField = $mmenuEl.find('.BRpageviewValue');
81
+ $mmenuEl.data('mmenu').bind('opened', () => {
82
+ // Update "Link to this page view" link
83
+ if ($BRpageviewField.length) {
84
+ $BRpageviewField.val(window.location.href);
85
+ }
86
+ });
87
+
88
+ //apply filters when checkboxs clicked
89
+ $drawerEl.find('.BRcheckbox-filters').click(() => applyFilters($drawerEl, this));
90
+
91
+ // Bind mobile switch buttons
92
+ $drawerEl.find('.DrawerLayoutButton.one_page_mode').click(
93
+ () => this.switchMode(this.constMode1up));
94
+ $drawerEl.find('.DrawerLayoutButton.two_page_mode').click(
95
+ () => this.switchMode(this.constMode2up));
96
+ $drawerEl.find('.DrawerLayoutButton.thumbnail_mode').click(
97
+ () => this.switchMode(this.constModeThumb));
98
+
99
+ if (this.mobileNavFullscreenOnly) {
100
+ $(document.body).addClass('BRbodyMobileNavEnabledFullscreen');
101
+ } else {
102
+ $(document.body).addClass('BRbodyMobileNavEnabled');
103
+ }
104
+
105
+ this.refs.$mmenu = $mmenuEl;
106
+
107
+ }
108
+
109
+ // Call the parent method at the end, because it binds events to DOM
110
+ super_.apply(this, arguments);
111
+
112
+
113
+ if (this.enableMobileNav) {
114
+ // Need to bind more, console after toolbar is initialized
115
+ this.$('.BRmobileHamburger').click(() => {
116
+ if ($mmenuEl.data('mmenu').getInstance().vars.opened) {
117
+ $mmenuEl.data('mmenu').close();
118
+ } else {
119
+ $mmenuEl.data('mmenu').open();
120
+ this.trigger("mobileNavOpen");
121
+ }
122
+ });
123
+
124
+
125
+ const closeMobileMenu = (e) => {
126
+ // Need to close the mobile menu to reset DOM & Style
127
+ // driven by menu plugin
128
+ const width = $( window ).width();
129
+ const mobileMenuIsOpen = $mmenuEl.data('mmenu').getInstance().vars.opened;
130
+ // $brBreakPointMobile: 800px;
131
+ if (mobileMenuIsOpen && (width >= 800)) {
132
+ $mmenuEl.data('mmenu').close ();
133
+ }
134
+ };
135
+
136
+ window.addEventListener('resize', utils.debounce(closeMobileMenu, 900));
137
+ }
138
+ };
139
+ })(BookReader.prototype.initToolbar);
140
+
141
+
142
+ BookReader.prototype.buildToolbarElement = (function (super_) {
143
+ return function () {
144
+ const $el = super_.call(this);
145
+ if (this.enableMobileNav) {
146
+ const escapedTitle = BookReader.util.escapeHTML(this.bookTitle);
147
+ const toolbar = `
148
+ <span class="BRmobileHamburgerWrapper">
149
+ <button class="BRmobileHamburger"></button>
150
+ <span class="BRtoolbarMobileTitle" title="${escapedTitle}">${escapedTitle}</span>
151
+ </span>
152
+ `;
153
+ $el
154
+ .addClass('responsive')
155
+ .prepend($(toolbar));
156
+ }
157
+ return $el;
158
+ };
159
+ })(BookReader.prototype.buildToolbarElement);
160
+
161
+ /**
162
+ * This method builds the html for the mobile drawer. It can be decorated to
163
+ * extend the default drawer.
164
+ * @return {jqueryElement}
165
+ */
166
+ BookReader.prototype.buildMobileDrawerElement = function() {
167
+ let experimentalHtml = '';
168
+ //builds filters checkbox html
169
+ if (this.enableExperimentalControls) {
170
+ experimentalHtml = `
171
+ <p class="DrawerSettingsTitle">Visual Adjustment</p>
172
+ <div class="BRcheckbox-group-filters">
173
+ `;
174
+ FILTERLIST.forEach( (el, i) => {
175
+ const checkboxHtml = `
176
+ <input type="checkbox" class="BRcheckbox-filters" id="filter${i}">
177
+ <label for="filter${i}" class="BRcheckbox-label-filters">${el.label}</label><br>
178
+
179
+ `;
180
+ experimentalHtml = experimentalHtml.concat(checkboxHtml);
181
+ });
182
+ experimentalHtml = experimentalHtml.concat("</div>");
183
+ }
184
+
185
+
186
+ const settingsSection = `
187
+ <span>
188
+ <span class="DrawerIconWrapper">
189
+ <img class="DrawerIcon" src="${`${this.imagesBaseURL}icon_gear.svg`}" alt="settings-icon"/>
190
+ </span>
191
+ Settings
192
+ </span>
193
+ <div class=DrawerSettingsWrapper>
194
+ <div class="DrawerSettingsLayoutWrapper">
195
+ <button class="DrawerLayoutButton one_page_mode">
196
+ <img src="${this.imagesBaseURL}icon_one_page.svg" alt="Single Page"/>
197
+ <br>
198
+ One Page
199
+ </button>
200
+ <button class="DrawerLayoutButton two_page_mode TwoPagesButton">
201
+ <img src="${this.imagesBaseURL}icon_two_pages.svg" alt="Two Pages"/>
202
+ <br>
203
+ Two Pages
204
+ </button>
205
+ <button class="DrawerLayoutButton thumbnail_mode">
206
+ <img src="${this.imagesBaseURL}icon_thumbnails.svg" alt="Thumbnails"/>
207
+ <br>
208
+ Thumbnails
209
+ </button>
210
+ </div>
211
+ <br>
212
+ <div class="DrawerSettingsTitle">Zoom</div>
213
+ <button class='BRicon zoom_out'></button>
214
+ <button class='BRicon zoom_in'></button>
215
+ <br style="clear:both"><br><br>
216
+ ${experimentalHtml}
217
+ </div>
218
+ `;
219
+ const moreInfo = `
220
+ <span>
221
+ <span class="DrawerIconWrapper ">
222
+ <img class="DrawerIcon" src="${this.imagesBaseURL}icon_info.svg" alt="info-icon"/>
223
+ </span>
224
+ About This Book
225
+ </span>
226
+ <div class="BRmobileInfo"></div>
227
+ `;
228
+ const share = `
229
+ <span>
230
+ <span class="DrawerIconWrapper">
231
+ <img class="DrawerIcon" src="${this.imagesBaseURL}icon_share.svg" alt="info-share"/>
232
+ </span>
233
+ Share This Book
234
+ </span>
235
+ <div class="BRmobileShare"></div>
236
+ `;
237
+ const navMenu = `
238
+ <nav id="BRmobileMenu" class="BRmobileMenu">
239
+ <ul>
240
+ <li class="BRmobileMenu__settings">${settingsSection}</li>
241
+ <li class="BRmobileMenu__moreInfoRow">${moreInfo}</li>
242
+ <li class="BRmobileMenu__share">${share}</li>
243
+ </ul>
244
+ </nav>
245
+ `;
246
+
247
+ const $el = $(navMenu);
248
+ return $el;
249
+ };
250
+
251
+ /**
252
+ * Mmenu moves itself out side of the root BookReader element, so we need to
253
+ * include it in the scoped $ function.
254
+ */
255
+ BookReader.prototype.$ = (function (super_) {
256
+ return function (arg) {
257
+ let $results = super_.call(this, arg);
258
+ if (this.refs.$mmenu) {
259
+ $results = $results.add(this.refs.$mmenu.find(arg));
260
+ }
261
+ return $results;
262
+ };
263
+ })(BookReader.prototype.$);
264
+
265
+ /**
266
+ * Dynamically creates styles combining different filters for BookReaders imgs
267
+ * based on filters checkbox
268
+ */
269
+ const applyFilters = (drawerEl, br) => {
270
+ let filterStr = "";
271
+
272
+ $('.BRcheckbox-filters').each(
273
+ (i, el) => {
274
+ br.refs.$br.removeClass("filter-applied");
275
+ if ($(el).is(':checked')) {
276
+ br.refs.$br.addClass($(el).attr("filter-applied"));
277
+ filterStr = filterStr + FILTERLIST[i].filter;
278
+ }
279
+ }
280
+ );
281
+ const filtersSheet = $("#filtersStyle")[0] || document.createElement('style');
282
+ filtersSheet.id = "filtersStyle";
283
+ filtersSheet.innerHTML = `.BRpagecontainer img {
284
+ filter: ${filterStr};
285
+ -webkit-filter: ${filterStr};}`;
286
+ document.body.appendChild(filtersSheet);
287
+ };
@@ -0,0 +1,68 @@
1
+ import * as docCookies from '../util/docCookies.js';
2
+
3
+ /* global BookReader */
4
+
5
+ /** @deprecated Exposed for backward compatibility */
6
+ BookReader.docCookies = docCookies;
7
+
8
+ /**
9
+ * Plugin to remember the current page number in a cookie
10
+ */
11
+ jQuery.extend(BookReader.defaultOptions, {
12
+ enablePageResume: true,
13
+ /** @type {string|null} eg '/', '/details/id' */
14
+ resumeCookiePath: null,
15
+ });
16
+
17
+ /** @override */
18
+ BookReader.prototype.init = (function(super_) {
19
+ return function() {
20
+ super_.call(this);
21
+ if (this.options.enablePageResume) {
22
+ this.bind(BookReader.eventNames.fragmentChange, () => {
23
+ const params = this.paramsFromCurrent();
24
+ this.updateResumeValue(params.index);
25
+ });
26
+ }
27
+ };
28
+ })(BookReader.prototype.init);
29
+
30
+ /**
31
+ * Gets page resume value, for remembering reader's page
32
+ * Can be overridden for different implementation
33
+ *
34
+ * @return {number|null}
35
+ */
36
+ BookReader.prototype.getResumeValue = function() {
37
+ const val = BookReader.docCookies.getItem('br-resume');
38
+ if (val !== null) return parseInt(val);
39
+ else return null;
40
+ };
41
+
42
+ /**
43
+ * Return cookie path using pathname up to /page/... or /mode/...
44
+ * using window.location.pathname for urlPathPart:
45
+ * - matches encoding
46
+ * - ignores querystring part
47
+ * - ignores fragment part (after #)
48
+ * @param {string} urlPathPart - window.location.pathname
49
+ */
50
+ BookReader.prototype.getCookiePath = function(urlPathPart) {
51
+ return urlPathPart.match('.+?(?=/page/|/mode/|$)')[0];
52
+ };
53
+
54
+ /**
55
+ * Sets page resume value, for remembering reader's page
56
+ * Can be overridden for different implementation
57
+ *
58
+ * @param {Number} index leaf index
59
+ * @param {string} [cookieName]
60
+ */
61
+ BookReader.prototype.updateResumeValue = function(index, cookieName) {
62
+ const ttl = new Date(+new Date + 12096e5); // 2 weeks
63
+ // For multiple files in item, leave resumeCookiePath blank
64
+ // It's likely we can remove resumeCookiePath using getCookiePath()
65
+ const path = this.options.resumeCookiePath
66
+ || this.getCookiePath(window.location.pathname);
67
+ BookReader.docCookies.setItem(cookieName || 'br-resume', index, ttl, path, null, false);
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;