@internetarchive/bookreader 5.0.0-93 → 5.0.0-95

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 (224) hide show
  1. package/.github/workflows/npm-publish.yml +2 -12
  2. package/BookReaderDemo/IADemoBr.js +1 -24
  3. package/BookReaderDemo/demo-internetarchive.html +1 -0
  4. package/CHANGELOG.md +19 -1
  5. package/README.md +0 -2
  6. package/package.json +8 -4
  7. package/scripts/postversion.js +3 -2
  8. package/scripts/preversion.js +3 -1
  9. package/scripts/version.js +4 -6
  10. package/src/BookNavigator/book-navigator.js +38 -12
  11. package/src/BookNavigator/downloads/downloads-provider.js +2 -2
  12. package/src/BookNavigator/search/search-provider.js +5 -5
  13. package/src/BookNavigator/search/search-results.js +1 -1
  14. package/src/BookNavigator/sharing.js +2 -2
  15. package/src/BookNavigator/viewable-files.js +2 -2
  16. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +3 -3
  17. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +2 -2
  18. package/src/BookReader.js +57 -31
  19. package/src/assets/images/hypothesis.ico +0 -0
  20. package/src/css/_TextSelection.scss +3 -1
  21. package/src/plugins/plugin.autoplay.js +3 -3
  22. package/src/plugins/plugin.chapters.js +2 -2
  23. package/src/plugins/plugin.experiments.js +294 -0
  24. package/src/plugins/plugin.iiif.js +1 -1
  25. package/src/plugins/plugin.text_selection.js +112 -1
  26. package/src/plugins/search/view.js +5 -5
  27. package/src/plugins/tts/plugin.tts.js +3 -3
  28. package/src/plugins/url/plugin.url.js +2 -2
  29. package/tests/e2e/autoplay.test.js +1 -1
  30. package/tests/e2e/base.test.js +4 -4
  31. package/tests/e2e/helpers/base.js +2 -2
  32. package/tests/e2e/models/BookReader.js +1 -1
  33. package/tests/e2e/rightToLeft.test.js +4 -4
  34. package/tests/e2e/viewmode.test.js +2 -2
  35. package/tests/jest/BookNavigator/book-navigator.test.js +0 -13
  36. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +1 -1
  37. package/tests/jest/BookNavigator/downloads/downloads.test.js +1 -1
  38. package/tests/jest/BookNavigator/search/search-provider.test.js +5 -5
  39. package/tests/jest/BookReader.test.js +10 -10
  40. package/tests/jest/plugins/plugin.autoplay.test.js +6 -6
  41. package/tests/jest/plugins/plugin.chapters.test.js +2 -2
  42. package/tests/jest/plugins/plugin.resume.test.js +13 -13
  43. package/tests/jest/plugins/plugin.text_selection.test.js +155 -24
  44. package/tests/jest/plugins/search/plugin.search.test.js +7 -7
  45. package/tests/jest/plugins/search/plugin.search.view.test.js +8 -8
  46. package/tests/jest/plugins/search/utils.js +1 -1
  47. package/tests/jest/plugins/tts/PageChunkIterator.test.js +2 -2
  48. package/tests/jest/plugins/url/UrlPlugin.test.js +1 -1
  49. package/webpack.config.js +8 -3
  50. package/BookReader/BookReader.css +0 -2250
  51. package/BookReader/BookReader.js +0 -3
  52. package/BookReader/BookReader.js.LICENSE.txt +0 -72
  53. package/BookReader/BookReader.js.map +0 -1
  54. package/BookReader/ia-bookreader-bundle.js +0 -1782
  55. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +0 -7
  56. package/BookReader/ia-bookreader-bundle.js.map +0 -1
  57. package/BookReader/icons/1up.svg +0 -1
  58. package/BookReader/icons/2up.svg +0 -1
  59. package/BookReader/icons/advance.svg +0 -3
  60. package/BookReader/icons/chevron-right.svg +0 -1
  61. package/BookReader/icons/close-circle-dark.svg +0 -1
  62. package/BookReader/icons/close-circle.svg +0 -1
  63. package/BookReader/icons/fullscreen.svg +0 -1
  64. package/BookReader/icons/fullscreen_exit.svg +0 -1
  65. package/BookReader/icons/hamburger.svg +0 -1
  66. package/BookReader/icons/left-arrow.svg +0 -1
  67. package/BookReader/icons/magnify-minus.svg +0 -1
  68. package/BookReader/icons/magnify-plus.svg +0 -1
  69. package/BookReader/icons/magnify.svg +0 -1
  70. package/BookReader/icons/pause.svg +0 -1
  71. package/BookReader/icons/play.svg +0 -1
  72. package/BookReader/icons/playback-speed.svg +0 -1
  73. package/BookReader/icons/read-aloud.svg +0 -1
  74. package/BookReader/icons/review.svg +0 -3
  75. package/BookReader/icons/thumbnails.svg +0 -1
  76. package/BookReader/icons/voice.svg +0 -1
  77. package/BookReader/icons/volume-full.svg +0 -1
  78. package/BookReader/images/BRicons.png +0 -0
  79. package/BookReader/images/BRicons.svg +0 -5
  80. package/BookReader/images/BRicons_ia.png +0 -0
  81. package/BookReader/images/back_pages.png +0 -0
  82. package/BookReader/images/book_bottom_icon.png +0 -0
  83. package/BookReader/images/book_down_icon.png +0 -0
  84. package/BookReader/images/book_left_icon.png +0 -0
  85. package/BookReader/images/book_leftmost_icon.png +0 -0
  86. package/BookReader/images/book_right_icon.png +0 -0
  87. package/BookReader/images/book_rightmost_icon.png +0 -0
  88. package/BookReader/images/book_top_icon.png +0 -0
  89. package/BookReader/images/book_up_icon.png +0 -0
  90. package/BookReader/images/books_graphic.svg +0 -1
  91. package/BookReader/images/booksplit.png +0 -0
  92. package/BookReader/images/control_pause_icon.png +0 -0
  93. package/BookReader/images/control_play_icon.png +0 -0
  94. package/BookReader/images/embed_icon.png +0 -0
  95. package/BookReader/images/icon-home-ia.png +0 -0
  96. package/BookReader/images/icon_OL-logo-xs.png +0 -0
  97. package/BookReader/images/icon_alert-xs.png +0 -0
  98. package/BookReader/images/icon_book.svg +0 -1
  99. package/BookReader/images/icon_bookmark.svg +0 -1
  100. package/BookReader/images/icon_close-pop.png +0 -0
  101. package/BookReader/images/icon_download.png +0 -0
  102. package/BookReader/images/icon_gear.svg +0 -1
  103. package/BookReader/images/icon_hamburger.svg +0 -1
  104. package/BookReader/images/icon_home.png +0 -0
  105. package/BookReader/images/icon_home.svg +0 -1
  106. package/BookReader/images/icon_home_ia.png +0 -0
  107. package/BookReader/images/icon_indicator.png +0 -0
  108. package/BookReader/images/icon_info.svg +0 -1
  109. package/BookReader/images/icon_one_page.svg +0 -1
  110. package/BookReader/images/icon_pause.svg +0 -1
  111. package/BookReader/images/icon_play.svg +0 -1
  112. package/BookReader/images/icon_playback-rate.svg +0 -1
  113. package/BookReader/images/icon_return.png +0 -0
  114. package/BookReader/images/icon_search_button.svg +0 -1
  115. package/BookReader/images/icon_share.svg +0 -1
  116. package/BookReader/images/icon_skip-ahead.svg +0 -1
  117. package/BookReader/images/icon_skip-back.svg +0 -2
  118. package/BookReader/images/icon_speaker.svg +0 -1
  119. package/BookReader/images/icon_speaker_open.svg +0 -1
  120. package/BookReader/images/icon_thumbnails.svg +0 -1
  121. package/BookReader/images/icon_toc.svg +0 -1
  122. package/BookReader/images/icon_two_pages.svg +0 -1
  123. package/BookReader/images/icon_zoomer.png +0 -0
  124. package/BookReader/images/loading.gif +0 -0
  125. package/BookReader/images/logo_icon.png +0 -0
  126. package/BookReader/images/marker_chap-off.png +0 -0
  127. package/BookReader/images/marker_chap-off.svg +0 -1
  128. package/BookReader/images/marker_chap-off_ia.png +0 -0
  129. package/BookReader/images/marker_chap-on.png +0 -0
  130. package/BookReader/images/marker_chap-on.svg +0 -1
  131. package/BookReader/images/marker_srch-on.svg +0 -1
  132. package/BookReader/images/marker_srchchap-off.png +0 -0
  133. package/BookReader/images/marker_srchchap-on.png +0 -0
  134. package/BookReader/images/nav_control-dn.png +0 -0
  135. package/BookReader/images/nav_control-dn_ia.png +0 -0
  136. package/BookReader/images/nav_control-up.png +0 -0
  137. package/BookReader/images/nav_control-up_ia.png +0 -0
  138. package/BookReader/images/nav_control.png +0 -0
  139. package/BookReader/images/one_page_mode_icon.png +0 -0
  140. package/BookReader/images/paper-badge.png +0 -0
  141. package/BookReader/images/print_icon.png +0 -0
  142. package/BookReader/images/progressbar.gif +0 -0
  143. package/BookReader/images/right_edges.png +0 -0
  144. package/BookReader/images/slider.png +0 -0
  145. package/BookReader/images/slider_ia.png +0 -0
  146. package/BookReader/images/thumbnail_mode_icon.png +0 -0
  147. package/BookReader/images/transparent.png +0 -0
  148. package/BookReader/images/two_page_mode_icon.png +0 -0
  149. package/BookReader/images/unviewable_page.png +0 -0
  150. package/BookReader/images/zoom_in_icon.png +0 -0
  151. package/BookReader/images/zoom_out_icon.png +0 -0
  152. package/BookReader/jquery-3.js +0 -2
  153. package/BookReader/jquery-3.js.LICENSE.txt +0 -24
  154. package/BookReader/plugins/plugin.archive_analytics.js +0 -2
  155. package/BookReader/plugins/plugin.archive_analytics.js.map +0 -1
  156. package/BookReader/plugins/plugin.autoplay.js +0 -2
  157. package/BookReader/plugins/plugin.autoplay.js.map +0 -1
  158. package/BookReader/plugins/plugin.chapters.js +0 -26
  159. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +0 -1
  160. package/BookReader/plugins/plugin.chapters.js.map +0 -1
  161. package/BookReader/plugins/plugin.iframe.js +0 -2
  162. package/BookReader/plugins/plugin.iframe.js.map +0 -1
  163. package/BookReader/plugins/plugin.iiif.js +0 -2
  164. package/BookReader/plugins/plugin.iiif.js.map +0 -1
  165. package/BookReader/plugins/plugin.resume.js +0 -2
  166. package/BookReader/plugins/plugin.resume.js.map +0 -1
  167. package/BookReader/plugins/plugin.search.js +0 -3
  168. package/BookReader/plugins/plugin.search.js.LICENSE.txt +0 -1
  169. package/BookReader/plugins/plugin.search.js.map +0 -1
  170. package/BookReader/plugins/plugin.text_selection.js +0 -3
  171. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +0 -1
  172. package/BookReader/plugins/plugin.text_selection.js.map +0 -1
  173. package/BookReader/plugins/plugin.tts.js +0 -3
  174. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +0 -29
  175. package/BookReader/plugins/plugin.tts.js.map +0 -1
  176. package/BookReader/plugins/plugin.url.js +0 -2
  177. package/BookReader/plugins/plugin.url.js.map +0 -1
  178. package/BookReader/plugins/plugin.vendor-fullscreen.js +0 -2
  179. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +0 -1
  180. package/BookReader/webcomponents-bundle.js +0 -3
  181. package/BookReader/webcomponents-bundle.js.LICENSE.txt +0 -9
  182. package/BookReader/webcomponents-bundle.js.map +0 -1
  183. package/src/BookReader/BookModel.js +0 -554
  184. package/src/BookReader/DragScrollable.js +0 -233
  185. package/src/BookReader/ImageCache.js +0 -149
  186. package/src/BookReader/Mode1Up.js +0 -108
  187. package/src/BookReader/Mode1UpLit.js +0 -388
  188. package/src/BookReader/Mode2Up.js +0 -105
  189. package/src/BookReader/Mode2UpLit.js +0 -777
  190. package/src/BookReader/ModeCoordinateSpace.js +0 -29
  191. package/src/BookReader/ModeSmoothZoom.js +0 -312
  192. package/src/BookReader/ModeThumb.js +0 -342
  193. package/src/BookReader/Navbar/Navbar.js +0 -355
  194. package/src/BookReader/PageContainer.js +0 -169
  195. package/src/BookReader/ReduceSet.js +0 -26
  196. package/src/BookReader/Toolbar/Toolbar.js +0 -362
  197. package/src/BookReader/events.js +0 -19
  198. package/src/BookReader/options.js +0 -382
  199. package/src/BookReader/utils/HTMLDimensionsCacher.js +0 -44
  200. package/src/BookReader/utils/ScrollClassAdder.js +0 -31
  201. package/src/BookReader/utils/SelectionObserver.js +0 -45
  202. package/src/BookReader/utils/classes.js +0 -36
  203. package/src/BookReader/utils.js +0 -300
  204. package/tests/jest/BookReader/BookModel.test.js +0 -372
  205. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +0 -263
  206. package/tests/jest/BookReader/ImageCache.test.js +0 -150
  207. package/tests/jest/BookReader/Mode1UpLit.test.js +0 -73
  208. package/tests/jest/BookReader/Mode2Up.test.js +0 -98
  209. package/tests/jest/BookReader/Mode2UpLit.test.js +0 -190
  210. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +0 -16
  211. package/tests/jest/BookReader/ModeSmoothZoom.test.js +0 -218
  212. package/tests/jest/BookReader/ModeThumb.test.js +0 -71
  213. package/tests/jest/BookReader/Navbar/Navbar.test.js +0 -182
  214. package/tests/jest/BookReader/PageContainer.test.js +0 -238
  215. package/tests/jest/BookReader/ReduceSet.test.js +0 -38
  216. package/tests/jest/BookReader/Toolbar/Toolbar.test.js +0 -26
  217. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +0 -59
  218. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +0 -49
  219. package/tests/jest/BookReader/utils/SelectionObserver.test.js +0 -57
  220. package/tests/jest/BookReader/utils/classes.test.js +0 -88
  221. package/tests/jest/BookReader/utils.test.js +0 -250
  222. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
  223. /package/{.testcaferc.js → .testcaferc.cjs} +0 -0
  224. /package/{babel.config.js → babel.config.cjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { fixtureCleanup, fixtureSync } from '@open-wc/testing-helpers';
2
2
  import sinon from 'sinon';
3
- import searchProvider from '@/src/BookNavigator/search/search-provider';
3
+ import searchProvider from '@/src/BookNavigator/search/search-provider.js';
4
4
 
5
5
  afterEach(() => {
6
6
  sinon.restore();
@@ -88,7 +88,7 @@ describe('Search Provider', () => {
88
88
  onProviderChange: sinon.fake(),
89
89
  bookreader: {
90
90
  leafNumToIndex: sinon.fake(),
91
- _plugins: {
91
+ plugins: {
92
92
  search: {
93
93
  jumpToMatch: sinon.fake(),
94
94
  },
@@ -104,7 +104,7 @@ describe('Search Provider', () => {
104
104
  { detail: searchResultStub }),
105
105
  );
106
106
 
107
- expect(provider.bookreader._plugins.search.jumpToMatch.callCount).toEqual(1);
107
+ expect(provider.bookreader.plugins.search.jumpToMatch.callCount).toEqual(1);
108
108
  });
109
109
  test('update url when search is cancelled or input cleared', async() => {
110
110
  const urlPluginMock = {
@@ -115,7 +115,7 @@ describe('Search Provider', () => {
115
115
  onProviderChange: sinon.fake(),
116
116
  bookreader: {
117
117
  leafNumToIndex: sinon.fake(),
118
- _plugins: {
118
+ plugins: {
119
119
  search: {
120
120
  jumpToMatch: sinon.fake(),
121
121
  },
@@ -153,7 +153,7 @@ describe('Search Provider', () => {
153
153
  onProviderChange: sinon.fake(),
154
154
  bookreader: {
155
155
  leafNumToIndex: sinon.fake(),
156
- _plugins: {
156
+ plugins: {
157
157
  search: {
158
158
  jumpToMatch: sinon.fake(),
159
159
  },
@@ -39,35 +39,35 @@ test('has registered fullscreen toggle event', () => {
39
39
  });
40
40
 
41
41
  test('checks cookie when initParams called', () => {
42
- br._plugins.resume.getResumeValue = jest.fn(() => 15);
42
+ br.plugins.resume.getResumeValue = jest.fn(() => 15);
43
43
  br.urlReadFragment = jest.fn(() => '');
44
44
 
45
45
  const params = br.initParams();
46
- expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
46
+ expect(br.plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
47
47
  expect(params.init).toBe(true);
48
48
  expect(params.index).toBe(15);
49
49
  expect(params.fragmentChange).toBe(true);
50
50
  });
51
51
 
52
52
  test('does not check cookie when initParams called', () => {
53
- br._plugins.resume.getResumeValue = jest.fn(() => null);
53
+ br.plugins.resume.getResumeValue = jest.fn(() => null);
54
54
  br.urlReadFragment = jest.fn(() => '');
55
55
  br.options.plugins.resume.enabled = false;
56
56
 
57
57
  const params = br.initParams();
58
- expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(0);
58
+ expect(br.plugins.resume.getResumeValue).toHaveBeenCalledTimes(0);
59
59
  expect(params.init).toBe(true);
60
60
  expect(params.index).toBe(0);
61
61
  expect(params.fragmentChange).toBe(false);
62
62
  });
63
63
 
64
64
  test('gets index from fragment when both fragment and cookie when InitParams called', () => {
65
- br._plugins.resume.getResumeValue = jest.fn(() => 15);
65
+ br.plugins.resume.getResumeValue = jest.fn(() => 15);
66
66
  br.urlReadFragment = jest.fn(() => 'page/n4');
67
67
  br.options.plugins.resume.enabled = true;
68
68
 
69
69
  const params = br.initParams();
70
- expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
70
+ expect(br.plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
71
71
  expect(params.init).toBe(true);
72
72
  expect(params.index).toBe(4);
73
73
  expect(params.fragmentChange).toBe(true);
@@ -117,7 +117,7 @@ test('has added BR property: bookPath', () => {
117
117
  });
118
118
 
119
119
  test('has suppressFragmentChange true when init with no input', () => {
120
- br._plugins.resume.getResumeValue = jest.fn(() => null);
120
+ br.plugins.resume.getResumeValue = jest.fn(() => null);
121
121
  br.urlReadFragment = jest.fn(() => '');
122
122
  br.urlReadHashFragment = jest.fn(() => '');
123
123
  br.switchMode = jest.fn();
@@ -128,7 +128,7 @@ test('has suppressFragmentChange true when init with no input', () => {
128
128
  });
129
129
 
130
130
  test('has suppressFragmentChange false when init with cookie', () => {
131
- br._plugins.resume.getResumeValue = jest.fn(() => 5);
131
+ br.plugins.resume.getResumeValue = jest.fn(() => 5);
132
132
  br.urlReadFragment = jest.fn(() => '');
133
133
  br.switchMode = jest.fn();
134
134
 
@@ -138,7 +138,7 @@ test('has suppressFragmentChange false when init with cookie', () => {
138
138
  });
139
139
 
140
140
  test('has suppressFragmentChange false when init with fragment', () => {
141
- br._plugins.resume.getResumeValue = jest.fn(() => null);
141
+ br.plugins.resume.getResumeValue = jest.fn(() => null);
142
142
  br.urlReadFragment = jest.fn(() => 'mode/1up');
143
143
  br.switchMode = jest.fn();
144
144
 
@@ -148,7 +148,7 @@ test('has suppressFragmentChange false when init with fragment', () => {
148
148
  });
149
149
 
150
150
  test('has suppressFragmentChange false when init with hash fragment', () => {
151
- br._plugins.resume.getResumeValue = jest.fn(() => null);
151
+ br.plugins.resume.getResumeValue = jest.fn(() => null);
152
152
  br.urlReadFragment = jest.fn(() => '');
153
153
  br.urlReadHashFragment = jest.fn(() => 'mode/1up');
154
154
  br.switchMode = jest.fn();
@@ -15,21 +15,21 @@ afterEach(() => {
15
15
 
16
16
  describe('Plugin: Menu Toggle', () => {
17
17
  test('autoplay does not start when BookReaderInitializes', () => {
18
- br._plugins.autoplay.toggle = jest.fn();
18
+ br.plugins.autoplay.toggle = jest.fn();
19
19
  br.init();
20
- expect(br._plugins.autoplay.toggle).toHaveBeenCalledTimes(0);
20
+ expect(br.plugins.autoplay.toggle).toHaveBeenCalledTimes(0);
21
21
  });
22
22
  test('autoplay will run without `flipSpeed` parameters', () => {
23
- const initialTimer = br._plugins.autoplay.timer;
23
+ const initialTimer = br.plugins.autoplay.timer;
24
24
  br.next = jest.fn();
25
- br._plugins.autoplay.stop = jest.fn();
25
+ br.plugins.autoplay.stop = jest.fn();
26
26
  br.init();
27
- br._plugins.autoplay.toggle();
27
+ br.plugins.autoplay.toggle();
28
28
  // internally referenced functions that fire
29
29
  expect(br.next).toHaveBeenCalledTimes(1);
30
30
 
31
31
  expect(initialTimer).toBeFalsy();
32
32
  // timer changes when autoplay turns on
33
- expect(br._plugins.autoplay.timer).toBeTruthy();
33
+ expect(br.plugins.autoplay.timer).toBeTruthy();
34
34
  });
35
35
  });
@@ -2,8 +2,8 @@ import sinon from "sinon";
2
2
 
3
3
  import "@/src/BookReader.js";
4
4
  import {ChaptersPlugin} from "@/src/plugins/plugin.chapters.js";
5
- import { BookModel } from "@/src/BookReader/BookModel";
6
- import { deepCopy } from "../utils";
5
+ import { BookModel } from "@/src/BookReader/BookModel.js";
6
+ import { deepCopy } from "../utils.js";
7
7
  /** @typedef {import('@/src/plugins/plugin.chapters').TocEntry} TocEntry */
8
8
 
9
9
  /** @type {TocEntry[]} */
@@ -29,9 +29,9 @@ describe('updateResumeValue', () => {
29
29
  In this branch .toHaveBeenCalledTimes() === 1
30
30
  */
31
31
  test.skip('starts when BookReaderInit is called', () => {
32
- br._plugins.resume.updateResumeValue = jest.fn();
32
+ br.plugins.resume.updateResumeValue = jest.fn();
33
33
  br.init();
34
- expect(br._plugins.resume.updateResumeValue).toHaveBeenCalledTimes(2);
34
+ expect(br.plugins.resume.updateResumeValue).toHaveBeenCalledTimes(2);
35
35
  });
36
36
 
37
37
  test('handles cookieName=null', () => {
@@ -48,38 +48,38 @@ describe('updateResumeValue', () => {
48
48
  test('handles cookiePath not set', () => {
49
49
  const setItemSpy = sinon.spy(docCookies, 'setItem');
50
50
  // Save function
51
- const saveFn = br._plugins.resume.getCookiePath;
52
- br._plugins.resume.getCookiePath = jest.fn(() => '/details/foo');
53
- br._plugins.resume.updateResumeValue(16);
51
+ const saveFn = br.plugins.resume.getCookiePath;
52
+ br.plugins.resume.getCookiePath = jest.fn(() => '/details/foo');
53
+ br.plugins.resume.updateResumeValue(16);
54
54
  expect(setItemSpy.args[0][3]).toEqual('/details/foo');
55
55
  // Restore function
56
- br._plugins.resume.getCookiePath = saveFn;
56
+ br.plugins.resume.getCookiePath = saveFn;
57
57
  });
58
58
 
59
59
  test('handles cookie path from URL with decoration', () => {
60
60
  const complexPathWithPage = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy/page/n1/mode/2up';
61
61
  const complexPath = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy';
62
- expect(br._plugins.resume.getCookiePath(complexPathWithPage))
62
+ expect(br.plugins.resume.getCookiePath(complexPathWithPage))
63
63
  .toEqual(complexPath);
64
64
 
65
- expect(br._plugins.resume.getCookiePath('/details/item/mode/1up'))
65
+ expect(br.plugins.resume.getCookiePath('/details/item/mode/1up'))
66
66
  .toEqual('/details/item');
67
67
 
68
- expect(br._plugins.resume.getCookiePath('/details/item/inside/a/long/path/model/is/used'))
68
+ expect(br.plugins.resume.getCookiePath('/details/item/inside/a/long/path/model/is/used'))
69
69
  .toEqual('/details/item/inside/a/long/path/model/is/used');
70
70
 
71
- expect(br._plugins.resume.getCookiePath('/details/item/inside/a/long/path/mode/is/used'))
71
+ expect(br.plugins.resume.getCookiePath('/details/item/inside/a/long/path/mode/is/used'))
72
72
  .toEqual('/details/item/inside/a/long/path');
73
73
  });
74
74
 
75
75
  test('handles cookie path from URL with no decoration', () => {
76
- expect(br._plugins.resume.getCookiePath('/details/item'))
76
+ expect(br.plugins.resume.getCookiePath('/details/item'))
77
77
  .toEqual('/details/item');
78
78
 
79
- expect(br._plugins.resume.getCookiePath('/details/item/'))
79
+ expect(br.plugins.resume.getCookiePath('/details/item/'))
80
80
  .toEqual('/details/item/');
81
81
 
82
- expect(br._plugins.resume.getCookiePath('/details/item/almost/any/kind/of/long/path'))
82
+ expect(br.plugins.resume.getCookiePath('/details/item/almost/any/kind/of/long/path'))
83
83
  .toEqual('/details/item/almost/any/kind/of/long/path');
84
84
  });
85
85
  });
@@ -3,14 +3,14 @@ import sinon from 'sinon';
3
3
  import BookReader from '@/src/BookReader.js';
4
4
  import {
5
5
  Cache,
6
+ genAt,
7
+ genFilter,
6
8
  genMap,
7
9
  lookAroundWindow,
10
+ walkBetweenNodes,
8
11
  zip,
9
12
  } from '@/src/plugins/plugin.text_selection.js';
10
13
 
11
-
12
- /** @type {BookReader} */
13
-
14
14
  // djvu.xml book infos copied from https://ia803103.us.archive.org/14/items/goodytwoshoes00newyiala/goodytwoshoes00newyiala_djvu.xml
15
15
  const FAKE_XML_1WORD = `
16
16
  <OBJECT data="file://localhost//tmp/derive/goodytwoshoes00newyiala//goodytwoshoes00newyiala.djvu" height="3192" type="image/x.djvu" usemap="goodytwoshoes00newyiala_0001.djvu" width="2454">
@@ -113,9 +113,56 @@ describe("Generic tests", () => {
113
113
  $('.BRtextLayer').remove();
114
114
  });
115
115
 
116
+ test("_limitSelection handles short selection", async () => {
117
+ const $container = br.refs.$brContainer;
118
+ br.options.plugins.textSelection.maxProtectedWords = 5;
119
+ sinon.stub(br.plugins.textSelection, "getPageText")
120
+ .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
121
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
122
+
123
+ const rangeBefore = document.createRange();
124
+ rangeBefore.setStart($container.find(".BRwordElement")[0].firstChild, 0);
125
+ rangeBefore.setEnd($container.find(".BRwordElement")[4].firstChild, 1);
126
+ const selection = window.getSelection();
127
+ selection.removeAllRanges();
128
+ selection.addRange(rangeBefore);
129
+
130
+ br.plugins.textSelection._limitSelection();
131
+
132
+ const rangeAfter = window.getSelection().getRangeAt(0);
133
+ expect(rangeAfter.startContainer).toBe(rangeBefore.startContainer);
134
+ expect(rangeAfter.startOffset).toBe(0);
135
+ expect(rangeAfter.endContainer).toBe(rangeBefore.endContainer);
136
+ expect(rangeAfter.endOffset).toBe(1);
137
+
138
+ window.getSelection().removeAllRanges();
139
+ });
140
+
141
+ test("_limitSelection shrinks selection", async () => {
142
+ const $container = br.refs.$brContainer;
143
+ br.options.plugins.textSelection.maxProtectedWords = 5;
144
+ sinon.stub(br.plugins.textSelection, "getPageText")
145
+ .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
146
+
147
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
148
+
149
+ const rangeBefore = document.createRange();
150
+ rangeBefore.setStart($container.find(".BRwordElement")[0].firstChild, 0);
151
+ rangeBefore.setEnd($container.find(".BRwordElement")[12].firstChild, 1);
152
+ const selection = window.getSelection();
153
+ selection.removeAllRanges();
154
+ selection.addRange(rangeBefore);
155
+
156
+ br.plugins.textSelection._limitSelection();
157
+
158
+ const rangeAfter = window.getSelection().getRangeAt(0);
159
+ expect(rangeAfter.startContainer).toBe(rangeBefore.startContainer);
160
+ expect(rangeAfter.endContainer).toBe($container.find(".BRwordElement")[4].firstChild);
161
+ });
162
+
116
163
  test("_createPageContainer overridden function still creates a BRpagecontainer element", () => {
117
- const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
118
- sinon.stub(br._plugins.textSelection, "getPageText")
164
+ const spy = sinon.spy(br.plugins.textSelection, 'createTextLayer');
165
+ sinon.stub(br.plugins.textSelection, "getPageText")
119
166
  .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
120
167
  const container = br._createPageContainer(1, {});
121
168
  expect(container).toBeTruthy();
@@ -124,24 +171,24 @@ describe("Generic tests", () => {
124
171
 
125
172
  // test loading first object from sample data
126
173
  test("_createPageContainer handles index 0", () => {
127
- const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
174
+ const spy = sinon.spy(br.plugins.textSelection, 'createTextLayer');
128
175
  br._createPageContainer(0, {});
129
176
  expect(spy.callCount).toBe(1);
130
177
  });
131
178
 
132
179
  // test loading last object from sample data
133
180
  test("_createPageContainer handles index -1", () => {
134
- const spy = sinon.spy(br._plugins.textSelection, 'createTextLayer');
181
+ const spy = sinon.spy(br.plugins.textSelection, 'createTextLayer');
135
182
  br._createPageContainer(-1, {});
136
183
  expect(spy.callCount).toBe(0);
137
184
  });
138
185
 
139
186
  test("createTextLayer will render the last page and create text layer properly", async () => {
140
187
  const $container = br.refs.$brContainer;
141
- sinon.stub(br._plugins.textSelection, "getPageText")
188
+ sinon.stub(br.plugins.textSelection, "getPageText")
142
189
  .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
143
190
  const pageIndex = br.data.length - 1;
144
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: pageIndex, width: 100, height: 100 }});
191
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: pageIndex, width: 100, height: 100 }});
145
192
  expect($container.find(".BRtextLayer").length).toBe(1);
146
193
  expect($container.find("p").length).toBe(1);
147
194
  });
@@ -149,9 +196,9 @@ describe("Generic tests", () => {
149
196
  test("createTextLayer will not create text layer if there are too many words", async () => {
150
197
  const $container = br.refs.$brContainer;
151
198
  const xml = FAKE_XML_1WORD.replace(/<WORD.*<\/WORD>/, FAKE_XML_1WORD.match(/<WORD.*<\/WORD>/)[0].repeat(3000));
152
- sinon.stub(br._plugins.textSelection, "getPageText")
199
+ sinon.stub(br.plugins.textSelection, "getPageText")
153
200
  .returns($(new DOMParser().parseFromString(xml, "text/xml")));
154
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 0, width: 100, height: 100 }});
201
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 0, width: 100, height: 100 }});
155
202
  expect($container.find(".BRtextLayer").length).toBe(0);
156
203
  expect($container.find("p").length).toBe(0);
157
204
  expect($container.find(".BRwordElement").length).toBe(0);
@@ -159,9 +206,9 @@ describe("Generic tests", () => {
159
206
 
160
207
  test("createTextLayer creates text layer with paragraph with 1 word element", async () => {
161
208
  const $container = br.refs.$brContainer;
162
- sinon.stub(br._plugins.textSelection, "getPageText")
209
+ sinon.stub(br.plugins.textSelection, "getPageText")
163
210
  .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
164
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 1, width: 100, height: 100 }});
211
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 1, width: 100, height: 100 }});
165
212
  expect($container.find(".BRtextLayer").length).toBe(1);
166
213
  expect($container.find("p").length).toBe(1);
167
214
  expect($container.find(".BRwordElement").length).toBe(1);
@@ -170,9 +217,9 @@ describe("Generic tests", () => {
170
217
 
171
218
  test("createTextLayer creates text layer with paragraph with multiple word elements", async () => {
172
219
  const $container = br.refs.$brContainer;
173
- sinon.stub(br._plugins.textSelection, "getPageText")
220
+ sinon.stub(br.plugins.textSelection, "getPageText")
174
221
  .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_WORDS, "text/xml")));
175
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 2, width: 100, height: 100 }});
222
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 2, width: 100, height: 100 }});
176
223
  expect($container.find(".BRtextLayer").length).toBe(1);
177
224
  expect($container.find("p").length).toBe(1);
178
225
  expect($container.find(".BRwordElement").length).toBe(3);
@@ -181,9 +228,9 @@ describe("Generic tests", () => {
181
228
 
182
229
  test("createTextLayer creates text layer with paragraph with word with 5 params coordinates", async () => {
183
230
  const $container = br.refs.$brContainer;
184
- sinon.stub(br._plugins.textSelection, "getPageText")
231
+ sinon.stub(br.plugins.textSelection, "getPageText")
185
232
  .returns($(new DOMParser().parseFromString(FAKE_XML_5COORDS, "text/xml")));
186
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
233
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
187
234
  expect($container.find(".BRtextLayer").length).toBe(1);
188
235
  expect($container.find("p").length).toBe(1);
189
236
  expect($container.find(".BRwordElement").length).toBe(1);
@@ -191,9 +238,9 @@ describe("Generic tests", () => {
191
238
 
192
239
  test("createTextLayer handles multiple lines", async () => {
193
240
  const $container = br.refs.$brContainer;
194
- sinon.stub(br._plugins.textSelection, "getPageText")
241
+ sinon.stub(br.plugins.textSelection, "getPageText")
195
242
  .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
196
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
243
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
197
244
  expect($container.find(".BRtextLayer").length).toBe(1);
198
245
  expect($container.find("p").length).toBe(1);
199
246
  expect($container.find(".BRlineElement").length).toBe(3);
@@ -206,9 +253,9 @@ describe("Generic tests", () => {
206
253
 
207
254
  test("createTextLayer repairs trailing hyphens", async () => {
208
255
  const $container = br.refs.$brContainer;
209
- sinon.stub(br._plugins.textSelection, "getPageText")
256
+ sinon.stub(br.plugins.textSelection, "getPageText")
210
257
  .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_LINES, "text/xml")));
211
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
258
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
212
259
 
213
260
  expect($container.find(".BRwordElement--hyphen").length).toBe(1);
214
261
  expect($container.find(".BRwordElement--hyphen").closest(".BRlineElement").text().endsWith(' ')).toBe(false);
@@ -217,9 +264,9 @@ describe("Generic tests", () => {
217
264
 
218
265
  test("createTextLayer can handle empty xml", async () => {
219
266
  const $container = br.refs.$brContainer;
220
- sinon.stub(br._plugins.textSelection, "getPageText")
267
+ sinon.stub(br.plugins.textSelection, "getPageText")
221
268
  .returns($(new DOMParser().parseFromString(FAKE_XML_EMPTY, "text/xml")));
222
- await br._plugins.textSelection.createTextLayer({ $container, page: { index: 4, width: 100, height: 100 }});
269
+ await br.plugins.textSelection.createTextLayer({ $container, page: { index: 4, width: 100, height: 100 }});
223
270
  expect($container.find(".BRtextLayer").length).toBe(1);
224
271
  expect($container.find("p").length).toBe(0);
225
272
  expect($container.find(".BRwordElement").length).toBe(0);
@@ -228,7 +275,7 @@ describe("Generic tests", () => {
228
275
  const LONG_PRESS_DURATION = 500;
229
276
  test("calling stopPageFlip does not allow long click to flip the page", () => {
230
277
  const $container = br.refs.$brContainer;
231
- br._plugins.textSelection.stopPageFlip($container);
278
+ br.plugins.textSelection.stopPageFlip($container);
232
279
  const currIndex = br.currentIndex();
233
280
  $container.find("BRwordElement").trigger("mousedown");
234
281
  // Waits for long press
@@ -270,6 +317,38 @@ describe("Cache", () => {
270
317
  });
271
318
  });
272
319
 
320
+ describe('genAt', () => {
321
+ test('handles empty', () => {
322
+ expect(genAt(genRange(-1), 0)).toBeUndefined();
323
+ });
324
+
325
+ test('handles non-empty', () => {
326
+ expect(genAt(genRange(3), 0)).toBe(0);
327
+ expect(genAt(genRange(3), 1)).toBe(1);
328
+ expect(genAt(genRange(3), 2)).toBe(2);
329
+ });
330
+
331
+ test('handles out of bounds', () => {
332
+ expect(genAt(genRange(3), 4)).toBeUndefined();
333
+ expect(genAt(genRange(3), -1)).toBeUndefined();
334
+ });
335
+ });
336
+
337
+ describe('genFilter', () => {
338
+ test('handles empty', () => {
339
+ expect(Array.from(genFilter(genRange(0), x => x > 0))).toEqual([]);
340
+ });
341
+
342
+ test('handles non-empty', () => {
343
+ expect(Array.from(genFilter(genRange(3), x => x > 1))).toEqual([2, 3]);
344
+ expect(Array.from(genFilter(genRange(3), x => x < 1))).toEqual([0]);
345
+ });
346
+
347
+ test('handles all false', () => {
348
+ expect(Array.from(genFilter(genRange(3), x => x > 3))).toEqual([]);
349
+ });
350
+ });
351
+
273
352
  describe('genMap', () => {
274
353
  test('handles empty', () => {
275
354
  expect(Array.from(genMap([], x => x ** 2))).toEqual([]);
@@ -314,3 +393,55 @@ describe('zip', () => {
314
393
  expect(Array.from(zip([1, 2], [3, 4]))).toEqual([[1, 3], [2, 4]]);
315
394
  });
316
395
  });
396
+
397
+ describe('walkBetweenNodes', () => {
398
+ const tree = $(FAKE_XML_MULT_LINES);
399
+
400
+ test('handles empty', () => {
401
+ const result = Array.from(walkBetweenNodes(tree[0], tree[0]));
402
+ expect(result).toHaveLength(1);
403
+ expect(result[0]).toBe(tree[0]);
404
+ });
405
+
406
+ test('Words on same line', () => {
407
+ const start = tree.find('WORD')[2];
408
+ const end = start.nextElementSibling;
409
+ // Use first child so we hit the text nodes
410
+ const result = Array.from(walkBetweenNodes(start.firstChild, end.firstChild));
411
+ expect(result).toHaveLength(5);
412
+ expect(result[0].nodeType).toBe(Node.TEXT_NODE);
413
+ expect(result[0].textContent).toBe('false ');
414
+ expect(result[1]).toBe(start);
415
+ // Whitespace
416
+ expect(result[2].nodeType).toBe(Node.TEXT_NODE);
417
+ expect(result[2].textContent).toMatch(/^\s*$/);
418
+ expect(result[3]).toBe(end);
419
+ expect(result[4].nodeType).toBe(Node.TEXT_NODE);
420
+ expect(result[4].textContent).toBe('judgment ');
421
+ });
422
+
423
+ test('Words on different lines', () => {
424
+ const start = tree.find('WORD')[2];
425
+ const end = tree.find('WORD')[19];
426
+ const result = Array.from(walkBetweenNodes(start.firstChild, end.firstChild));
427
+ // Expect two LINES in result
428
+ expect(result.filter(x => x.nodeName == 'LINE')).toHaveLength(2);
429
+ // Expect 18 WORDs in result
430
+ expect(result.filter(x => x.nodeName == 'WORD')).toHaveLength(18);
431
+ // First word should be the start word
432
+ expect(result[0].parentElement).toBe(start);
433
+ expect(result[0].textContent).toBe('false ');
434
+ // Last word should be the end word
435
+ expect(result[result.length - 1].parentElement).toBe(end);
436
+ expect(result[result.length - 1].textContent).toBe('Suppose');
437
+ });
438
+ });
439
+
440
+ /**
441
+ * @param {number} n
442
+ */
443
+ function* genRange(n) {
444
+ for (let i = 0; i <= n; i++) {
445
+ yield i;
446
+ }
447
+ }
@@ -31,7 +31,7 @@ beforeEach(() => {
31
31
  });
32
32
  br.initToolbar = jest.fn();
33
33
  br.showProgressPopup = jest.fn();
34
- br._plugins.search.searchXHR = jest.fn();
34
+ br.plugins.search.searchXHR = jest.fn();
35
35
  });
36
36
 
37
37
  afterEach(() => {
@@ -45,18 +45,18 @@ describe('Plugin: Search', () => {
45
45
  });
46
46
 
47
47
  test('Constructs SearchView', () => {
48
- expect(br._plugins.search.searchView).toBeDefined();
48
+ expect(br.plugins.search.searchView).toBeDefined();
49
49
  });
50
50
 
51
51
  test('On init, it will run a search if given `options.initialSearchTerm`', () => {
52
- br._plugins.search.search = jest.fn();
52
+ br.plugins.search.search = jest.fn();
53
53
  br.options.plugins.search.initialSearchTerm = 'foo';
54
54
  br.init();
55
55
 
56
- expect(br._plugins.search.search).toHaveBeenCalled();
57
- expect(br._plugins.search.search.mock.calls[0][1])
56
+ expect(br.plugins.search.search).toHaveBeenCalled();
57
+ expect(br.plugins.search.search.mock.calls[0][1])
58
58
  .toHaveProperty('goToFirstResult', true);
59
- expect(br._plugins.search.search.mock.calls[0][1])
59
+ expect(br.plugins.search.search.mock.calls[0][1])
60
60
  .toHaveProperty('suppressFragmentChange', false);
61
61
  });
62
62
 
@@ -75,7 +75,7 @@ describe('Plugin: Search', () => {
75
75
  test('SearchStarted event fires and should go to first result', () => {
76
76
  br.init();
77
77
  br.search('foo', { goToFirstResult: true});
78
- expect(br._plugins.search.options.goToFirstResult).toBeTruthy();
78
+ expect(br.plugins.search.options.goToFirstResult).toBeTruthy();
79
79
  });
80
80
 
81
81
  test('SearchCallback event fires when AJAX search returns results', async () => {
@@ -78,16 +78,16 @@ describe('View: Plugin: Search', () => {
78
78
  const event = new CustomEvent(`${namespace}SearchCallback`);
79
79
  const options = { goToFirstResult: false };
80
80
 
81
- expect(br._plugins.search.searchView.dom.searchNavigation).toBeUndefined();
81
+ expect(br.plugins.search.searchView.dom.searchNavigation).toBeUndefined();
82
82
 
83
- br._plugins.search.searchView.handleSearchCallback(event, { results, options});
84
- expect(br._plugins.search.searchView.dom.searchNavigation).toBeDefined();
83
+ br.plugins.search.searchView.handleSearchCallback(event, { results, options});
84
+ expect(br.plugins.search.searchView.dom.searchNavigation).toBeDefined();
85
85
  });
86
86
  test('has controls', () => {
87
87
  br.init();
88
88
  const event = new CustomEvent(`${namespace}SearchCallback`);
89
89
  const options = { goToFirstResult: false };
90
- br._plugins.search.searchView.handleSearchCallback(event, { results, options});
90
+ br.plugins.search.searchView.handleSearchCallback(event, { results, options});
91
91
 
92
92
  const searchResultsNav = document.querySelector('.BRsearch-navigation');
93
93
  expect(searchResultsNav).toBeDefined();
@@ -102,9 +102,9 @@ describe('View: Plugin: Search', () => {
102
102
  br.init();
103
103
  const event = new CustomEvent(`${namespace}SearchCallback`);
104
104
  const options = { goToFirstResult: false };
105
- br._plugins.search.searchView.handleSearchCallback(event, { results: resultWithScript, options });
105
+ br.plugins.search.searchView.handleSearchCallback(event, { results: resultWithScript, options });
106
106
 
107
- expect(br._plugins.search.searchView.dom.searchNavigation.parent().html()).not.toContain('<script>alert(1);</script>');
107
+ expect(br.plugins.search.searchView.dom.searchNavigation.parent().html()).not.toContain('<script>alert(1);</script>');
108
108
  });
109
109
 
110
110
  describe('Click events handlers', () => {
@@ -114,7 +114,7 @@ describe('View: Plugin: Search', () => {
114
114
  br.trigger = (eventName) => eventNameTriggered = eventName;
115
115
 
116
116
  expect(eventNameTriggered).toBeFalsy();
117
- br._plugins.search.searchView.toggleSidebar();
117
+ br.plugins.search.searchView.toggleSidebar();
118
118
  expect(eventNameTriggered).toEqual('ToggleSearchMenu');
119
119
  });
120
120
  it('triggers custom event when closing navbar', () => {
@@ -123,7 +123,7 @@ describe('View: Plugin: Search', () => {
123
123
  br.trigger = (eventName) => eventNameTriggered = eventName;
124
124
 
125
125
  expect(eventNameTriggered).toBeFalsy();
126
- br._plugins.search.searchView.clearSearchFieldAndResults();
126
+ br.plugins.search.searchView.clearSearchFieldAndResults();
127
127
  expect(eventNameTriggered).toEqual('SearchResultsCleared');
128
128
  });
129
129
  });
@@ -1,4 +1,4 @@
1
- import { marshallSearchResults } from "@/src/plugins/search/utils";
1
+ import { marshallSearchResults } from "@/src/plugins/search/utils.js";
2
2
 
3
3
  export const DUMMY_RESULTS = {
4
4
  ia: "adventuresofoli00dick",
@@ -1,6 +1,6 @@
1
1
  import sinon from 'sinon';
2
- import PageChunkIterator from "@/src/plugins/tts/PageChunkIterator";
3
- import PageChunk from '@/src/plugins/tts/PageChunk';
2
+ import PageChunkIterator from "@/src/plugins/tts/PageChunkIterator.js";
3
+ import PageChunk from '@/src/plugins/tts/PageChunk.js';
4
4
 
5
5
  describe('Buffers pages', () => {
6
6
  test('Does not error if no room for reverse buffer', async () => {
@@ -1,4 +1,4 @@
1
- import { UrlPlugin } from '@/src/plugins/url/UrlPlugin';
1
+ import { UrlPlugin } from '@/src/plugins/url/UrlPlugin.js';
2
2
 
3
3
  afterEach(() => {
4
4
  jest.clearAllMocks();