@internetarchive/bookreader 5.0.0-9-multiple-files → 5.0.0-90

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 (333) hide show
  1. package/.eslintrc.js +21 -19
  2. package/.github/workflows/node.js.yml +81 -7
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +505 -1442
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  57. package/BookReader/images/unviewable_page.png +0 -0
  58. package/BookReader/jquery-3.js +2 -0
  59. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  60. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  61. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js +1 -165
  63. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  64. package/BookReader/plugins/plugin.chapters.js +22 -301
  65. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  66. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  67. package/BookReader/plugins/plugin.iframe.js +1 -74
  68. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  69. package/BookReader/plugins/plugin.iiif.js +2 -0
  70. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  71. package/BookReader/plugins/plugin.resume.js +1 -368
  72. package/BookReader/plugins/plugin.resume.js.map +1 -1
  73. package/BookReader/plugins/plugin.search.js +2 -1420
  74. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.search.js.map +1 -1
  76. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  77. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  78. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  79. package/BookReader/plugins/plugin.tts.js +2 -9193
  80. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  81. package/BookReader/plugins/plugin.tts.js.map +1 -1
  82. package/BookReader/plugins/plugin.url.js +1 -269
  83. package/BookReader/plugins/plugin.url.js.map +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  85. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  86. package/BookReader/webcomponents-bundle.js +3 -0
  87. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  88. package/BookReader/webcomponents-bundle.js.map +1 -0
  89. package/BookReaderDemo/BookReaderDemo.css +18 -19
  90. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +144 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  95. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  96. package/BookReaderDemo/demo-fullscreen.html +2 -4
  97. package/BookReaderDemo/demo-iiif.html +99 -12
  98. package/BookReaderDemo/demo-internetarchive.html +214 -18
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +526 -525
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +595 -33
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +5 -2
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +70 -62
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +0 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +10 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/book-navigator.js +590 -0
  125. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  126. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  127. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  128. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
  129. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  130. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  131. package/src/BookNavigator/delete-modal-actions.js +1 -1
  132. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  133. package/src/BookNavigator/downloads/downloads.js +29 -25
  134. package/src/BookNavigator/search/search-provider.js +80 -28
  135. package/src/BookNavigator/search/search-results.js +29 -26
  136. package/src/BookNavigator/sharing.js +27 -0
  137. package/src/BookNavigator/viewable-files.js +95 -0
  138. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
  140. package/src/BookReader/BookModel.js +76 -41
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/ImageCache.js +48 -15
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +777 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +19 -13
  150. package/src/BookReader/Navbar/Navbar.js +70 -54
  151. package/src/BookReader/PageContainer.js +116 -22
  152. package/src/BookReader/ReduceSet.js +3 -3
  153. package/src/BookReader/Toolbar/Toolbar.js +14 -41
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +73 -15
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils/classes.js +1 -1
  160. package/src/BookReader/utils.js +128 -13
  161. package/src/BookReader.js +562 -1078
  162. package/src/BookReaderPlugin.js +44 -0
  163. package/src/assets/icons/close-circle-dark.svg +1 -0
  164. package/src/assets/icons/magnify-minus.svg +3 -7
  165. package/src/assets/icons/magnify-plus.svg +3 -7
  166. package/src/assets/icons/voice.svg +1 -0
  167. package/src/assets/images/unviewable_page.png +0 -0
  168. package/src/css/BookReader.scss +1 -17
  169. package/src/css/_BRBookmarks.scss +1 -1
  170. package/src/css/_BRComponent.scss +1 -1
  171. package/src/css/_BRicon.scss +8 -2
  172. package/src/css/_BRmain.scss +33 -27
  173. package/src/css/_BRnav.scss +12 -42
  174. package/src/css/_BRpages.scss +170 -42
  175. package/src/css/_BRsearch.scss +68 -230
  176. package/src/css/_BRtoolbar.scss +5 -5
  177. package/src/css/_TextSelection.scss +87 -27
  178. package/src/css/_colorbox.scss +2 -2
  179. package/src/css/_controls.scss +24 -7
  180. package/src/css/_icons.scss +7 -1
  181. package/src/ia-bookreader/ia-bookreader.js +224 -0
  182. package/src/plugins/plugin.archive_analytics.js +84 -78
  183. package/src/plugins/plugin.autoplay.js +99 -104
  184. package/src/plugins/plugin.chapters.js +237 -191
  185. package/src/plugins/plugin.iframe.js +1 -1
  186. package/src/plugins/plugin.iiif.js +141 -0
  187. package/src/plugins/plugin.resume.js +53 -50
  188. package/src/plugins/plugin.text_selection.js +503 -175
  189. package/src/plugins/plugin.vendor-fullscreen.js +7 -7
  190. package/src/plugins/search/plugin.search.js +183 -121
  191. package/src/plugins/search/utils.js +43 -0
  192. package/src/plugins/search/view.js +67 -202
  193. package/src/plugins/tts/AbstractTTSEngine.js +75 -45
  194. package/src/plugins/tts/FestivalTTSEngine.js +21 -31
  195. package/src/plugins/tts/PageChunk.js +16 -23
  196. package/src/plugins/tts/PageChunkIterator.js +11 -17
  197. package/src/plugins/tts/WebTTSEngine.js +88 -72
  198. package/src/plugins/tts/plugin.tts.js +310 -350
  199. package/src/plugins/tts/utils.js +16 -26
  200. package/src/plugins/url/UrlPlugin.js +191 -0
  201. package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
  202. package/src/util/browserSniffing.js +22 -0
  203. package/src/util/docCookies.js +21 -2
  204. package/src/util/strings.js +1 -0
  205. package/tests/e2e/README.md +37 -0
  206. package/tests/e2e/autoplay.test.js +9 -6
  207. package/tests/e2e/base.test.js +8 -16
  208. package/tests/e2e/helpers/base.js +55 -50
  209. package/tests/e2e/helpers/debug.js +1 -1
  210. package/tests/e2e/helpers/mockSearch.js +19 -22
  211. package/tests/e2e/helpers/params.js +17 -0
  212. package/tests/e2e/helpers/rightToLeft.js +8 -14
  213. package/tests/e2e/helpers/search.js +73 -0
  214. package/tests/e2e/models/Navigation.js +20 -37
  215. package/tests/e2e/rightToLeft.test.js +4 -5
  216. package/tests/e2e/viewmode.test.js +40 -33
  217. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  218. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  219. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  220. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  221. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  222. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  223. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  224. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  225. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
  226. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  227. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  228. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  229. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  230. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  231. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  232. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  233. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  234. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  235. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  236. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  237. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  238. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +42 -29
  239. package/tests/jest/BookReader/PageContainer.test.js +238 -0
  240. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  241. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
  242. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  243. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  244. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  245. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  246. package/tests/jest/BookReader/utils.test.js +250 -0
  247. package/tests/jest/BookReader.keyboard.test.js +190 -0
  248. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
  249. package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
  250. package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
  251. package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
  252. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  253. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
  254. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
  255. package/tests/jest/plugins/plugin.text_selection.test.js +316 -0
  256. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  257. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
  258. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +42 -9
  259. package/tests/jest/plugins/search/utils.js +25 -0
  260. package/tests/jest/plugins/search/utils.test.js +29 -0
  261. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +30 -10
  262. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  263. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  264. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  265. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  266. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  267. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  268. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +57 -18
  269. package/tests/jest/setup.js +3 -0
  270. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  271. package/tests/jest/util/docCookies.test.js +24 -0
  272. package/tests/{util → jest/util}/strings.test.js +1 -1
  273. package/tests/{utils.js → jest/utils.js} +38 -0
  274. package/webpack.config.js +16 -10
  275. package/.babelrc +0 -12
  276. package/.dependabot/config.yml +0 -6
  277. package/.testcaferc.json +0 -5
  278. package/BookReader/bookreader-component-bundle.js +0 -14330
  279. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  280. package/BookReader/bookreader-component-bundle.js.map +0 -1
  281. package/BookReader/icons/sort-ascending.svg +0 -1
  282. package/BookReader/icons/sort-descending.svg +0 -1
  283. package/BookReader/jquery-1.10.1.js +0 -108
  284. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  285. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  286. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  287. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  288. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  289. package/BookReaderDemo/BookReaderJSAutoplay.js +0 -56
  290. package/BookReaderDemo/IIIFBookReader.js +0 -207
  291. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  292. package/BookReaderDemo/demo-autoplay.html +0 -38
  293. package/BookReaderDemo/demo-iiif.js +0 -26
  294. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  295. package/karma.conf.js +0 -23
  296. package/src/BookNavigator/BookModel.js +0 -14
  297. package/src/BookNavigator/BookNavigator.js +0 -452
  298. package/src/BookNavigator/assets/book-loader.js +0 -27
  299. package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
  300. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  301. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  302. package/src/BookNavigator/search/a-search-result.js +0 -55
  303. package/src/BookNavigator/volumes/volumes-provider.js +0 -108
  304. package/src/BookNavigator/volumes/volumes.js +0 -162
  305. package/src/BookReader/DebugConsole.js +0 -54
  306. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  307. package/src/ItemNavigator/ItemNavigator.js +0 -372
  308. package/src/ItemNavigator/providers/sharing.js +0 -29
  309. package/src/assets/icons/sort-ascending.svg +0 -1
  310. package/src/assets/icons/sort-descending.svg +0 -1
  311. package/src/css/_MobileNav.scss +0 -194
  312. package/src/dragscrollable-br.js +0 -261
  313. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  314. package/src/plugins/plugin.mobile_nav.js +0 -287
  315. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  316. package/tests/BookReader/DebugConsole.test.js +0 -25
  317. package/tests/BookReader/Mode1Up.test.js +0 -164
  318. package/tests/BookReader/Mode2Up.test.js +0 -247
  319. package/tests/BookReader/PageContainer.test.js +0 -115
  320. package/tests/BookReader/utils.test.js +0 -109
  321. package/tests/e2e/helpers/desktopSearch.js +0 -72
  322. package/tests/e2e/helpers/mobileSearch.js +0 -85
  323. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  324. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  325. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  326. package/tests/karma/BookNavigator/volumes.test.js +0 -133
  327. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  328. package/tests/plugins/plugin.archive_analytics.test.js +0 -23
  329. package/tests/plugins/plugin.autoplay.test.js +0 -52
  330. package/tests/plugins/plugin.chapters.test.js +0 -130
  331. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  332. package/tests/plugins/plugin.text_selection.test.js +0 -203
  333. package/tests/util/docCookies.test.js +0 -15
@@ -1,19 +1,32 @@
1
1
  import sinon from 'sinon';
2
- import { getNavPageNumHtml } from '../../../src/BookReader/Navbar/Navbar.js';
3
- import BookReader from '../../../src/BookReader.js';
2
+ import { getNavPageNumHtml } from '@/src/BookReader/Navbar/Navbar.js';
3
+ import BookReader from '@/src/BookReader.js';
4
4
 
5
5
  describe('getNavPageNumHtml', () => {
6
6
  const f = getNavPageNumHtml;
7
- test('handle n-prefixed page numbers', () => {
8
- expect(f(3, 40, 'n3', '', 40)).toBe('Page (4 of 40)');
7
+
8
+ test('handle n-prefixed page numbers-min format', () => {
9
+ expect(f(3, 40, 'n3', '', 40)).toBe('(4 of 40)');
10
+ });
11
+
12
+ test('handle regular page numbers-min format', () => {
13
+ expect(f(3, 40, '14', '', 40)).toBe('14 of 40');
14
+ });
15
+
16
+ test('handle no max page-min format', () => {
17
+ expect(f(3, 40, '14', '', null)).toBe('14');
18
+ });
19
+
20
+ test('handle n-prefixed page numbers-max format', () => {
21
+ expect(f(3, 40, 'n3', '', 40, true)).toBe('Page — (4/40)');
9
22
  });
10
23
 
11
- test('handle regular page numbers', () => {
12
- expect(f(3, 40, '14', '', 40)).toBe('Page 14 of 40');
24
+ test('handle regular page numbers-max format', () => {
25
+ expect(f(3, 40, '14', '', 40, true)).toBe('Page 14 (4/40)');
13
26
  });
14
27
 
15
- test('handle no max page', () => {
16
- expect(f(3, 40, '14', '', null)).toBe('Page 14');
28
+ test('handle no max page-max format', () => {
29
+ expect(f(3, 40, '14', '', null, true)).toBe('Page 14 (4/40)');
17
30
  });
18
31
  });
19
32
 
@@ -40,7 +53,7 @@ beforeEach(() => {
40
53
  uri: '//archive.org/download/BookReader/img/page004.jpg' },
41
54
  { width: 800, height: 1200,
42
55
  uri: '//archive.org/download/BookReader/img/page005.jpg' },
43
- ]
56
+ ],
44
57
  ],
45
58
  });
46
59
  br.init();
@@ -63,14 +76,14 @@ describe('Navbar slider', () => {
63
76
 
64
77
  test('on slide change, actual page changes', () => {
65
78
  const $slider = navbar.$root.find('.BRpager');
66
- const jumpToIndexSpy = sinon.spy(br, 'jumpToIndex');
79
+ const jumpToIndexStub = sinon.stub(br, 'jumpToIndex');
67
80
  expect(br.currentIndex()).toBe(0);
68
81
 
69
82
  $slider.trigger('slidechange', { value: 3 });
70
83
 
71
84
  expect(navbar.$root.find('.BRcurrentpage').text().includes('3'));
72
- expect(jumpToIndexSpy.callCount).toBe(1);
73
- expect(jumpToIndexSpy.args[0][0]).toBe(3);
85
+ expect(jumpToIndexStub.callCount).toBe(1);
86
+ expect(jumpToIndexStub.args[0][0]).toBe(3);
74
87
  });
75
88
  });
76
89
 
@@ -89,17 +102,17 @@ describe('Navbar controls overrides', () => {
89
102
  visible: true,
90
103
  className: 'viewmode',
91
104
  excludedModes: [1],
92
- }
93
- }
105
+ },
106
+ },
94
107
  };
95
108
  createBRWithOverrides(overrides);
96
109
 
97
110
  const $viewMode = navbar.$root.find('.viewmode');
98
111
 
99
112
  expect($viewMode.find('.icon-thumb').length).toBe(1);
100
- $viewMode.click();
113
+ $viewMode.trigger("click");
101
114
  expect($viewMode.find('.icon-twopg').length).toBe(1);
102
- $viewMode.click();
115
+ $viewMode.trigger("click");
103
116
  expect($viewMode.find('.icon-thumb').length).toBe(1);
104
117
  });
105
118
 
@@ -107,9 +120,9 @@ describe('Navbar controls overrides', () => {
107
120
  const overrides = {
108
121
  controls: {
109
122
  onePage: {
110
- visible: false
111
- }
112
- }
123
+ visible: false,
124
+ },
125
+ },
113
126
  };
114
127
  createBRWithOverrides(overrides);
115
128
 
@@ -122,9 +135,9 @@ describe('Navbar controls overrides', () => {
122
135
  const overrides = {
123
136
  controls: {
124
137
  onePage: {
125
- className: 'foo'
126
- }
127
- }
138
+ className: 'foo',
139
+ },
140
+ },
128
141
  };
129
142
  createBRWithOverrides(overrides);
130
143
 
@@ -139,9 +152,9 @@ describe('Navbar controls overrides', () => {
139
152
  onePage: {
140
153
  template: () => (
141
154
  '<button id="foo"></button>'
142
- )
143
- }
144
- }
155
+ ),
156
+ },
157
+ },
145
158
  };
146
159
  createBRWithOverrides(overrides);
147
160
 
@@ -154,12 +167,12 @@ describe('Navbar controls overrides', () => {
154
167
  const overrides = {
155
168
  controls: {
156
169
  viewmode: {
157
- visible: true
170
+ visible: true,
158
171
  },
159
172
  onePage: {
160
- visible: false
161
- }
162
- }
173
+ visible: false,
174
+ },
175
+ },
163
176
  };
164
177
  createBRWithOverrides(overrides);
165
178
 
@@ -0,0 +1,238 @@
1
+ import {PageContainer, boxToSVGRect, createSVGPageLayer, renderBoxesInPageContainerLayer} from '@/src/BookReader/PageContainer.js';
2
+ import {ImageCache} from '@/src/BookReader/ImageCache.js';
3
+ import {BookModel} from '@/src/BookReader/BookModel.js';
4
+ import { afterEventLoop } from '../utils.js';
5
+ import sinon from 'sinon';
6
+ /** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
7
+
8
+ const SAMPLE_BOOK = new BookModel(
9
+ {
10
+ data: [
11
+ [
12
+ { width: 123, height: 123, uri: 'https://archive.org/image0.jpg', pageNum: '1' },
13
+ ],
14
+ [
15
+ { width: 123, height: 123, uri: 'https://archive.org/image1.jpg', pageNum: '2' },
16
+ { width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '3' },
17
+ ],
18
+ [
19
+ { width: 123, height: 123, uri: 'https://archive.org/image3.jpg', pageNum: '4' },
20
+ { width: 123, height: 123, uri: 'https://archive.org/image4.jpg', pageNum: '5' },
21
+ ],
22
+ [
23
+ { width: 123, height: 123, uri: 'https://archive.org/image5.jpg', pageNum: '6' },
24
+ ],
25
+ ],
26
+ },
27
+ );
28
+
29
+ const realGetPageURI = SAMPLE_BOOK.getPageURI;
30
+ SAMPLE_BOOK.getPageURI = function (index, reduce, rotate) {
31
+ // Need to add a reduce url parameter, since the src is used
32
+ // for caching
33
+ return realGetPageURI.call(SAMPLE_BOOK, index, reduce, rotate) + `?reduce=${reduce}`;
34
+ };
35
+
36
+ describe('constructor', () => {
37
+ test('protected books', () => {
38
+ const pc = new PageContainer(null, {isProtected: true});
39
+ expect(pc.$container.hasClass('protected')).toBe(true);
40
+ expect(pc.$container.find('.BRscreen').length).toBe(1);
41
+ });
42
+
43
+ test('non-protected books', () => {
44
+ const pc = new PageContainer(null, {isProtected: false});
45
+ expect(pc.$container.hasClass('protected')).toBe(false);
46
+ expect(pc.$container.find('.BRscreen').length).toBe(0);
47
+ });
48
+
49
+ test('empty page', () => {
50
+ const pc = new PageContainer(null, {isProtected: false});
51
+ expect(pc.$container.hasClass('BRemptypage')).toBe(true);
52
+ });
53
+
54
+ test('non-empty page', () => {
55
+ const pc = new PageContainer({index: 7}, {isProtected: false});
56
+ expect(pc.$container.hasClass('BRemptypage')).toBe(false);
57
+ expect(pc.$container.hasClass('pagediv7')).toBe(true);
58
+ });
59
+
60
+ test('adds side attribute', () => {
61
+ const pc = new PageContainer({index: 7, pageSide: 'R'}, {isProtected: false});
62
+ expect(pc.$container.hasClass('BRemptypage')).toBe(false);
63
+ expect(pc.$container.attr('data-side')).toBe('R');
64
+ });
65
+ });
66
+
67
+ describe('update', () => {
68
+ test('dimensions sets CSS', () => {
69
+ const imageCache = new ImageCache(SAMPLE_BOOK);
70
+ const pc = new PageContainer(null, {imageCache});
71
+ pc.update({ dimensions: { left: 20 } });
72
+ expect(pc.$container[0].style.left).toBe('20px');
73
+ });
74
+
75
+ test('does not create image if empty page', () => {
76
+ const imageCache = new ImageCache(SAMPLE_BOOK);
77
+ const pc = new PageContainer(null, {imageCache});
78
+ pc.update({ reduce: null });
79
+ expect(pc.$img).toBeNull();
80
+ pc.update({ reduce: 7 });
81
+ expect(pc.$img).toBeNull();
82
+ });
83
+
84
+ test('does not create image if no reduce', () => {
85
+ const imageCache = new ImageCache(SAMPLE_BOOK);
86
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
87
+ pc.update({ reduce: null });
88
+ expect(pc.$img).toBeNull();
89
+ });
90
+
91
+ test('loads image on initial load', () => {
92
+ const imageCache = new ImageCache(SAMPLE_BOOK);
93
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
94
+ pc.update({ reduce: 7 }); // This will load reduce=8 into memory
95
+ expect(pc.$container.hasClass('BRpageloading')).toBe(true);
96
+ expect(pc.$container.children('.BRpageimage').length).toBe(1);
97
+ pc.$img.trigger('load');
98
+ expect(pc.$container.hasClass('BRpageloading')).toBe(false);
99
+ expect(pc.$container.children('.BRpageimage').length).toBe(1);
100
+ });
101
+
102
+ test('does not set loading class if already loaded', () => {
103
+ const imageCache = new ImageCache(SAMPLE_BOOK);
104
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
105
+ pc.update({ reduce: 7 }); // This will load reduce=8 into memory
106
+ pc.$img.trigger('load');
107
+ pc.update({ reduce: 6 }); // This will still load reduce=8
108
+ expect(pc.$container.hasClass('BRpageloading')).toBe(false);
109
+ expect(pc.$container.children('.BRpageimage').length).toBe(1);
110
+ });
111
+
112
+ test('removes image between updates only if changed', async () => {
113
+ const clock = sinon.useFakeTimers();
114
+ const imageCache = new ImageCache(SAMPLE_BOOK);
115
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
116
+
117
+ // load reduce=8
118
+ pc.update({ reduce: 7 });
119
+ pc.$img.trigger('load');
120
+ const img1 = pc.$img[0];
121
+
122
+ // Should not create a new image; same final reduce
123
+ pc.update({ reduce: 6 });
124
+ expect(pc.$img[0]).toBe(img1);
125
+ expect(pc.$container.children('.BRpageimage').length).toBe(1);
126
+
127
+ // Should create a new image; different reduce
128
+ pc.update({ reduce: 3 });
129
+ expect(pc.$img[0]).not.toBe(img1);
130
+ expect(pc.$container.children('.BRpageimage').length).toBe(2);
131
+
132
+ pc.$img.trigger('load');
133
+ // After loading we remove the old image; but not immediately!
134
+ expect(pc.$container.children('.BRpageimage').length).toBe(2);
135
+ expect(pc.$container.hasClass('BRpageloading')).toBe(false);
136
+ // increment time clock 100ms
137
+ clock.tick(100);
138
+ // wait for promises to resolve
139
+ clock.restore();
140
+ await afterEventLoop();
141
+ // NOW we remove the old image
142
+ expect(pc.$container.children('.BRpageimage').length).toBe(1);
143
+ });
144
+
145
+ test('shows lower res image while loading if one available', () => {
146
+ const imageCache = new ImageCache(SAMPLE_BOOK);
147
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
148
+ pc.update({ reduce: 7 });
149
+ pc.$img.trigger('load');
150
+
151
+ pc.update({reduce: 2});
152
+ expect(pc.$container.hasClass('BRpageloading')).toBe(true);
153
+ expect(pc.$container.children('.BRpageimage').length).toBe(2);
154
+ expect(pc.$container.children('.BRpageimage')[0].src).toContain('reduce=4');
155
+ expect(pc.$img[0].src).toContain('reduce=2');
156
+ });
157
+ });
158
+
159
+ describe('createSVGPageLayer', () => {
160
+ test('Does what it says', () => {
161
+ const svg = createSVGPageLayer({ width: 100, height: 200}, 'myClass');
162
+ expect(svg.getAttribute('viewBox')).toBe('0 0 100 200');
163
+ expect(svg.getAttribute('class')).toContain('myClass');
164
+ });
165
+ });
166
+
167
+ describe('boxToSVGRect', () => {
168
+ test('Does what it says', () => {
169
+ const rect = boxToSVGRect({ l: 100, r: 200, t: 300, b: 500 });
170
+ expect(rect.getAttribute('x')).toBe('100');
171
+ expect(rect.getAttribute('y')).toBe('300');
172
+ expect(rect.getAttribute('width')).toBe('100');
173
+ expect(rect.getAttribute('height')).toBe('200');
174
+ });
175
+ });
176
+
177
+ describe('renderBoxesInPageContainerLayer', () => {
178
+ test('Handles missing layer', () => {
179
+ const container = document.createElement('div');
180
+ const page = { width: 100, height: 200 };
181
+ const boxes = [{l: 1, r: 2, t: 3, b: 4}];
182
+ renderBoxesInPageContainerLayer('foo', boxes, page, container);
183
+ expect(container.querySelector('.foo')).toBeTruthy();
184
+ expect(container.querySelectorAll('.foo rect').length).toBe(1);
185
+ });
186
+
187
+ test('Handles existing layer', () => {
188
+ const container = document.createElement('div');
189
+ const layer = document.createElement('svg');
190
+ layer.classList.add('foo');
191
+ container.append(layer);
192
+
193
+ const page = { width: 100, height: 200 };
194
+ const boxes = [{l: 1, r: 2, t: 3, b: 4}];
195
+ renderBoxesInPageContainerLayer('foo', boxes, page, container);
196
+ expect(container.querySelector('.foo')).toBe(layer);
197
+ expect(container.querySelectorAll('.foo rect').length).toBe(1);
198
+ });
199
+
200
+ test('Adds layer after image if it exists', () => {
201
+ const container = document.createElement('div');
202
+ const img = document.createElement('img');
203
+ img.classList.add('BRpageimage');
204
+ container.append(img);
205
+
206
+ const page = { width: 100, height: 200 };
207
+ const boxes = [{l: 1, r: 2, t: 3, b: 4}];
208
+ renderBoxesInPageContainerLayer('foo', boxes, page, container);
209
+ expect(container.querySelector('.foo')).toBeTruthy();
210
+ expect(container.children[0].getAttribute('class')).toBe('BRpageimage');
211
+ expect(container.children[1].getAttribute('class')).toBe('BRPageLayer foo');
212
+ });
213
+
214
+ test('Renders all boxes', () => {
215
+ const container = document.createElement('div');
216
+ const page = { width: 100, height: 200 };
217
+ const boxes = [{l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}];
218
+ renderBoxesInPageContainerLayer('foo', boxes, page, container);
219
+ expect(container.querySelectorAll('.foo rect').length).toBe(3);
220
+ });
221
+
222
+ test('Adds optional classes', () => {
223
+ const container = document.createElement('div');
224
+ const page = { width: 100, height: 200 };
225
+ const boxes = [{l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}];
226
+ renderBoxesInPageContainerLayer('foo', boxes, page, container, ['match-1', 'match-2', 'match-3']);
227
+ const rects = Array.from(container.querySelectorAll('.foo rect'));
228
+ expect(rects.map(r => r.getAttribute('class'))).toEqual(['match-1', 'match-2', 'match-3']);
229
+ });
230
+
231
+ test('Handles no boxes', () => {
232
+ const container = document.createElement('div');
233
+ const page = { width: 100, height: 200 };
234
+ const boxes = [];
235
+ renderBoxesInPageContainerLayer('foo', boxes, page, container);
236
+ expect(container.querySelectorAll('.foo rect').length).toBe(0);
237
+ });
238
+ });
@@ -1,4 +1,4 @@
1
- import {IntegerReduceSet, Pow2ReduceSet} from '../../src/BookReader/ReduceSet.js';
1
+ import {IntegerReduceSet, Pow2ReduceSet} from '@/src/BookReader/ReduceSet.js';
2
2
 
3
3
  describe('IntegerReduceSet', () => {
4
4
  test('floor', () => {
@@ -1,10 +1,10 @@
1
1
  import sinon from 'sinon';
2
2
 
3
- import { createPopup } from '../../../src/BookReader/Toolbar/Toolbar.js';
3
+ import { createPopup } from '@/src/BookReader/Toolbar/Toolbar.js';
4
4
 
5
5
  afterEach(() => {
6
6
  sinon.restore();
7
- })
7
+ });
8
8
 
9
9
  describe('createPopup', () => {
10
10
  test('calls window.open', () => {
@@ -20,7 +20,7 @@ describe('createPopup', () => {
20
20
  expect(openStub.args[0]).toEqual([
21
21
  'openlibrary.org',
22
22
  'Open Library',
23
- 'status=1,width=100,height=100,top=334,left=462'
23
+ 'status=1,width=100,height=100,top=334,left=462',
24
24
  ]);
25
25
  });
26
26
  });
@@ -0,0 +1,59 @@
1
+ // @ts-check
2
+ import sinon from 'sinon';
3
+ import { HTMLDimensionsCacher } from '@/src/BookReader/utils/HTMLDimensionsCacher';
4
+
5
+ describe('HTMLDimensionsCacher', () => {
6
+ test('Does not read from element directly', () => {
7
+ const element = document.createElement('div');
8
+ const getBoundingClientRectStub = element.getBoundingClientRect = sinon.stub().returns({ top: 10, left: 20 });
9
+ const clientWidthStub = sinon.stub().returns(300);
10
+ const clientHeightStub = sinon.stub().returns(500);
11
+ Object.defineProperty(element, 'clientWidth', { get: clientWidthStub });
12
+ Object.defineProperty(element, 'clientHeight', { get: clientHeightStub });
13
+
14
+ const hdc = new HTMLDimensionsCacher(element);
15
+ hdc.clientHeight;
16
+ expect(getBoundingClientRectStub.callCount).toBe(0);
17
+ expect(clientWidthStub.callCount).toBe(0);
18
+ expect(clientHeightStub.callCount).toBe(0);
19
+ });
20
+
21
+ test('Read from element when calling update', () => {
22
+ const element = document.createElement('div');
23
+ const getBoundingClientRectStub = element.getBoundingClientRect = sinon.stub().returns({ top: 10, left: 20 });
24
+ const clientWidthStub = sinon.stub().returns(300);
25
+ const clientHeightStub = sinon.stub().returns(500);
26
+ Object.defineProperty(element, 'clientWidth', { get: clientWidthStub });
27
+ Object.defineProperty(element, 'clientHeight', { get: clientHeightStub });
28
+
29
+ const hdc = new HTMLDimensionsCacher(element);
30
+ hdc.updateClientSizes();
31
+ expect(getBoundingClientRectStub.callCount).toBe(1);
32
+ expect(clientWidthStub.callCount).toBe(1);
33
+ expect(clientHeightStub.callCount).toBe(1);
34
+
35
+ expect(hdc.boundingClientRect).toEqual({ top: 10, left: 20 });
36
+ expect(hdc.clientWidth).toBe(300);
37
+ expect(hdc.clientHeight).toBe(500);
38
+ });
39
+
40
+ test('Does not listen for window resizes when not attached', () => {
41
+ const element = document.createElement('div');
42
+ const hdc = new HTMLDimensionsCacher(element);
43
+ const dummyWindow = new EventTarget();
44
+ const debouncedUpdateSpy = sinon.spy(hdc, 'debouncedUpdateClientSizes');
45
+
46
+ dummyWindow.dispatchEvent(new Event('resize', {}));
47
+ expect(debouncedUpdateSpy.callCount).toBe(0);
48
+
49
+ hdc.attachResizeListener(dummyWindow);
50
+
51
+ dummyWindow.dispatchEvent(new Event('resize', {}));
52
+ expect(debouncedUpdateSpy.callCount).toBe(1);
53
+
54
+ hdc.detachResizeListener(dummyWindow);
55
+
56
+ dummyWindow.dispatchEvent(new Event('resize', {}));
57
+ expect(debouncedUpdateSpy.callCount).toBe(1);
58
+ });
59
+ });
@@ -0,0 +1,49 @@
1
+ // @ts-check
2
+ import sinon from 'sinon';
3
+ import { ScrollClassAdder } from '@/src/BookReader/utils/ScrollClassAdder';
4
+
5
+ describe('ScrollClassAdder', () => {
6
+ test('Does not attach during construction', () => {
7
+ const element = document.createElement('div');
8
+ const attachSpy = sinon.spy(ScrollClassAdder.prototype, 'attach');
9
+ new ScrollClassAdder(element, 'foo');
10
+ expect(attachSpy.callCount).toBe(0);
11
+ });
12
+
13
+ test('Attach/detach call correct methods', () => {
14
+ const el = document.createElement('div');
15
+ const addEventListenerSpy = sinon.spy(el, 'addEventListener');
16
+ const removeEventListenerSpy = sinon.spy(el, 'removeEventListener');
17
+ const sca = new ScrollClassAdder(el, 'foo');
18
+ expect(addEventListenerSpy.callCount).toBe(0);
19
+ sca.attach();
20
+ expect(addEventListenerSpy.callCount).toBe(1);
21
+ sca.detach();
22
+ expect(removeEventListenerSpy.callCount).toBe(1);
23
+ });
24
+
25
+ test('onScroll adds class at right time', () => {
26
+ const clock = sinon.useFakeTimers();
27
+ const el = document.createElement('div');
28
+ const sca = new ScrollClassAdder(el, 'foo');
29
+ expect(el.getAttribute('class')).toBeFalsy();
30
+ sca.onScroll();
31
+ expect(el.getAttribute('class')).toBe('foo');
32
+ clock.tick(600);
33
+ expect(el.getAttribute('class')).toBeFalsy();
34
+
35
+ sca.onScroll();
36
+ expect(el.getAttribute('class')).toBe('foo');
37
+ clock.tick(500);
38
+ expect(el.getAttribute('class')).toBe('foo');
39
+ sca.onScroll();
40
+ expect(el.getAttribute('class')).toBe('foo');
41
+ clock.tick(100);
42
+ expect(el.getAttribute('class')).toBe('foo');
43
+ clock.tick(499);
44
+ expect(el.getAttribute('class')).toBe('foo');
45
+ clock.tick(1);
46
+ expect(el.getAttribute('class')).toBeFalsy();
47
+ clock.restore();
48
+ });
49
+ });
@@ -0,0 +1,57 @@
1
+ // @ts-check
2
+ import sinon from "sinon";
3
+ import { SelectionObserver } from "@/src/BookReader/utils/SelectionObserver";
4
+
5
+ afterEach(() => {
6
+ sinon.restore();
7
+ });
8
+
9
+ describe("SelectionObserver", () => {
10
+ test("_onSelectionChange", () => {
11
+ const handler = sinon.spy();
12
+ const observer = new SelectionObserver(".text-layer", handler);
13
+ const target = document.createElement("div");
14
+ target.classList.add("text-layer");
15
+
16
+ // stub window.getSelection
17
+ const getSelectionStub = sinon.stub(window, "getSelection");
18
+ getSelectionStub.returns({ toString: () => "test", anchorNode: target });
19
+ observer._onSelectionChange();
20
+ expect(handler.callCount).toBe(1);
21
+ expect(handler.calledWith("started", target)).toBe(true);
22
+ expect(observer.selecting).toBe(true);
23
+
24
+ // Calling it again does not call the handler again
25
+ observer._onSelectionChange();
26
+ expect(handler.callCount).toBe(1);
27
+
28
+ // Until the selection is cleared
29
+ getSelectionStub.returns({ toString: () => "", anchorNode: null });
30
+ expect(observer.selecting).toBe(true);
31
+ expect(handler.callCount).toBe(1);
32
+
33
+ observer._onSelectionChange();
34
+ expect(handler.callCount).toBe(2);
35
+ expect(handler.calledWith("cleared", target)).toBe(true);
36
+
37
+ // Calling it again does not call the handler again
38
+ sinon.restore();
39
+ sinon.stub(window, "getSelection").returns({ toString: () => "" });
40
+ observer._onSelectionChange();
41
+ expect(handler.callCount).toBe(2);
42
+ });
43
+
44
+ test('Only fires when selection started in selector', () => {
45
+ const handler = sinon.spy();
46
+ const observer = new SelectionObserver(".text-layer", handler);
47
+ const target = document.createElement("div");
48
+ target.classList.add("text-layer");
49
+
50
+ // stub window.getSelection
51
+ const getSelectionStub = sinon.stub(window, "getSelection");
52
+ getSelectionStub.returns({ toString: () => "test", anchorNode: document.body });
53
+ observer._onSelectionChange();
54
+ expect(handler.callCount).toBe(0);
55
+ expect(observer.selecting).toBe(false);
56
+ });
57
+ });
@@ -1,4 +1,4 @@
1
- import { exposeOverrideable } from '../../../src/BookReader/utils/classes.js';
1
+ import { exposeOverrideable } from '@/src/BookReader/utils/classes.js';
2
2
 
3
3
  describe('exposeOverrideable', () => {
4
4
  test('adds method to To class', () => {