@internetarchive/bookreader 5.0.0-11 → 5.0.0-111

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 (381) hide show
  1. package/BookReader/474.js +2 -0
  2. package/BookReader/474.js.map +1 -0
  3. package/BookReader/BookReader.css +649 -1225
  4. package/BookReader/BookReader.js +1 -1
  5. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  6. package/BookReader/BookReader.js.map +1 -1
  7. package/BookReader/bergamot-translator-worker.js +2966 -0
  8. package/BookReader/bergamot-translator-worker.wasm +0 -0
  9. package/BookReader/hypothesis/LICENSE +50 -0
  10. package/BookReader/hypothesis/README.md +55 -0
  11. package/BookReader/hypothesis/build/boot.js +1 -0
  12. package/BookReader/hypothesis/build/manifest.json +20 -0
  13. package/BookReader/hypothesis/build/scripts/annotator.bundle.js +184 -0
  14. package/BookReader/hypothesis/build/scripts/annotator.bundle.js.map +1 -0
  15. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js +798 -0
  16. package/BookReader/hypothesis/build/scripts/sidebar.bundle.js.map +1 -0
  17. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js +711 -0
  18. package/BookReader/hypothesis/build/scripts/ui-playground.bundle.js.map +1 -0
  19. package/BookReader/hypothesis/build/styles/annotator.css +2235 -0
  20. package/BookReader/hypothesis/build/styles/annotator.css.map +1 -0
  21. package/BookReader/hypothesis/build/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  23. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  24. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  25. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  26. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  27. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  28. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  29. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  30. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  31. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  32. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  33. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  34. package/BookReader/hypothesis/build/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  35. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  36. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  37. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  38. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  39. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  40. package/BookReader/hypothesis/build/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  41. package/BookReader/hypothesis/build/styles/highlights.css +2 -0
  42. package/BookReader/hypothesis/build/styles/highlights.css.map +1 -0
  43. package/BookReader/hypothesis/build/styles/katex.min.css +2 -0
  44. package/BookReader/hypothesis/build/styles/katex.min.css.map +1 -0
  45. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css +2 -0
  46. package/BookReader/hypothesis/build/styles/pdfjs-overrides.css.map +1 -0
  47. package/BookReader/hypothesis/build/styles/sidebar.css +2731 -0
  48. package/BookReader/hypothesis/build/styles/sidebar.css.map +1 -0
  49. package/BookReader/hypothesis/build/styles/ui-playground.css +2659 -0
  50. package/BookReader/hypothesis/build/styles/ui-playground.css.map +1 -0
  51. package/BookReader/hypothesis/package.json +126 -0
  52. package/BookReader/ia-bookreader-bundle.js +1904 -0
  53. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  54. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  55. package/BookReader/icons/1up.svg +1 -1
  56. package/BookReader/icons/2up.svg +1 -1
  57. package/BookReader/icons/advance.svg +1 -1
  58. package/BookReader/icons/chevron-right.svg +1 -1
  59. package/BookReader/icons/close-circle-dark.svg +1 -1
  60. package/BookReader/icons/close-circle.svg +1 -1
  61. package/BookReader/icons/fullscreen.svg +1 -1
  62. package/BookReader/icons/fullscreen_exit.svg +1 -1
  63. package/BookReader/icons/hamburger.svg +1 -1
  64. package/BookReader/icons/left-arrow.svg +1 -1
  65. package/BookReader/icons/magnify-minus.svg +1 -1
  66. package/BookReader/icons/magnify-plus.svg +1 -1
  67. package/BookReader/icons/magnify.svg +1 -1
  68. package/BookReader/icons/pause.svg +1 -1
  69. package/BookReader/icons/play.svg +1 -1
  70. package/BookReader/icons/playback-speed.svg +1 -1
  71. package/BookReader/icons/read-aloud.svg +1 -1
  72. package/BookReader/icons/review.svg +1 -1
  73. package/BookReader/icons/slider-toggle.svg +1 -0
  74. package/BookReader/icons/thumbnails.svg +1 -1
  75. package/BookReader/icons/voice.svg +1 -0
  76. package/BookReader/icons/volume-full.svg +1 -1
  77. package/BookReader/images/BRicons.svg +3 -3
  78. package/BookReader/images/books_graphic.svg +1 -1
  79. package/BookReader/images/hypothesis.ico +0 -0
  80. package/BookReader/images/icon_book.svg +1 -1
  81. package/BookReader/images/icon_bookmark.svg +1 -1
  82. package/BookReader/images/icon_experiment.svg +1 -0
  83. package/BookReader/images/icon_gear.svg +1 -1
  84. package/BookReader/images/icon_hamburger.svg +1 -1
  85. package/BookReader/images/icon_home.svg +1 -1
  86. package/BookReader/images/icon_info.svg +1 -1
  87. package/BookReader/images/icon_one_page.svg +1 -1
  88. package/BookReader/images/icon_pause.svg +1 -1
  89. package/BookReader/images/icon_play.svg +1 -1
  90. package/BookReader/images/icon_playback-rate.svg +1 -1
  91. package/BookReader/images/icon_search_button.svg +1 -1
  92. package/BookReader/images/icon_share.svg +1 -1
  93. package/BookReader/images/icon_skip-ahead.svg +1 -1
  94. package/BookReader/images/icon_skip-back.svg +1 -1
  95. package/BookReader/images/icon_speaker.svg +1 -1
  96. package/BookReader/images/icon_speaker_open.svg +1 -1
  97. package/BookReader/images/icon_thumbnails.svg +1 -1
  98. package/BookReader/images/icon_toc.svg +1 -1
  99. package/BookReader/images/icon_two_pages.svg +1 -1
  100. package/BookReader/images/marker_chap-off.svg +1 -1
  101. package/BookReader/images/marker_chap-on.svg +1 -1
  102. package/BookReader/images/marker_srch-on.svg +1 -1
  103. package/BookReader/images/translate.svg +1 -0
  104. package/BookReader/images/unviewable_page.png +0 -0
  105. package/BookReader/jquery-3.js +2 -0
  106. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  107. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  108. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  109. package/BookReader/plugins/plugin.autoplay.js +1 -1
  110. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  111. package/BookReader/plugins/plugin.chapters.js +22 -1
  112. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  113. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  114. package/BookReader/plugins/plugin.experiments.js +3 -0
  115. package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -0
  116. package/BookReader/plugins/plugin.experiments.js.map +1 -0
  117. package/BookReader/plugins/plugin.iframe.js +1 -1
  118. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  119. package/BookReader/plugins/plugin.iiif.js +2 -0
  120. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  121. package/BookReader/plugins/plugin.resume.js +1 -1
  122. package/BookReader/plugins/plugin.resume.js.map +1 -1
  123. package/BookReader/plugins/plugin.search.js +2 -1
  124. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  125. package/BookReader/plugins/plugin.search.js.map +1 -1
  126. package/BookReader/plugins/plugin.text_selection.js +24 -1
  127. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  128. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  129. package/BookReader/plugins/plugin.translate.js +159 -0
  130. package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
  131. package/BookReader/plugins/plugin.translate.js.map +1 -0
  132. package/BookReader/plugins/plugin.tts.js +1 -1
  133. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  134. package/BookReader/plugins/plugin.tts.js.map +1 -1
  135. package/BookReader/plugins/plugin.url.js +2 -1
  136. package/BookReader/plugins/plugin.url.js.LICENSE.txt +1 -0
  137. package/BookReader/plugins/plugin.url.js.map +1 -1
  138. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  139. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  140. package/BookReader/plugins/translator-worker.js +2 -0
  141. package/BookReader/plugins/translator-worker.js.map +1 -0
  142. package/BookReader/silence.mp3 +0 -0
  143. package/BookReader/translator-worker.js +475 -0
  144. package/BookReader/webcomponents-bundle.js +3 -0
  145. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  146. package/BookReader/webcomponents-bundle.js.map +1 -0
  147. package/README.md +14 -3
  148. package/jsconfig.json +19 -0
  149. package/package.json +93 -70
  150. package/src/BookReader/BookModel.js +92 -46
  151. package/src/BookReader/DragScrollable.js +233 -0
  152. package/src/BookReader/ImageCache.js +49 -16
  153. package/src/BookReader/Mode1Up.js +66 -365
  154. package/src/BookReader/Mode1UpLit.js +392 -0
  155. package/src/BookReader/Mode2Up.js +87 -1315
  156. package/src/BookReader/Mode2UpLit.js +786 -0
  157. package/src/BookReader/ModeAbstract.js +43 -0
  158. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  159. package/src/BookReader/ModeSmoothZoom.js +312 -0
  160. package/src/BookReader/ModeThumb.js +29 -15
  161. package/src/BookReader/Navbar/Navbar.js +201 -76
  162. package/src/BookReader/PageContainer.js +120 -23
  163. package/src/BookReader/ReduceSet.js +2 -2
  164. package/src/BookReader/Toolbar/Toolbar.js +18 -40
  165. package/src/BookReader/events.js +3 -3
  166. package/src/BookReader/options.js +94 -17
  167. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  168. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  169. package/src/BookReader/utils/SelectionObserver.js +53 -0
  170. package/src/BookReader/utils/classes.js +1 -1
  171. package/src/BookReader/utils.js +136 -12
  172. package/src/BookReader.js +695 -1228
  173. package/src/BookReaderPlugin.js +52 -0
  174. package/src/assets/icons/magnify-minus.svg +3 -7
  175. package/src/assets/icons/magnify-plus.svg +3 -7
  176. package/src/assets/icons/slider-toggle.svg +1 -0
  177. package/src/assets/icons/voice.svg +1 -0
  178. package/src/assets/images/hypothesis.ico +0 -0
  179. package/src/assets/images/icon_experiment.svg +1 -0
  180. package/src/assets/images/translate.svg +1 -0
  181. package/src/assets/images/unviewable_page.png +0 -0
  182. package/src/assets/silence.mp3 +0 -0
  183. package/src/css/BookReader.scss +1 -5
  184. package/src/css/_BRBookmarks.scss +1 -1
  185. package/src/css/_BRComponent.scss +1 -1
  186. package/src/css/_BRicon.scss +8 -2
  187. package/src/css/_BRmain.scss +16 -3
  188. package/src/css/_BRnav.scss +74 -70
  189. package/src/css/_BRpages.scss +171 -42
  190. package/src/css/_BRsearch.scss +69 -30
  191. package/src/css/_BRtoolbar.scss +5 -5
  192. package/src/css/_TextSelection.scss +188 -24
  193. package/src/css/_colorbox.scss +2 -2
  194. package/src/css/_controls.scss +24 -7
  195. package/src/css/_icons.scss +8 -1
  196. package/src/{BookNavigator/assets → css}/button-base.js +2 -2
  197. package/src/css/icon_checkmark.js +9 -0
  198. package/src/css/sharedStyles.js +15 -0
  199. package/src/ia-bookreader/downloads/downloads-provider.js +81 -0
  200. package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +25 -5
  201. package/src/ia-bookreader/ia-bookreader.js +666 -0
  202. package/src/ia-bookreader/sharing.js +27 -0
  203. package/src/ia-bookreader/viewable-files.js +98 -0
  204. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +17 -17
  205. package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +75 -67
  206. package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +4 -3
  207. package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +1 -1
  208. package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +43 -31
  209. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +48 -49
  210. package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +3 -3
  211. package/src/plugins/bookmarks/bookmarks-provider.js +63 -0
  212. package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +1 -1
  213. package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +117 -68
  214. package/src/plugins/plugin.archive_analytics.js +84 -78
  215. package/src/plugins/plugin.autoplay.js +99 -104
  216. package/src/plugins/plugin.chapters.js +319 -205
  217. package/src/plugins/plugin.experiments.js +339 -0
  218. package/src/plugins/plugin.iframe.js +1 -1
  219. package/src/plugins/plugin.iiif.js +141 -0
  220. package/src/plugins/plugin.resume.js +54 -51
  221. package/src/plugins/plugin.text_selection.js +539 -219
  222. package/src/plugins/plugin.vendor-fullscreen.js +5 -5
  223. package/src/plugins/search/plugin.search.js +374 -392
  224. package/src/{BookNavigator → plugins}/search/search-provider.js +59 -27
  225. package/src/{BookNavigator → plugins}/search/search-results.js +105 -76
  226. package/src/plugins/search/utils.js +50 -0
  227. package/src/plugins/search/view.js +50 -68
  228. package/src/plugins/translate/TranslationManager.js +164 -0
  229. package/src/plugins/translate/plugin.translate.js +512 -0
  230. package/src/plugins/tts/AbstractTTSEngine.js +78 -49
  231. package/src/plugins/tts/FestivalTTSEngine.js +20 -30
  232. package/src/plugins/tts/PageChunk.js +33 -21
  233. package/src/plugins/tts/PageChunkIterator.js +11 -17
  234. package/src/plugins/tts/WebTTSEngine.js +131 -91
  235. package/src/plugins/tts/plugin.tts.js +345 -350
  236. package/src/plugins/tts/utils.js +77 -49
  237. package/src/plugins/url/UrlPlugin.js +211 -0
  238. package/src/plugins/{plugin.url.js → url/plugin.url.js} +105 -20
  239. package/src/util/TextSelectionManager.js +532 -0
  240. package/src/util/browserSniffing.js +33 -1
  241. package/src/util/cache.js +20 -0
  242. package/src/util/docCookies.js +21 -2
  243. package/src/util/lit.js +15 -0
  244. package/src/util/strings.js +1 -0
  245. package/.babelrc +0 -12
  246. package/.dependabot/config.yml +0 -6
  247. package/.eslintrc.js +0 -50
  248. package/.gitattributes +0 -2
  249. package/.github/ISSUE_TEMPLATE/bug.md +0 -32
  250. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -30
  251. package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -15
  252. package/.github/workflows/node.js.yml +0 -37
  253. package/.github/workflows/npm-publish.yml +0 -47
  254. package/.testcaferc.json +0 -5
  255. package/BookReader/bookreader-component-bundle.js +0 -1450
  256. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  257. package/BookReader/bookreader-component-bundle.js.map +0 -1
  258. package/BookReader/jquery-1.10.1.js +0 -2
  259. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  260. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  261. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  262. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  263. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  264. package/BookReaderDemo/BookReaderDemo.css +0 -41
  265. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -115
  266. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  267. package/BookReaderDemo/BookReaderJSSimple.js +0 -55
  268. package/BookReaderDemo/IIIFBookReader.js +0 -207
  269. package/BookReaderDemo/assets/v5/Bookreader-logo-cool-grad.svg +0 -1
  270. package/BookReaderDemo/assets/v5/Bookreader-logo-flat.svg +0 -1
  271. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-cool-grad.png +0 -0
  272. package/BookReaderDemo/assets/v5/Bookreader-logo-hex-flat.png +0 -0
  273. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.png +0 -0
  274. package/BookReaderDemo/assets/v5/Bookreader-logo-lines.svg +0 -1
  275. package/BookReaderDemo/assets/v5/Bookreader-logo-warm.svg +0 -1
  276. package/BookReaderDemo/assets/v5/bookreader-logo-renders@1x.png +0 -0
  277. package/BookReaderDemo/assets/v5/bookreader-logo-renders@2x.png +0 -0
  278. package/BookReaderDemo/assets/v5/bookreader-v5-screenshot.png +0 -0
  279. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  280. package/BookReaderDemo/demo-advanced.html +0 -33
  281. package/BookReaderDemo/demo-autoplay.html +0 -38
  282. package/BookReaderDemo/demo-embed-iframe-src.html +0 -84
  283. package/BookReaderDemo/demo-embed.html +0 -26
  284. package/BookReaderDemo/demo-fullscreen-mobile.html +0 -36
  285. package/BookReaderDemo/demo-fullscreen.html +0 -33
  286. package/BookReaderDemo/demo-iiif.html +0 -34
  287. package/BookReaderDemo/demo-iiif.js +0 -26
  288. package/BookReaderDemo/demo-internetarchive.html +0 -74
  289. package/BookReaderDemo/demo-multiple.html +0 -43
  290. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  291. package/BookReaderDemo/demo-preview-pages.html +0 -1092
  292. package/BookReaderDemo/demo-simple.html +0 -34
  293. package/BookReaderDemo/demo-vendor-fullscreen.html +0 -36
  294. package/BookReaderDemo/immersion-1up.html +0 -64
  295. package/BookReaderDemo/immersion-mode.html +0 -35
  296. package/BookReaderDemo/toggle_controls.html +0 -53
  297. package/BookReaderDemo/view_mode.html +0 -39
  298. package/BookReaderDemo/viewmode-cycle.html +0 -41
  299. package/CHANGELOG.md +0 -495
  300. package/CONTRIBUTING.md +0 -7
  301. package/codecov.yml +0 -17
  302. package/index.html +0 -31
  303. package/karma.conf.js +0 -23
  304. package/screenshot.png +0 -0
  305. package/scripts/postversion.js +0 -10
  306. package/scripts/preversion.js +0 -14
  307. package/scripts/version.js +0 -26
  308. package/src/BookNavigator/BookModel.js +0 -14
  309. package/src/BookNavigator/BookNavigator.js +0 -446
  310. package/src/BookNavigator/assets/book-loader.js +0 -27
  311. package/src/BookNavigator/assets/icon_checkmark.js +0 -6
  312. package/src/BookNavigator/assets/icon_close.js +0 -3
  313. package/src/BookNavigator/bookmarks/bookmarks-provider.js +0 -53
  314. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  315. package/src/BookNavigator/downloads/downloads-provider.js +0 -66
  316. package/src/BookNavigator/search/a-search-result.js +0 -55
  317. package/src/BookReader/DebugConsole.js +0 -54
  318. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  319. package/src/ItemNavigator/ItemNavigator.js +0 -376
  320. package/src/ItemNavigator/providers/sharing.js +0 -29
  321. package/src/css/_MobileNav.scss +0 -194
  322. package/src/dragscrollable-br.js +0 -261
  323. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  324. package/src/plugins/plugin.mobile_nav.js +0 -287
  325. package/tests/BookReader/BookModel.test.js +0 -312
  326. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  327. package/tests/BookReader/DebugConsole.test.js +0 -25
  328. package/tests/BookReader/ImageCache.test.js +0 -150
  329. package/tests/BookReader/Mode1Up.test.js +0 -164
  330. package/tests/BookReader/Mode2Up.test.js +0 -247
  331. package/tests/BookReader/Navbar/Navbar.test.js +0 -169
  332. package/tests/BookReader/PageContainer.test.js +0 -115
  333. package/tests/BookReader/ReduceSet.test.js +0 -38
  334. package/tests/BookReader/Toolbar/Toolbar.test.js +0 -26
  335. package/tests/BookReader/utils/classes.test.js +0 -88
  336. package/tests/BookReader/utils.test.js +0 -109
  337. package/tests/BookReader.options.test.js +0 -39
  338. package/tests/BookReader.test.js +0 -301
  339. package/tests/e2e/README.md +0 -75
  340. package/tests/e2e/autoplay.test.js +0 -13
  341. package/tests/e2e/base.test.js +0 -35
  342. package/tests/e2e/helpers/base.js +0 -263
  343. package/tests/e2e/helpers/debug.js +0 -13
  344. package/tests/e2e/helpers/desktopSearch.js +0 -72
  345. package/tests/e2e/helpers/mobileSearch.js +0 -85
  346. package/tests/e2e/helpers/mockSearch.js +0 -93
  347. package/tests/e2e/helpers/rightToLeft.js +0 -29
  348. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  349. package/tests/e2e/models/BookReader.js +0 -11
  350. package/tests/e2e/models/Navigation.js +0 -56
  351. package/tests/e2e/rightToLeft.test.js +0 -20
  352. package/tests/e2e/viewmode.test.js +0 -37
  353. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  354. package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +0 -133
  355. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +0 -222
  356. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  357. package/tests/karma/BookNavigator/search/search-results.test.js +0 -240
  358. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  359. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  360. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  361. package/tests/plugins/plugin.autoplay.test.js +0 -52
  362. package/tests/plugins/plugin.chapters.test.js +0 -130
  363. package/tests/plugins/plugin.iframe.test.js +0 -42
  364. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  365. package/tests/plugins/plugin.resume.test.js +0 -98
  366. package/tests/plugins/plugin.text_selection.test.js +0 -203
  367. package/tests/plugins/plugin.url.test.js +0 -129
  368. package/tests/plugins/plugin.vendor-fullscreen.test.js +0 -65
  369. package/tests/plugins/search/plugin.search.test.js +0 -173
  370. package/tests/plugins/search/plugin.search.view.test.js +0 -106
  371. package/tests/plugins/tts/AbstractTTSEngine.test.js +0 -153
  372. package/tests/plugins/tts/FestivalTTSEngine.test.js +0 -59
  373. package/tests/plugins/tts/PageChunk.test.js +0 -57
  374. package/tests/plugins/tts/PageChunkIterator.test.js +0 -179
  375. package/tests/plugins/tts/WebTTSEngine.test.js +0 -126
  376. package/tests/plugins/tts/utils.test.js +0 -133
  377. package/tests/util/browserSniffing.test.js +0 -56
  378. package/tests/util/docCookies.test.js +0 -15
  379. package/tests/util/strings.test.js +0 -63
  380. package/tests/utils.js +0 -42
  381. package/webpack.config.js +0 -86
@@ -1,20 +1,5 @@
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
- }
1
+ // @ts-check
2
+ import langs from 'iso-language-codes';
18
3
 
19
4
  /**
20
5
  * Use regex to approximate word count in a string
@@ -26,15 +11,6 @@ export function approximateWordCount(text) {
26
11
  return m ? m.length : 0;
27
12
  }
28
13
 
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
14
  /**
39
15
  * Checks whether the current browser is on android
40
16
  * @param {string} [userAgent]
@@ -44,48 +20,100 @@ export function isAndroid(userAgent = navigator.userAgent) {
44
20
  return /android/i.test(userAgent);
45
21
  }
46
22
 
23
+ /** @type {{[lang: string]: string}} */
24
+ // Handle odd one-off language pairs that might show up over time
25
+ const specialLangs = {
26
+ "zh-hans": "中文 (Zhōngwén)",
27
+ };
28
+
47
29
  /**
48
30
  * @typedef {string} ISO6391
49
31
  * Language code in ISO 639-1 format. e.g. en, fr, zh
50
32
  **/
51
33
 
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
34
  /**
62
35
  * @param {string} language in some format
63
36
  * @return {ISO6391?}
64
37
  */
65
38
  export function toISO6391(language) {
66
39
  if (!language) return null;
67
- language = language.toLowerCase();
40
+ language = language.toLocaleLowerCase();
41
+ if (specialLangs[language]) {
42
+ return language;
43
+ }
44
+ const codeObj = (
45
+ findLanguage(language, ['iso639_1']) ||
46
+ findLanguage(language, ['iso639_2T']) ||
47
+ findLanguage(language, ['iso639_2B', 'name', 'nativeName'])
48
+ );
49
+ if (codeObj) return codeObj.iso639_1;
50
+ return null;
51
+ }
68
52
 
69
- return searchForISO6391(language, ['ISO 639-1']) ||
70
- searchForISO6391(language, ['ISO 639-2/B']) ||
71
- searchForISO6391(language, ['ISO 639-2/T', 'Endonym', 'Name']);
53
+ /**
54
+ *
55
+ * @param {string} language
56
+ * @returns {string}
57
+ */
58
+ export function toNativeName(language) {
59
+ if (!language) return null;
60
+ language = language.toLocaleLowerCase();
61
+ if (specialLangs[language]) {
62
+ return specialLangs[language];
63
+ }
64
+ const codeObj = (
65
+ findLanguage(language, ['iso639_1']) ||
66
+ findLanguage(language, ['iso639_2T']) ||
67
+ findLanguage(language, ['iso639_2B', 'name', 'nativeName'])
68
+ );
69
+ if (codeObj?.nativeName) return codeObj.nativeName.split(", ")[0];
70
+ return null;
72
71
  }
73
72
 
73
+ /** @typedef {import('iso-language-codes').Code} Code */
74
+
74
75
  /**
75
- * Searches for the given long in the given columns.
76
76
  * @param {string} language
77
- * @param {Array<keyof COLUMN_TO_LANG_INDEX>} columnsToSearch
78
- * @return {ISO6391?}
77
+ * @param {Array<'iso639_1' | 'iso639_2T' | 'iso639_2B' | 'nativeName' | 'name'>} fields
78
+ * @returns {Code | null}
79
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']];
80
+ function findLanguage(language, fields) {
81
+ if (!language) return null;
82
+ language = language.toLowerCase();
83
+ for (const lang of langs) {
84
+ for (const codeType of fields) {
85
+ if (lang[codeType]?.toLowerCase().split(", ").includes(language)) {
86
+ return lang;
87
87
  }
88
88
  }
89
89
  }
90
90
  return null;
91
91
  }
92
+
93
+ /**
94
+ * Checks whether the current browser supports localStorage or
95
+ * if the current context has access to it.
96
+ * @return {boolean}
97
+ */
98
+ export function hasLocalStorage() {
99
+ try {
100
+ return !!window.localStorage;
101
+ } catch (e) {
102
+ // Will throw in sandboxed iframe
103
+ // DOMException: Window.localStorage getter: Forbidden in a sandboxed document without the 'allow-same-origin' flag.
104
+ return false;
105
+ }
106
+ }
107
+
108
+ export const DEBUG_READ_ALOUD = location.toString().indexOf('_debugReadAloud=true') != -1;
109
+
110
+ export async function checkIfFiresPause() {
111
+ // Pick some random text so that if it accidentally speaks, it's not too annoying
112
+ const u = new SpeechSynthesisUtterance("Loading");
113
+ let calledPause = false;
114
+ u.addEventListener('pause', () => calledPause = true);
115
+ speechSynthesis.speak(u);
116
+ await new Promise(res => setTimeout(res, 10));
117
+ speechSynthesis.pause();
118
+ return calledPause;
119
+ }
@@ -0,0 +1,211 @@
1
+ export class UrlPlugin {
2
+ constructor(options = {}) {
3
+ this.bookReaderOptions = options;
4
+
5
+ // the canonical order of elements is important in the path and query string
6
+ this.urlSchema = [
7
+ { name: 'page', position: 'path', default: 'n0' },
8
+ { name: 'mode', position: 'path', default: '2up' },
9
+ { name: 'search', position: 'path', deprecated_for: 'q' },
10
+ { name: 'q', position: 'query_param' },
11
+ { name: 'sort', position: 'query_param' },
12
+ { name: 'view', position: 'query_param' },
13
+ { name: 'admin', position: 'query_param' },
14
+ ];
15
+
16
+ this.urlState = {};
17
+ this.urlMode = this.bookReaderOptions.urlMode || 'hash';
18
+ this.urlHistoryBasePath = this.bookReaderOptions.urlHistoryBasePath || '/';
19
+ this.urlLocationPollId = null;
20
+ this.oldLocationHash = null;
21
+ this.oldUserHash = null;
22
+ }
23
+
24
+ /**
25
+ * Parse JSON object URL state to string format
26
+ * Arrange path names in an order that it is positioned on the urlSchema
27
+ * @param {Object} urlState
28
+ * @returns {string}
29
+ */
30
+ urlStateToUrlString(urlState) {
31
+ const searchParams = new URLSearchParams();
32
+ const pathParams = {};
33
+
34
+ Object.keys(urlState).forEach(key => {
35
+ let schema = this.urlSchema.find(schema => schema.name === key);
36
+ if (schema?.deprecated_for) {
37
+ schema = this.urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
38
+ }
39
+ if (schema?.position == 'path') {
40
+ pathParams[schema?.name] = urlState[key];
41
+ } else {
42
+ searchParams.append(schema?.name || key, urlState[key]);
43
+ }
44
+ });
45
+
46
+ const strPathParams = this.urlSchema
47
+ .filter(s => s.position == 'path')
48
+ .map(schema => pathParams[schema.name] ? `${schema.name}/${encodeURIComponent(pathParams[schema.name])}` : '')
49
+ .join('/');
50
+
51
+ // replace consecutive slashes with a single slash + remove trailing slashes
52
+ const strStrippedTrailingSlash = `${strPathParams.replace(/\/+/g, '/').replace(/\/+$/, '')}`;
53
+ const concatenatedPath = `${strStrippedTrailingSlash}?${searchParams.toString()}`;
54
+ return searchParams.toString() ? concatenatedPath : `${strStrippedTrailingSlash}`;
55
+ }
56
+
57
+ /**
58
+ * Parse string URL and add it in the current urlState
59
+ * Example:
60
+ * /page/n7/mode/2up => {page: 'n7', mode: '2up'}
61
+ * /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}
62
+ * @param {string} urlString
63
+ * @returns {object}
64
+ */
65
+ urlStringToUrlState(urlString) {
66
+ const urlState = {};
67
+
68
+ // Fetch searchParams from given {str}
69
+ // Note: whole URL path is needed for URL parsing
70
+ const urlPath = new URL(urlString, 'http://example.com');
71
+ const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());
72
+ const splitUrlMatches = urlPath.pathname.match(/[^\\/]+\/[^\\/]+/g);
73
+ const urlStrSplitSlashObj = splitUrlMatches ? Object.fromEntries(splitUrlMatches.map(x => x.split('/'))) : {};
74
+
75
+ const doesKeyExists = (_object, _key) => {
76
+ return Object.keys(_object).some(value => value == _key);
77
+ };
78
+
79
+ // Add path objects to urlState
80
+ this.urlSchema
81
+ .filter(schema => schema.position == 'path')
82
+ .forEach(schema => {
83
+ const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
84
+ const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
85
+
86
+ // Not in the URL
87
+ if (!hasPropertyKey && !hasDeprecatedKey) {
88
+ return;
89
+ }
90
+
91
+ const urlStateParam = hasDeprecatedKey ? schema.deprecated_for : schema.name;
92
+ urlState[urlStateParam] = decodeURIComponent(urlStrSplitSlashObj[schema.name]);
93
+ });
94
+
95
+ // Add searchParams to urlState
96
+ Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
97
+ urlState[key] = value;
98
+ });
99
+
100
+ return urlState;
101
+ }
102
+
103
+ /**
104
+ * Add or update key-value to the urlState
105
+ * @param {string} key
106
+ * @param {string} val
107
+ */
108
+ setUrlParam(key, value) {
109
+ this.urlState[key] = value;
110
+
111
+ this.pushToAddressBar();
112
+ }
113
+
114
+ /**
115
+ * Delete key-value to the urlState
116
+ * @param {string} key
117
+ */
118
+ removeUrlParam(key) {
119
+ delete this.urlState[key];
120
+
121
+ this.pushToAddressBar();
122
+ }
123
+
124
+ /**
125
+ * Get key-value from the urlState
126
+ * @param {string} key
127
+ * @return {string}
128
+ */
129
+ getUrlParam(key) {
130
+ return this.urlState[key];
131
+ }
132
+
133
+ /**
134
+ * Push URL params to addressbar
135
+ */
136
+ pushToAddressBar() {
137
+ const urlStrPath = this.urlStateToUrlString(this.urlState);
138
+ const concatenatedPath = urlStrPath !== '/' ? urlStrPath : '';
139
+ if (this.urlMode == 'history') {
140
+ if (!window.history || !window.history.replaceState) {
141
+ this.options.urlMode = 'hash';
142
+ } else {
143
+ const newUrlPath = `${this.urlHistoryBasePath}${concatenatedPath}`.trim().replace(/(\/+)/g, '/');
144
+ try {
145
+ window.history.replaceState({}, null, newUrlPath);
146
+ } catch (e) {
147
+ // DOMException on Chrome when in sandboxed iframe
148
+ this.urlMode = 'hash';
149
+ }
150
+ }
151
+ }
152
+
153
+ if (this.urlMode == 'hash') {
154
+ window.location.replace('#' + concatenatedPath);
155
+ }
156
+ this.oldLocationHash = urlStrPath;
157
+ }
158
+
159
+ /**
160
+ * Get the url and check if it has changed
161
+ * If it was changeed, update the urlState
162
+ */
163
+ listenForHashChanges() {
164
+ this.oldLocationHash = this.getHash();
165
+ if (this.urlLocationPollId) {
166
+ clearInterval(this.urlLocationPollId);
167
+ this.urlLocationPollId = null;
168
+ }
169
+
170
+ // check if the URL changes
171
+ const updateHash = () => {
172
+ const newFragment = this.getHash();
173
+ const hasFragmentChange = newFragment != this.oldLocationHash;
174
+
175
+ if (!hasFragmentChange) { return; }
176
+
177
+ this.urlState = this.urlStringToUrlState(newFragment);
178
+ };
179
+ this.urlLocationPollId = setInterval(updateHash, 500);
180
+ }
181
+
182
+ /**
183
+ * Will read either the hash or URL and return the bookreader fragment
184
+ */
185
+ pullFromAddressBar(location = window.location) {
186
+ const path = this.urlMode === 'history'
187
+ ? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)
188
+ : location.hash.substr(1);
189
+ this.urlState = this.urlStringToUrlState(path);
190
+ }
191
+
192
+ /**
193
+ * Get the hash out of the current URL. Also augments it with the text
194
+ * from the main part of the URL, since that is not readable by JS
195
+ * from the actual hash
196
+ * @returns
197
+ */
198
+ getHash() {
199
+ const text = this.retrieveTextFragment(window.location.search);
200
+ const textFragment = text ? `:~:text=${text[0]}` : '';
201
+ return `${window.location.hash.slice(1)}${textFragment}`;
202
+ }
203
+
204
+ /**
205
+ * @param {string} urlString
206
+ * @returns {string}
207
+ */
208
+ retrieveTextFragment(urlString) {
209
+ return urlString.match(/(?<=[&?]?text=)[^&]*/);
210
+ }
211
+ }
@@ -1,4 +1,8 @@
1
1
  /* global BookReader */
2
+
3
+ import { UrlPlugin } from "./UrlPlugin.js";
4
+ import { sleep } from "../../BookReader/utils.js";
5
+
2
6
  /**
3
7
  * Plugin for URL management in BookReader
4
8
  * Note read more about the url "fragment" here:
@@ -22,7 +26,7 @@ jQuery.extend(BookReader.defaultOptions, {
22
26
  urlHistoryBasePath: '/',
23
27
 
24
28
  /** Only these params will be reflected onto the URL */
25
- urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight'],
29
+ urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view', 'text'],
26
30
 
27
31
  /** If true, don't update the URL when `page == n0 (eg "/page/n0")` */
28
32
  urlTrackIndex0: false,
@@ -39,6 +43,10 @@ BookReader.prototype.setup = (function(super_) {
39
43
  this.locationPollId = null;
40
44
  this.oldLocationHash = null;
41
45
  this.oldUserHash = null;
46
+ // Should include the :~:text= prefix
47
+ this.textFragment = null;
48
+ // Tracks the original textFragment page num when first loaded
49
+ this.textFragmentPage = null;
42
50
  };
43
51
  })(BookReader.prototype.setup);
44
52
 
@@ -50,7 +58,7 @@ BookReader.prototype.init = (function(super_) {
50
58
  this.bind(BookReader.eventNames.PostInit, () => {
51
59
  const { updateWindowTitle, urlMode } = this.options;
52
60
  if (updateWindowTitle) {
53
- document.title = this.shortTitle(50);
61
+ document.title = this.shortTitle(this.bookTitle, 50);
54
62
  }
55
63
  if (urlMode === 'hash') {
56
64
  this.urlStartLocationPolling();
@@ -58,7 +66,7 @@ BookReader.prototype.init = (function(super_) {
58
66
  });
59
67
 
60
68
  this.bind(BookReader.eventNames.fragmentChange,
61
- this.urlUpdateFragment.bind(this)
69
+ this.urlUpdateFragment.bind(this),
62
70
  );
63
71
  }
64
72
  super_.call(this);
@@ -86,7 +94,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
86
94
  this.oldLocationHash = this.urlReadFragment();
87
95
 
88
96
  if (this.locationPollId) {
89
- clearInterval(this.locationPollID);
97
+ clearInterval(this.locationPollId);
90
98
  this.locationPollId = null;
91
99
  }
92
100
 
@@ -103,7 +111,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
103
111
  this.trigger(BookReader.eventNames.stop);
104
112
  if (this.animating) {
105
113
  // Queue change if animating
106
- if (this.autoStop) this.autoStop();
114
+ this.plugins.autoplay?.stop();
107
115
  this.animationFinishedCallback = updateParams;
108
116
  } else {
109
117
  // update immediately
@@ -121,7 +129,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
121
129
  */
122
130
  BookReader.prototype.urlUpdateFragment = function() {
123
131
  const allParams = this.paramsFromCurrent();
124
- const { urlMode, urlTrackIndex0, urlTrackedParams } = this.options;
132
+ const { urlTrackIndex0, urlTrackedParams } = this.options;
125
133
 
126
134
  if (!urlTrackIndex0
127
135
  && (typeof(allParams.index) !== 'undefined')
@@ -137,29 +145,69 @@ BookReader.prototype.urlUpdateFragment = function() {
137
145
  return validParams;
138
146
  }, {});
139
147
 
140
- const newFragment = this.fragmentFromParams(params, urlMode);
148
+ // eg 'page/3/mode/2up'; no query params (in hash mode, it might have /search/term)
149
+ // Does NOT have the :~:text fragment
150
+ const newFragment = this.fragmentFromParams(params, this.options.urlMode);
151
+ const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;
152
+ // eg 'page/3/mode/2up'; no query params
153
+ // WILL CONTAIN the :~:text fragment in hash mode (!)
141
154
  const currFragment = this.urlReadFragment();
155
+ // This should have both ?q=foo&text=bar (and any other params) as an encoded string
142
156
  const currQueryString = this.getLocationSearch();
143
- const newQueryString = this.queryStringFromParams(params, currQueryString, urlMode);
144
- if (currFragment === newFragment && currQueryString === newQueryString) {
157
+ // Eg ?q=foo&text=bar; only query params, no fragment
158
+ const newQueryString = this.queryStringFromParams(params, currQueryString, this.options.urlMode);
159
+
160
+ // NOTE: If ?text is in the URL, we will fire fragment change events on every render; which is
161
+ // not desireable, but currently don't have a way to handle re-writing ?text to the hash text
162
+ // fragment form, :~:text=foo.
163
+ const hasTextParam = this.urlPlugin.retrieveTextFragment(currQueryString);
164
+ if (currFragment === newFragment && currQueryString === newQueryString && !hasTextParam) {
145
165
  return;
146
166
  }
147
167
 
148
- if (urlMode === 'history') {
149
- if (window.history && window.history.replaceState) {
168
+ if (this.options.urlMode === 'history') {
169
+ if (!window.history || !window.history.replaceState) {
170
+ this.options.urlMode = 'hash';
171
+ } else {
150
172
  const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\/+$/, '');
151
- const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;
152
-
173
+ const textFragment = this.urlPlugin.retrieveTextFragment(newQueryString);
153
174
  const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;
154
- window.history.replaceState({}, null, newUrlPath);
155
- this.oldLocationHash = newFragment + newQueryString;
156
-
175
+ const extractedPage = this.urlPlugin.urlStringToUrlState(newFragmentWithSlash)?.page;
176
+ if (!this.textFragmentPage && textFragment) {
177
+ this.textFragmentPage = extractedPage ? extractedPage : null;
178
+ this.textFragment = `:~:text=${textFragment}`;
179
+ }
180
+ try {
181
+ window.history.replaceState({}, null, newUrlPath);
182
+ this.oldLocationHash = newFragment + newQueryString;
183
+ if (textFragment) {
184
+ this.oldLocationHash += `:~:text=${textFragment[0]}`;
185
+ }
186
+ } catch (e) {
187
+ // DOMException on Chrome when in sandboxed iframe
188
+ this.options.urlMode = 'hash';
189
+ }
157
190
  }
158
- } else {
191
+ }
192
+
193
+ if (this.options.urlMode === 'hash') {
159
194
  const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());
160
- window.location.replace('#' + newFragment + newQueryStringSearch);
161
- this.oldLocationHash = newFragment + newQueryStringSearch;
195
+ let textFragment = this.urlPlugin.retrieveTextFragment(this.readQueryString());
196
+ const extractedPage = this.urlPlugin.urlStringToUrlState(newFragmentWithSlash)?.page;
162
197
 
198
+ if (textFragment) {
199
+ textFragment = `:~:text=${textFragment[0]}`;
200
+ } else {
201
+ textFragment = '';
202
+ }
203
+ if (!this.textFragmentPage && textFragment) {
204
+ this.textFragmentPage = extractedPage ? extractedPage : null;
205
+ this.textFragment = textFragment;
206
+ } else if (this.textFragmentPage && extractedPage != this.textFragmentPage) {
207
+ textFragment = '';
208
+ }
209
+ window.location.replace('#' + newFragment + newQueryStringSearch + textFragment);
210
+ this.oldLocationHash = newFragment + newQueryStringSearch + textFragment;
163
211
  }
164
212
  };
165
213
 
@@ -185,7 +233,7 @@ BookReader.prototype.urlReadFragment = function() {
185
233
  if (urlMode === 'history') {
186
234
  return window.location.pathname.substr(urlHistoryBasePath.length);
187
235
  } else {
188
- return window.location.hash.substr(1);
236
+ return this.urlPlugin.getHash();
189
237
  }
190
238
  };
191
239
 
@@ -196,3 +244,40 @@ BookReader.prototype.urlReadFragment = function() {
196
244
  BookReader.prototype.urlReadHashFragment = function() {
197
245
  return window.location.hash.substr(1);
198
246
  };
247
+ export class BookreaderUrlPlugin extends BookReader {
248
+ init() {
249
+ if (this.options.enableUrlPlugin) {
250
+ this.urlPlugin = new UrlPlugin(this.options);
251
+ const location = this.getLocationSearch();
252
+ if (location.includes("text=")) {
253
+ this.on('textLayerVisible', async (_, {pageContainerEl}) => {
254
+ const visiblePageNum = pageContainerEl.getAttribute('data-page-num');
255
+
256
+ // Hack: More time mode 1up page "settle down" from user scrolling
257
+ await sleep(this.mode === 1 ? 900 : 100);
258
+
259
+ // No textFragment found or the textFragment stored doesn't match current visible page loaded
260
+ if (!this.textFragment || this.textFragmentPage !== visiblePageNum) return;
261
+ if (this.options.urlMode === 'history') {
262
+ window.location.replace(`#${this.textFragment}`);
263
+ } else {
264
+ // for urlMode hash, textFragment is stored in oldLocationHash already
265
+ window.location.replace(`#${this.oldLocationHash}`);
266
+ }
267
+ });
268
+ }
269
+ this.bind(BookReader.eventNames.PostInit, () => {
270
+ const { urlMode } = this.options;
271
+
272
+ if (urlMode === 'hash') {
273
+ this.urlPlugin.listenForHashChanges();
274
+ }
275
+ });
276
+ }
277
+
278
+ super.init();
279
+ }
280
+ }
281
+
282
+ window.BookReader = BookreaderUrlPlugin;
283
+ export default BookreaderUrlPlugin;