@internetarchive/bookreader 5.0.0-88-alpha.11 → 5.0.0-89

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 (243) hide show
  1. package/BookReader/BookReader.css +17 -3
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/ia-bookreader-bundle.js +87 -108
  5. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  6. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  7. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  8. package/BookReader/plugins/plugin.autoplay.js +1 -1
  9. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  10. package/BookReader/plugins/plugin.iiif.js +1 -1
  11. package/BookReader/plugins/plugin.iiif.js.map +1 -1
  12. package/BookReader/plugins/plugin.resume.js +1 -1
  13. package/BookReader/plugins/plugin.resume.js.map +1 -1
  14. package/BookReader/plugins/plugin.search.js +1 -1
  15. package/BookReader/plugins/plugin.search.js.map +1 -1
  16. package/BookReader/plugins/plugin.text_selection.js +1 -1
  17. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  18. package/BookReader/plugins/plugin.tts.js +1 -1
  19. package/BookReader/plugins/plugin.tts.js.map +1 -1
  20. package/BookReader/plugins/plugin.url.js +1 -1
  21. package/BookReader/plugins/plugin.url.js.map +1 -1
  22. package/CHANGELOG.md +14 -0
  23. package/babel.config.js +12 -30
  24. package/codecov.yml +1 -1
  25. package/jsconfig.json +1 -3
  26. package/package.json +14 -16
  27. package/src/BookNavigator/search/search-results.js +1 -1
  28. package/src/BookReader/ImageCache.js +48 -15
  29. package/src/BookReader/Mode1UpLit.js +56 -86
  30. package/src/BookReader/Mode2UpLit.js +5 -5
  31. package/src/BookReader/Navbar/Navbar.js +53 -11
  32. package/src/BookReader/PageContainer.js +41 -22
  33. package/src/BookReader/options.js +27 -3
  34. package/src/BookReader/utils.js +10 -0
  35. package/src/BookReader.js +120 -21
  36. package/src/BookReaderPlugin.js +44 -0
  37. package/src/css/_BRnav.scss +0 -3
  38. package/src/css/_BRpages.scss +21 -2
  39. package/src/css/_controls.scss +4 -0
  40. package/src/plugins/plugin.archive_analytics.js +84 -78
  41. package/src/plugins/plugin.autoplay.js +98 -102
  42. package/src/plugins/plugin.chapters.js +17 -22
  43. package/src/plugins/plugin.iiif.js +16 -30
  44. package/src/plugins/plugin.resume.js +54 -51
  45. package/src/plugins/plugin.text_selection.js +68 -76
  46. package/src/plugins/tts/AbstractTTSEngine.js +2 -4
  47. package/src/plugins/tts/PageChunk.js +5 -9
  48. package/src/plugins/tts/PageChunkIterator.js +3 -5
  49. package/src/plugins/tts/plugin.tts.js +309 -329
  50. package/src/plugins/url/plugin.url.js +1 -1
  51. package/src/util/strings.js +1 -0
  52. package/tests/e2e/autoplay.test.js +8 -5
  53. package/tests/e2e/helpers/base.js +2 -2
  54. package/tests/e2e/helpers/mockSearch.js +6 -9
  55. package/tests/jest/BookReader/Navbar/Navbar.test.js +16 -3
  56. package/tests/jest/BookReader/PageContainer.test.js +96 -55
  57. package/tests/jest/BookReader/utils.test.js +21 -0
  58. package/tests/jest/BookReader.test.js +13 -12
  59. package/tests/jest/plugins/plugin.archive_analytics.test.js +8 -11
  60. package/tests/jest/plugins/plugin.autoplay.test.js +9 -22
  61. package/tests/jest/plugins/plugin.resume.test.js +19 -32
  62. package/tests/jest/plugins/plugin.text_selection.test.js +23 -24
  63. package/dist/esm/BookNavigator/assets/bookmark-colors.js +0 -4
  64. package/dist/esm/BookNavigator/assets/button-base.js +0 -4
  65. package/dist/esm/BookNavigator/assets/ia-logo.js +0 -4
  66. package/dist/esm/BookNavigator/assets/icon_checkmark.js +0 -8
  67. package/dist/esm/BookNavigator/assets/icon_close.js +0 -4
  68. package/dist/esm/BookNavigator/book-navigator.js +0 -612
  69. package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +0 -35
  70. package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +0 -78
  71. package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +0 -160
  72. package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -24
  73. package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +0 -55
  74. package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +0 -521
  75. package/dist/esm/BookNavigator/delete-modal-actions.js +0 -29
  76. package/dist/esm/BookNavigator/downloads/downloads-provider.js +0 -84
  77. package/dist/esm/BookNavigator/downloads/downloads.js +0 -69
  78. package/dist/esm/BookNavigator/search/search-provider.js +0 -238
  79. package/dist/esm/BookNavigator/search/search-results.js +0 -161
  80. package/dist/esm/BookNavigator/sharing.js +0 -26
  81. package/dist/esm/BookNavigator/viewable-files.js +0 -94
  82. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -83
  83. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +0 -131
  84. package/dist/esm/BookReader/BookModel.js +0 -575
  85. package/dist/esm/BookReader/DragScrollable.js +0 -224
  86. package/dist/esm/BookReader/ImageCache.js +0 -122
  87. package/dist/esm/BookReader/Mode1Up.js +0 -114
  88. package/dist/esm/BookReader/Mode1UpLit.js +0 -579
  89. package/dist/esm/BookReader/Mode2Up.js +0 -106
  90. package/dist/esm/BookReader/Mode2UpLit.js +0 -1020
  91. package/dist/esm/BookReader/ModeCoordinateSpace.js +0 -28
  92. package/dist/esm/BookReader/ModeSmoothZoom.js +0 -318
  93. package/dist/esm/BookReader/ModeThumb.js +0 -366
  94. package/dist/esm/BookReader/Navbar/Navbar.js +0 -253
  95. package/dist/esm/BookReader/PageContainer.js +0 -165
  96. package/dist/esm/BookReader/ReduceSet.js +0 -27
  97. package/dist/esm/BookReader/Toolbar/Toolbar.js +0 -242
  98. package/dist/esm/BookReader/events.js +0 -20
  99. package/dist/esm/BookReader/options.js +0 -331
  100. package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +0 -48
  101. package/dist/esm/BookReader/utils/ScrollClassAdder.js +0 -31
  102. package/dist/esm/BookReader/utils/SelectionObserver.js +0 -42
  103. package/dist/esm/BookReader/utils/classes.js +0 -37
  104. package/dist/esm/BookReader/utils.js +0 -315
  105. package/dist/esm/BookReader.js +0 -1828
  106. package/dist/esm/assets/icons/1up.svg +0 -12
  107. package/dist/esm/assets/icons/2up.svg +0 -15
  108. package/dist/esm/assets/icons/advance.svg +0 -26
  109. package/dist/esm/assets/icons/chevron-right.svg +0 -1
  110. package/dist/esm/assets/icons/close-circle-dark.svg +0 -1
  111. package/dist/esm/assets/icons/close-circle.svg +0 -1
  112. package/dist/esm/assets/icons/fullscreen.svg +0 -17
  113. package/dist/esm/assets/icons/fullscreen_exit.svg +0 -17
  114. package/dist/esm/assets/icons/hamburger.svg +0 -15
  115. package/dist/esm/assets/icons/left-arrow.svg +0 -12
  116. package/dist/esm/assets/icons/magnify-minus.svg +0 -12
  117. package/dist/esm/assets/icons/magnify-plus.svg +0 -13
  118. package/dist/esm/assets/icons/magnify.svg +0 -15
  119. package/dist/esm/assets/icons/pause.svg +0 -23
  120. package/dist/esm/assets/icons/play.svg +0 -22
  121. package/dist/esm/assets/icons/playback-speed.svg +0 -34
  122. package/dist/esm/assets/icons/read-aloud.svg +0 -22
  123. package/dist/esm/assets/icons/review.svg +0 -22
  124. package/dist/esm/assets/icons/thumbnails.svg +0 -17
  125. package/dist/esm/assets/icons/voice.svg +0 -1
  126. package/dist/esm/assets/icons/volume-full.svg +0 -22
  127. package/dist/esm/assets/images/BRicons.png +0 -0
  128. package/dist/esm/assets/images/BRicons.svg +0 -94
  129. package/dist/esm/assets/images/BRicons_ia.png +0 -0
  130. package/dist/esm/assets/images/back_pages.png +0 -0
  131. package/dist/esm/assets/images/book_bottom_icon.png +0 -0
  132. package/dist/esm/assets/images/book_down_icon.png +0 -0
  133. package/dist/esm/assets/images/book_left_icon.png +0 -0
  134. package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
  135. package/dist/esm/assets/images/book_right_icon.png +0 -0
  136. package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
  137. package/dist/esm/assets/images/book_top_icon.png +0 -0
  138. package/dist/esm/assets/images/book_up_icon.png +0 -0
  139. package/dist/esm/assets/images/books_graphic.svg +0 -177
  140. package/dist/esm/assets/images/booksplit.png +0 -0
  141. package/dist/esm/assets/images/control_pause_icon.png +0 -0
  142. package/dist/esm/assets/images/control_play_icon.png +0 -0
  143. package/dist/esm/assets/images/embed_icon.png +0 -0
  144. package/dist/esm/assets/images/icon-home-ia.png +0 -0
  145. package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
  146. package/dist/esm/assets/images/icon_alert-xs.png +0 -0
  147. package/dist/esm/assets/images/icon_book.svg +0 -12
  148. package/dist/esm/assets/images/icon_bookmark.svg +0 -12
  149. package/dist/esm/assets/images/icon_close-pop.png +0 -0
  150. package/dist/esm/assets/images/icon_download.png +0 -0
  151. package/dist/esm/assets/images/icon_gear.svg +0 -14
  152. package/dist/esm/assets/images/icon_hamburger.svg +0 -20
  153. package/dist/esm/assets/images/icon_home.png +0 -0
  154. package/dist/esm/assets/images/icon_home.svg +0 -21
  155. package/dist/esm/assets/images/icon_home_ia.png +0 -0
  156. package/dist/esm/assets/images/icon_indicator.png +0 -0
  157. package/dist/esm/assets/images/icon_info.svg +0 -11
  158. package/dist/esm/assets/images/icon_one_page.svg +0 -8
  159. package/dist/esm/assets/images/icon_pause.svg +0 -1
  160. package/dist/esm/assets/images/icon_play.svg +0 -1
  161. package/dist/esm/assets/images/icon_playback-rate.svg +0 -15
  162. package/dist/esm/assets/images/icon_return.png +0 -0
  163. package/dist/esm/assets/images/icon_search_button.svg +0 -8
  164. package/dist/esm/assets/images/icon_share.svg +0 -9
  165. package/dist/esm/assets/images/icon_skip-ahead.svg +0 -6
  166. package/dist/esm/assets/images/icon_skip-back.svg +0 -13
  167. package/dist/esm/assets/images/icon_speaker.svg +0 -18
  168. package/dist/esm/assets/images/icon_speaker_open.svg +0 -10
  169. package/dist/esm/assets/images/icon_thumbnails.svg +0 -12
  170. package/dist/esm/assets/images/icon_toc.svg +0 -5
  171. package/dist/esm/assets/images/icon_two_pages.svg +0 -9
  172. package/dist/esm/assets/images/icon_zoomer.png +0 -0
  173. package/dist/esm/assets/images/loading.gif +0 -0
  174. package/dist/esm/assets/images/logo_icon.png +0 -0
  175. package/dist/esm/assets/images/marker_chap-off.png +0 -0
  176. package/dist/esm/assets/images/marker_chap-off.svg +0 -11
  177. package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
  178. package/dist/esm/assets/images/marker_chap-on.png +0 -0
  179. package/dist/esm/assets/images/marker_chap-on.svg +0 -11
  180. package/dist/esm/assets/images/marker_srch-on.svg +0 -11
  181. package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
  182. package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
  183. package/dist/esm/assets/images/nav_control-dn.png +0 -0
  184. package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
  185. package/dist/esm/assets/images/nav_control-up.png +0 -0
  186. package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
  187. package/dist/esm/assets/images/nav_control.png +0 -0
  188. package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
  189. package/dist/esm/assets/images/paper-badge.png +0 -0
  190. package/dist/esm/assets/images/print_icon.png +0 -0
  191. package/dist/esm/assets/images/progressbar.gif +0 -0
  192. package/dist/esm/assets/images/right_edges.png +0 -0
  193. package/dist/esm/assets/images/slider.png +0 -0
  194. package/dist/esm/assets/images/slider_ia.png +0 -0
  195. package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
  196. package/dist/esm/assets/images/transparent.png +0 -0
  197. package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
  198. package/dist/esm/assets/images/unviewable_page.png +0 -0
  199. package/dist/esm/assets/images/zoom_in_icon.png +0 -0
  200. package/dist/esm/assets/images/zoom_out_icon.png +0 -0
  201. package/dist/esm/css/BookReader.scss +0 -85
  202. package/dist/esm/css/_BRBookmarks.scss +0 -29
  203. package/dist/esm/css/_BRComponent.scss +0 -13
  204. package/dist/esm/css/_BRfloat.scss +0 -197
  205. package/dist/esm/css/_BRicon.scss +0 -54
  206. package/dist/esm/css/_BRmain.scss +0 -262
  207. package/dist/esm/css/_BRnav.scss +0 -354
  208. package/dist/esm/css/_BRpages.scss +0 -213
  209. package/dist/esm/css/_BRsearch.scss +0 -268
  210. package/dist/esm/css/_BRtoolbar.scss +0 -84
  211. package/dist/esm/css/_BRvendor.scss +0 -5
  212. package/dist/esm/css/_TextSelection.scss +0 -108
  213. package/dist/esm/css/_colorbox.scss +0 -52
  214. package/dist/esm/css/_controls.scss +0 -257
  215. package/dist/esm/css/_icons.scss +0 -121
  216. package/dist/esm/ia-bookreader/ia-bookreader.js +0 -141
  217. package/dist/esm/jquery-wrapper.js +0 -3
  218. package/dist/esm/plugins/plugin.archive_analytics.js +0 -72
  219. package/dist/esm/plugins/plugin.autoplay.js +0 -119
  220. package/dist/esm/plugins/plugin.chapters.js +0 -288
  221. package/dist/esm/plugins/plugin.iframe.js +0 -44
  222. package/dist/esm/plugins/plugin.iiif.js +0 -146
  223. package/dist/esm/plugins/plugin.resume.js +0 -66
  224. package/dist/esm/plugins/plugin.text_selection.js +0 -621
  225. package/dist/esm/plugins/plugin.vendor-fullscreen.js +0 -227
  226. package/dist/esm/plugins/search/plugin.search.js +0 -499
  227. package/dist/esm/plugins/search/utils.js +0 -42
  228. package/dist/esm/plugins/search/view.js +0 -360
  229. package/dist/esm/plugins/tts/AbstractTTSEngine.js +0 -282
  230. package/dist/esm/plugins/tts/FestivalTTSEngine.js +0 -192
  231. package/dist/esm/plugins/tts/PageChunk.js +0 -105
  232. package/dist/esm/plugins/tts/PageChunkIterator.js +0 -155
  233. package/dist/esm/plugins/tts/WebTTSEngine.js +0 -364
  234. package/dist/esm/plugins/tts/plugin.tts.js +0 -315
  235. package/dist/esm/plugins/tts/tooltip_dict.js +0 -14
  236. package/dist/esm/plugins/tts/utils.js +0 -79
  237. package/dist/esm/plugins/url/UrlPlugin.js +0 -197
  238. package/dist/esm/plugins/url/plugin.url.js +0 -212
  239. package/dist/esm/util/browserSniffing.js +0 -56
  240. package/dist/esm/util/debouncer.js +0 -25
  241. package/dist/esm/util/docCookies.js +0 -75
  242. package/dist/esm/util/strings.js +0 -34
  243. package/index.js +0 -2
@@ -106,7 +106,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
106
106
  this.trigger(BookReader.eventNames.stop);
107
107
  if (this.animating) {
108
108
  // Queue change if animating
109
- if (this.autoStop) this.autoStop();
109
+ this._plugins.autoplay?.stop();
110
110
  this.animationFinishedCallback = updateParams;
111
111
  } else {
112
112
  // update immediately
@@ -9,6 +9,7 @@
9
9
  * @param {StringWithVars|String} template
10
10
  * @param { {[varName: string]: { toString: () => string} } } vars
11
11
  * @param { {[varName: string]: { toString: () => string} } } [overrides]
12
+ * @returns {StringWithVars|string}
12
13
  */
13
14
  export function applyVariables(template, vars, overrides = {}, possibleFilters = APPLY_FILTERS) {
14
15
  return template?.replace(/\{\{([^}]*?)\}\}/g, ($0, $1) => {
@@ -2,12 +2,15 @@ import { ClientFunction } from 'testcafe';
2
2
  import params from './helpers/params';
3
3
 
4
4
  const getLocationHref = ClientFunction(() => window.location.href.toString());
5
- const FLIP_SPEED = 1000;
6
- const FIRST_PAGE_DELAY = 2000;
5
+ const FLIP_SPEED = 200;
6
+ const FLIP_DELAY = 500;
7
7
 
8
- fixture `Autoplay plugin`.page `${params.baseUrl}/BookReaderDemo/demo-internetarchive.html?ocaid=goody&autoflip=1`;
8
+ fixture `Autoplay plugin`.page `${params.baseUrl}/BookReaderDemo/demo-internetarchive.html?ocaid=goody&autoflip=1&flipSpeed=${FLIP_SPEED}&flipDelay=${FLIP_DELAY}`;
9
9
 
10
10
  test('page auto-advances after allotted flip speed and delay', async t => {
11
- await t.wait(2 * FLIP_SPEED + FIRST_PAGE_DELAY);
12
- await t.expect(getLocationHref()).match(/page\/n3/);
11
+ // Flips from cover, to #page/n1 to #page/n3, etc
12
+ await t.expect(getLocationHref()).notMatch(/page\/n\d+/);
13
+ await t.wait(2 * (FLIP_SPEED + FLIP_DELAY) + 500);
14
+ // Don't check for a specific page; initial load time can vary
15
+ await t.expect(getLocationHref()).match(/page\/n\d+/);
13
16
  });
@@ -78,8 +78,8 @@ export function runBaseTests (br) {
78
78
 
79
79
  // Check if uses plugin.resume.js
80
80
  const usesResume = ClientFunction(() => {
81
- const hasResumePlugin = typeof(br.getResumeValue) !== "undefined";
82
- const hasResumeValue = hasResumePlugin ? br.getResumeValue() : false;
81
+ const hasResumePlugin = typeof(br._plugins.resume) !== "undefined";
82
+ const hasResumeValue = hasResumePlugin ? br._plugins.resume.getResumeValue() : false;
83
83
  return hasResumeValue;
84
84
  });
85
85
 
@@ -4,21 +4,18 @@ export const PAGE_FIRST_RESULT = 30;
4
4
 
5
5
  export const SEARCH_INSIDE_URL_RE = /https:\/\/ia[0-9]+\.us\.archive\.org\/fulltext\/inside\.php\?item_id=.*/;
6
6
 
7
- //adding jQueryxxxxxxxx-xxxxxxxx (semi-random numbers) from request url to returned search request object
8
7
  /** Mock response for a matching search term. */
9
8
  export function mockResponseFound(req, res) {
10
- const requestUrl = new URL(req.url);
11
- const jqueryUrl = requestUrl.searchParams.get("callback");
12
- const wholeString = jqueryUrl + '(' + JSON.stringify(MOCKED_RESPONSE_FOUND) + ')';
13
- res.setBody(wholeString);
9
+ res.headers['Access-Control-Allow-Origin'] = '*';
10
+ res.headers['Content-Type'] = 'application/json';
11
+ res.setBody(JSON.stringify(MOCKED_RESPONSE_FOUND));
14
12
  }
15
13
 
16
14
  /** Mock response for a matching search term. */
17
15
  export function mockResponseNotFound(req, res) {
18
- const requestUrl = new URL(req.url);
19
- const jqueryUrl = requestUrl.searchParams.get("callback");
20
- const wholeString = jqueryUrl + '(' + JSON.stringify(MOCKED_RESPONSE_NOT_FOUND) + ')';
21
- res.setBody(wholeString);
16
+ res.headers['Access-Control-Allow-Origin'] = '*';
17
+ res.headers['Content-Type'] = 'application/json';
18
+ res.setBody(JSON.stringify(MOCKED_RESPONSE_NOT_FOUND));
22
19
  }
23
20
 
24
21
  const PAGE_FIRST_RESULT_ADJUSTED = PAGE_FIRST_RESULT + 12;
@@ -4,17 +4,30 @@ import BookReader from '@/src/BookReader.js';
4
4
 
5
5
  describe('getNavPageNumHtml', () => {
6
6
  const f = getNavPageNumHtml;
7
- test('handle n-prefixed page numbers', () => {
7
+
8
+ test('handle n-prefixed page numbers-min format', () => {
8
9
  expect(f(3, 40, 'n3', '', 40)).toBe('(4 of 40)');
9
10
  });
10
11
 
11
- test('handle regular page numbers', () => {
12
+ test('handle regular page numbers-min format', () => {
12
13
  expect(f(3, 40, '14', '', 40)).toBe('14 of 40');
13
14
  });
14
15
 
15
- test('handle no max page', () => {
16
+ test('handle no max page-min format', () => {
16
17
  expect(f(3, 40, '14', '', null)).toBe('14');
17
18
  });
19
+
20
+ test('handle n-prefixed page numbers-max format', () => {
21
+ expect(f(3, 40, 'n3', '', 40, true)).toBe('Page — (4/40)');
22
+ });
23
+
24
+ test('handle regular page numbers-max format', () => {
25
+ expect(f(3, 40, '14', '', 40, true)).toBe('Page 14 (4/40)');
26
+ });
27
+
28
+ test('handle no max page-max format', () => {
29
+ expect(f(3, 40, '14', '', null, true)).toBe('Page 14 (4/40)');
30
+ });
18
31
  });
19
32
 
20
33
  /** @type {BookReader} */
@@ -1,4 +1,37 @@
1
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
+ };
2
35
 
3
36
  describe('constructor', () => {
4
37
  test('protected books', () => {
@@ -33,13 +66,15 @@ describe('constructor', () => {
33
66
 
34
67
  describe('update', () => {
35
68
  test('dimensions sets CSS', () => {
36
- const pc = new PageContainer(null, {});
69
+ const imageCache = new ImageCache(SAMPLE_BOOK);
70
+ const pc = new PageContainer(null, {imageCache});
37
71
  pc.update({ dimensions: { left: 20 } });
38
72
  expect(pc.$container[0].style.left).toBe('20px');
39
73
  });
40
74
 
41
75
  test('does not create image if empty page', () => {
42
- const pc = new PageContainer(null, {});
76
+ const imageCache = new ImageCache(SAMPLE_BOOK);
77
+ const pc = new PageContainer(null, {imageCache});
43
78
  pc.update({ reduce: null });
44
79
  expect(pc.$img).toBeNull();
45
80
  pc.update({ reduce: 7 });
@@ -47,71 +82,77 @@ describe('update', () => {
47
82
  });
48
83
 
49
84
  test('does not create image if no reduce', () => {
50
- const pc = new PageContainer({index: 17}, {});
85
+ const imageCache = new ImageCache(SAMPLE_BOOK);
86
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
51
87
  pc.update({ reduce: null });
52
88
  expect(pc.$img).toBeNull();
53
89
  });
54
90
 
55
- test('does not set background image if already loaded', () => {
56
- const fakeImageCache = {
57
- imageLoaded: () => true,
58
- image: () => $('<img/>'),
59
- };
60
- const pc = new PageContainer({index: 12}, {imageCache: fakeImageCache});
61
- pc.update({ reduce: 7 });
62
- expect(pc.$img[0].style.background).toBe('');
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);
63
100
  });
64
101
 
65
- test('removes image between updates only if changed', () => {
66
- const fakeImageCache = {
67
- imageLoaded: () => true,
68
- image: (index, reduce) => $(`<img src="page${index}-${reduce}.jpg" />`),
69
- };
70
- const pc = new PageContainer({index: 12}, {imageCache: fakeImageCache});
71
- pc.update({ reduce: 7 });
72
- const $im1 = pc.$img;
73
- pc.update({ reduce: 7 });
74
- expect(pc.$img).toBe($im1);
75
- pc.update({ reduce: 16 });
76
- expect(pc.$img).not.toBe($im1);
77
- expect($im1.parent().length).toBe(0);
78
- });
79
-
80
- test('adds/removes loading indicators while loading', () => {
81
- const fakeImageCache = {
82
- imageLoaded: () => false,
83
- image: () => $('<img/>'),
84
- getBestLoadedReduce: () => undefined,
85
- };
86
- const pc = new PageContainer({index: 12}, {imageCache: fakeImageCache, loadingImage: 'loading.gif'});
87
- pc.update({ reduce: 7 });
88
- expect(pc.$container.hasClass('BRpageloading')).toBe(true);
89
- // See https://github.com/jsdom/jsdom/issues/3169
90
- // expect(pc.$img.css('background')).toBeTruthy();
91
- // expect(pc.$img.css('background').includes('loading.gif')).toBe(true);
92
- // expect(pc.$img.css('background').includes(',')).toBe(false);
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});
93
116
 
94
- pc.$img.trigger('loadend');
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);
95
135
  expect(pc.$container.hasClass('BRpageloading')).toBe(false);
96
- expect(pc.$img.css('background')).toBeFalsy();
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);
97
143
  });
98
144
 
99
145
  test('shows lower res image while loading if one available', () => {
100
- const fakeImageCache = {
101
- imageLoaded: () => false,
102
- image: () => $('<img/>'),
103
- getBestLoadedReduce: () => 3,
104
- };
105
- const fakePage = {
106
- index: 12,
107
- getURI: () => 'page12.jpg',
108
- };
109
- const pc = new PageContainer(fakePage, {imageCache: fakeImageCache, loadingImage: 'loading.gif'});
146
+ const imageCache = new ImageCache(SAMPLE_BOOK);
147
+ const pc = new PageContainer(SAMPLE_BOOK.getPage(3), {imageCache});
110
148
  pc.update({ reduce: 7 });
111
- // See https://github.com/jsdom/jsdom/issues/3169
112
- // expect(pc.$img.css('background').includes('page12.jpg')).toBe(true);
113
- pc.$img.trigger('loadend');
114
- expect(pc.$img.css('background')).toBeFalsy();
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');
115
156
  });
116
157
  });
117
158
 
@@ -10,6 +10,7 @@ import {
10
10
  escapeRegExp,
11
11
  getActiveElement,
12
12
  isInputActive,
13
+ parseAnimationSpeed,
13
14
  poll,
14
15
  polyfillCustomEvent,
15
16
  PolyfilledCustomEvent,
@@ -227,3 +228,23 @@ describe('escapeRegex', () => {
227
228
  expect(escapeRegExp('https://example.com')).toBe('https://example\\.com');
228
229
  });
229
230
  });
231
+
232
+ describe('parseAnimationSpeed', () => {
233
+ test('Parses numbers', () => {
234
+ expect(parseAnimationSpeed(100)).toBe(100);
235
+ expect(parseAnimationSpeed(0)).toBe(0);
236
+ expect(parseAnimationSpeed(1000)).toBe(1000);
237
+ });
238
+
239
+ test('Parses strings', () => {
240
+ expect(parseAnimationSpeed('slow')).toBe(600);
241
+ expect(parseAnimationSpeed('fast')).toBe(200);
242
+ expect(parseAnimationSpeed('100')).toBe(100);
243
+ });
244
+
245
+ test('Handles invalid input', () => {
246
+ expect(parseAnimationSpeed('foo')).toBeFalsy();
247
+ expect(parseAnimationSpeed('')).toBeFalsy();
248
+ expect(parseAnimationSpeed(null)).toBeFalsy();
249
+ });
250
+ });
@@ -3,6 +3,7 @@ import BookReader, {_modeStringToNumber} from '@/src/BookReader.js';
3
3
  import '@/src/plugins/plugin.resume.js';
4
4
  import '@/src/plugins/url/plugin.url.js';
5
5
 
6
+ /** @type {import('@/src/BookReader.js').default} */
6
7
  let br;
7
8
  beforeAll(() => {
8
9
  document.body.innerHTML = '<div id="BookReader">';
@@ -33,35 +34,35 @@ test('has registered fullscreen toggle event', () => {
33
34
  });
34
35
 
35
36
  test('checks cookie when initParams called', () => {
36
- br.getResumeValue = jest.fn(() => 15);
37
+ br._plugins.resume.getResumeValue = jest.fn(() => 15);
37
38
  br.urlReadFragment = jest.fn(() => '');
38
39
 
39
40
  const params = br.initParams();
40
- expect(br.getResumeValue).toHaveBeenCalledTimes(1);
41
+ expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
41
42
  expect(params.init).toBe(true);
42
43
  expect(params.index).toBe(15);
43
44
  expect(params.fragmentChange).toBe(true);
44
45
  });
45
46
 
46
47
  test('does not check cookie when initParams called', () => {
47
- br.getResumeValue = jest.fn(() => null);
48
+ br._plugins.resume.getResumeValue = jest.fn(() => null);
48
49
  br.urlReadFragment = jest.fn(() => '');
49
- br.options.enablePageResume = false;
50
+ br.options.plugins.resume.enabled = false;
50
51
 
51
52
  const params = br.initParams();
52
- expect(br.getResumeValue).toHaveBeenCalledTimes(0);
53
+ expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(0);
53
54
  expect(params.init).toBe(true);
54
55
  expect(params.index).toBe(0);
55
56
  expect(params.fragmentChange).toBe(false);
56
57
  });
57
58
 
58
59
  test('gets index from fragment when both fragment and cookie when InitParams called', () => {
59
- br.getResumeValue = jest.fn(() => 15);
60
+ br._plugins.resume.getResumeValue = jest.fn(() => 15);
60
61
  br.urlReadFragment = jest.fn(() => 'page/n4');
61
- br.options.enablePageResume = true;
62
+ br.options.plugins.resume.enabled = true;
62
63
 
63
64
  const params = br.initParams();
64
- expect(br.getResumeValue).toHaveBeenCalledTimes(1);
65
+ expect(br._plugins.resume.getResumeValue).toHaveBeenCalledTimes(1);
65
66
  expect(params.init).toBe(true);
66
67
  expect(params.index).toBe(4);
67
68
  expect(params.fragmentChange).toBe(true);
@@ -91,7 +92,7 @@ test('calls switchMode with init option when init called', () => {
91
92
  });
92
93
 
93
94
  test('has suppressFragmentChange true when init with no input', () => {
94
- br.getResumeValue = jest.fn(() => null);
95
+ br._plugins.resume.getResumeValue = jest.fn(() => null);
95
96
  br.urlReadFragment = jest.fn(() => '');
96
97
  br.urlReadHashFragment = jest.fn(() => '');
97
98
  br.switchMode = jest.fn();
@@ -102,7 +103,7 @@ test('has suppressFragmentChange true when init with no input', () => {
102
103
  });
103
104
 
104
105
  test('has suppressFragmentChange false when init with cookie', () => {
105
- br.getResumeValue = jest.fn(() => 5);
106
+ br._plugins.resume.getResumeValue = jest.fn(() => 5);
106
107
  br.urlReadFragment = jest.fn(() => '');
107
108
  br.switchMode = jest.fn();
108
109
 
@@ -112,7 +113,7 @@ test('has suppressFragmentChange false when init with cookie', () => {
112
113
  });
113
114
 
114
115
  test('has suppressFragmentChange false when init with fragment', () => {
115
- br.getResumeValue = jest.fn(() => null);
116
+ br._plugins.resume.getResumeValue = jest.fn(() => null);
116
117
  br.urlReadFragment = jest.fn(() => 'mode/1up');
117
118
  br.switchMode = jest.fn();
118
119
 
@@ -122,7 +123,7 @@ test('has suppressFragmentChange false when init with fragment', () => {
122
123
  });
123
124
 
124
125
  test('has suppressFragmentChange false when init with hash fragment', () => {
125
- br.getResumeValue = jest.fn(() => null);
126
+ br._plugins.resume.getResumeValue = jest.fn(() => null);
126
127
  br.urlReadFragment = jest.fn(() => '');
127
128
  br.urlReadHashFragment = jest.fn(() => 'mode/1up');
128
129
  br.switchMode = jest.fn();
@@ -1,23 +1,20 @@
1
1
  import sinon from 'sinon';
2
- import BookReader from '@/src/BookReader.js';
3
- import '@/src/plugins/plugin.archive_analytics.js';
4
-
5
- describe('archiveAnalyticsSendEvent', () => {
6
- const sendEvent = BookReader.prototype.archiveAnalyticsSendEvent;
2
+ import {ArchiveAnalyticsPlugin} from '@/src/plugins/plugin.archive_analytics.js';
7
3
 
4
+ describe('sendEvent', () => {
8
5
  test('logs if debug set to true', () => {
9
6
  const stub = sinon.stub(console, 'log');
10
- const FAKE_BR = { options: { enableArchiveAnalytics: true, debugArchiveAnaltyics: true }};
11
- sendEvent.call(FAKE_BR);
7
+ const p = new ArchiveAnalyticsPlugin({});
8
+ p.setup({ debug: true });
9
+ p.sendEvent();
12
10
  expect(stub.callCount).toBe(1);
13
11
  stub.restore();
14
12
  });
15
13
 
16
14
  test('Does not error if window.archive_analytics is undefined', () => {
17
- const spy = sinon.spy(sendEvent);
18
- const FAKE_BR = { options: { enableArchiveAnalytics: true }};
19
- spy.call(FAKE_BR);
15
+ const p = new ArchiveAnalyticsPlugin({});
16
+ const spy = sinon.spy(p.sendEvent);
17
+ p.sendEvent();
20
18
  expect(spy.threw()).toBe(false);
21
19
  });
22
20
  });
23
-
@@ -2,12 +2,11 @@
2
2
  import BookReader from '@/src/BookReader.js';
3
3
  import '@/src/plugins/plugin.autoplay.js';
4
4
 
5
-
5
+ /** @type {BookReader} */
6
6
  let br;
7
7
  beforeEach(() => {
8
8
  document.body.innerHTML = '<div id="BookReader">';
9
9
  br = new BookReader();
10
- br.init();
11
10
  });
12
11
 
13
12
  afterEach(() => {
@@ -15,34 +14,22 @@ afterEach(() => {
15
14
  });
16
15
 
17
16
  describe('Plugin: Menu Toggle', () => {
18
- test('has option flag', () => {
19
- expect(BookReader.defaultOptions.enableAutoPlayPlugin).toEqual(true);
20
- });
21
- test('has added BR property: autoTimer', () => {
22
- expect(br).toHaveProperty('autoTimer');
23
- expect(br.autoTimer).toEqual(null);
24
- });
25
- test('has added BR property: flipDelay', () => {
26
- expect(br).toHaveProperty('flipDelay');
27
- expect(br.flipDelay).toBeTruthy();
28
- expect(br.flipDelay).toBeGreaterThan(1);
29
- });
30
17
  test('autoplay does not start when BookReaderInitializes', () => {
31
- br.autoToggle = jest.fn();
18
+ br._plugins.autoplay.toggle = jest.fn();
32
19
  br.init();
33
- expect(br.autoToggle).toHaveBeenCalledTimes(0);
20
+ expect(br._plugins.autoplay.toggle).toHaveBeenCalledTimes(0);
34
21
  });
35
22
  test('autoplay will run without `flipSpeed` parameters', () => {
36
- const initialAutoTimer = br.autoTimer;
23
+ const initialTimer = br._plugins.autoplay.timer;
37
24
  br.next = jest.fn();
38
- br.autoStop = jest.fn();
25
+ br._plugins.autoplay.stop = jest.fn();
39
26
  br.init();
40
- br.autoToggle();
27
+ br._plugins.autoplay.toggle();
41
28
  // internally referenced functions that fire
42
29
  expect(br.next).toHaveBeenCalledTimes(1);
43
30
 
44
- expect(initialAutoTimer).toBeFalsy();
45
- // br.autoTimer changes when autoToggle turns on
46
- expect(br.autoTimer).toBeTruthy();
31
+ expect(initialTimer).toBeFalsy();
32
+ // timer changes when autoplay turns on
33
+ expect(br._plugins.autoplay.timer).toBeTruthy();
47
34
  });
48
35
  });
@@ -3,7 +3,9 @@ import '@/src/plugins/plugin.resume.js';
3
3
 
4
4
  import sinon from 'sinon';
5
5
  import * as docCookies from '@/src/util/docCookies.js';
6
+ import { ResumePlugin } from '@/src/plugins/plugin.resume.js';
6
7
 
8
+ /** @type {import('@/src/BookReader.js').default} */
7
9
  let br;
8
10
  beforeAll(() => {
9
11
  document.body.innerHTML = '<div id="BookReader">';
@@ -16,21 +18,6 @@ afterEach(() => {
16
18
  sinon.restore();
17
19
  });
18
20
 
19
- describe('Plugin: Remember Current Page in Cookies', () => {
20
- test('has default option flag', () => {
21
- expect(BookReader.defaultOptions.enablePageResume).toEqual(true);
22
- expect(BookReader.defaultOptions.resumeCookiePath).toEqual(null);
23
- });
24
-
25
- test('has added BR property: getResumeValue', () => {
26
- expect(br).toHaveProperty('getResumeValue');
27
- });
28
-
29
- test('has added BR property: updateResumeValue', () => {
30
- expect(br).toHaveProperty('updateResumeValue');
31
- });
32
- });
33
-
34
21
  describe('updateResumeValue', () => {
35
22
  /* Mark 2020-05-02
36
23
  Skipping while confirming with Neeraj
@@ -42,57 +29,57 @@ describe('updateResumeValue', () => {
42
29
  In this branch .toHaveBeenCalledTimes() === 1
43
30
  */
44
31
  test.skip('starts when BookReaderInit is called', () => {
45
- br.updateResumeValue = jest.fn();
32
+ br._plugins.resume.updateResumeValue = jest.fn();
46
33
  br.init();
47
- expect(br.updateResumeValue).toHaveBeenCalledTimes(2);
34
+ expect(br._plugins.resume.updateResumeValue).toHaveBeenCalledTimes(2);
48
35
  });
49
36
 
50
37
  test('handles cookieName=null', () => {
51
- const { updateResumeValue } = BookReader.prototype;
38
+ const p = new ResumePlugin(null);
39
+ p.setup({ cookiePath: '/details/goody' });
52
40
  const setItemSpy = sinon.spy(docCookies, 'setItem');
53
- const fakeBr = { options: { resumeCookiePath: '/details/goody' } };
54
41
 
55
- updateResumeValue.call(fakeBr, 16);
42
+ p.updateResumeValue(16);
56
43
  expect(setItemSpy.callCount).toBe(1);
57
44
  expect(setItemSpy.args[0].slice(0, 2)).toEqual(['br-resume', 16]);
58
45
  expect(setItemSpy.args[0][3]).toEqual('/details/goody');
59
46
  });
60
47
 
61
- test('handles resumeCookiePath not set', () => {
48
+ test('handles cookiePath not set', () => {
62
49
  const setItemSpy = sinon.spy(docCookies, 'setItem');
63
50
  // Save function
64
- const saveFn = br.getCookiePath;
65
- br.getCookiePath = jest.fn(() => '/details/foo');
66
- br.updateResumeValue(16);
51
+ const saveFn = br._plugins.resume.getCookiePath;
52
+ br._plugins.resume.getCookiePath = jest.fn(() => '/details/foo');
53
+ br._plugins.resume.updateResumeValue(16);
67
54
  expect(setItemSpy.args[0][3]).toEqual('/details/foo');
68
55
  // Restore function
69
- br.getCookiePath = saveFn;
56
+ br._plugins.resume.getCookiePath = saveFn;
70
57
  });
71
58
 
72
59
  test('handles cookie path from URL with decoration', () => {
73
60
  const complexPathWithPage = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy/page/n1/mode/2up';
74
61
  const complexPath = '/details/2008ELMValidityStudyFinalReportRevised/Executive%20Summary%20for%20the%20EPT%26ELM%20Validity%20Studie_20100603%20-%20Copy';
75
- expect(br.getCookiePath(complexPathWithPage))
62
+ expect(br._plugins.resume.getCookiePath(complexPathWithPage))
76
63
  .toEqual(complexPath);
77
64
 
78
- expect(br.getCookiePath('/details/item/mode/1up'))
65
+ expect(br._plugins.resume.getCookiePath('/details/item/mode/1up'))
79
66
  .toEqual('/details/item');
80
67
 
81
- expect(br.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'))
82
69
  .toEqual('/details/item/inside/a/long/path/model/is/used');
83
70
 
84
- expect(br.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'))
85
72
  .toEqual('/details/item/inside/a/long/path');
86
73
  });
87
74
 
88
75
  test('handles cookie path from URL with no decoration', () => {
89
- expect(br.getCookiePath('/details/item'))
76
+ expect(br._plugins.resume.getCookiePath('/details/item'))
90
77
  .toEqual('/details/item');
91
78
 
92
- expect(br.getCookiePath('/details/item/'))
79
+ expect(br._plugins.resume.getCookiePath('/details/item/'))
93
80
  .toEqual('/details/item/');
94
81
 
95
- expect(br.getCookiePath('/details/item/almost/any/kind/of/long/path'))
82
+ expect(br._plugins.resume.getCookiePath('/details/item/almost/any/kind/of/long/path'))
96
83
  .toEqual('/details/item/almost/any/kind/of/long/path');
97
84
  });
98
85
  });