@internetarchive/bookreader 5.0.0-36 → 5.0.0-39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (280) hide show
  1. package/.github/workflows/node.js.yml +69 -7
  2. package/.github/workflows/npm-publish.yml +2 -16
  3. package/BookReader/BookReader.css +8 -0
  4. package/BookReader/BookReader.js +1 -1
  5. package/BookReader/BookReader.js.LICENSE.txt +8 -29
  6. package/BookReader/BookReader.js.map +1 -1
  7. package/BookReader/ia-bookreader-bundle.js +144 -119
  8. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +15 -12
  9. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  10. package/BookReader/icons/magnify-minus.svg +1 -1
  11. package/BookReader/icons/magnify-plus.svg +1 -1
  12. package/BookReader/plugins/plugin.autoplay.js +1 -1
  13. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  14. package/BookReader/plugins/plugin.chapters.js +1 -1
  15. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  16. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  17. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  18. package/BookReader/plugins/plugin.resume.js +1 -1
  19. package/BookReader/plugins/plugin.resume.js.map +1 -1
  20. package/BookReader/plugins/plugin.search.js +1 -1
  21. package/BookReader/plugins/plugin.search.js.map +1 -1
  22. package/BookReader/plugins/plugin.text_selection.js +1 -1
  23. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  24. package/BookReader/plugins/plugin.tts.js +1 -1
  25. package/BookReader/plugins/plugin.tts.js.map +1 -1
  26. package/BookReader/plugins/plugin.url.js +1 -1
  27. package/BookReader/plugins/plugin.url.js.map +1 -1
  28. package/CHANGELOG.md +26 -0
  29. package/README.md +14 -1
  30. package/codecov.yml +6 -0
  31. package/package.json +30 -33
  32. package/renovate.json +43 -0
  33. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  34. package/src/BookNavigator/assets/button-base.js +1 -1
  35. package/src/BookNavigator/assets/ia-logo.js +1 -1
  36. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  37. package/src/BookNavigator/assets/icon_close.js +1 -1
  38. package/src/BookNavigator/assets/icon_sort_asc.js +1 -1
  39. package/src/BookNavigator/assets/icon_sort_desc.js +1 -1
  40. package/src/BookNavigator/assets/icon_sort_neutral.js +1 -1
  41. package/src/BookNavigator/assets/icon_volumes.js +1 -1
  42. package/src/BookNavigator/book-navigator.js +1 -2
  43. package/src/BookNavigator/bookmarks/bookmark-button.js +1 -1
  44. package/src/BookNavigator/bookmarks/bookmark-edit.js +2 -3
  45. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  46. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +1 -1
  47. package/src/BookNavigator/bookmarks/bookmarks-provider.js +1 -1
  48. package/src/BookNavigator/bookmarks/ia-bookmarks.js +4 -7
  49. package/src/BookNavigator/delete-modal-actions.js +1 -1
  50. package/src/BookNavigator/downloads/downloads-provider.js +1 -1
  51. package/src/BookNavigator/downloads/downloads.js +1 -2
  52. package/src/BookNavigator/search/a-search-result.js +2 -3
  53. package/src/BookNavigator/search/search-provider.js +1 -2
  54. package/src/BookNavigator/search/search-results.js +1 -2
  55. package/src/BookNavigator/sharing.js +1 -1
  56. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +1 -1
  57. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  58. package/src/BookNavigator/volumes/volumes-provider.js +1 -1
  59. package/src/BookNavigator/volumes/volumes.js +2 -3
  60. package/src/BookReader/Mode1Up.js +2 -1
  61. package/src/BookReader/Mode1UpLit.js +10 -3
  62. package/src/BookReader/Mode2Up.js +11 -0
  63. package/src/BookReader/ModeSmoothZoom.js +2 -0
  64. package/src/BookReader/PageContainer.js +10 -4
  65. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  66. package/src/BookReader.js +4 -2
  67. package/src/assets/icons/magnify-minus.svg +3 -7
  68. package/src/assets/icons/magnify-plus.svg +3 -7
  69. package/src/css/_TextSelection.scss +13 -0
  70. package/src/ia-bookreader/ia-bookreader.js +1 -1
  71. package/src/plugins/plugin.chapters.js +11 -15
  72. package/src/plugins/plugin.text_selection.js +9 -10
  73. package/src/plugins/search/plugin.search.js +8 -18
  74. package/src/plugins/search/view.js +2 -0
  75. package/src/plugins/tts/AbstractTTSEngine.js +9 -4
  76. package/src/plugins/tts/FestivalTTSEngine.js +10 -11
  77. package/src/plugins/tts/PageChunk.js +11 -20
  78. package/src/plugins/tts/WebTTSEngine.js +22 -26
  79. package/tests/e2e/base.test.js +4 -5
  80. package/tests/e2e/helpers/desktopSearch.js +13 -12
  81. package/tests/e2e/models/Navigation.js +12 -3
  82. package/tests/e2e/rightToLeft.test.js +1 -1
  83. package/tests/e2e/viewmode.test.js +37 -31
  84. package/tests/jest/BookReader/Mode1UpLit.test.js +2 -1
  85. package/tests/jest/BookReader/PageContainer.test.js +5 -4
  86. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  87. package/tests/jest/plugins/plugin.text_selection.test.js +25 -23
  88. package/tests/jest/plugins/search/plugin.search.test.js +12 -20
  89. package/tests/jest/plugins/tts/AbstractTTSEngine.test.js +3 -3
  90. package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +2 -2
  91. package/tests/karma/BookNavigator/downloads/downloads.test.js +1 -1
  92. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +3 -3
  93. package/webpack.config.js +1 -1
  94. package/.github/dependabot.yml +0 -8
  95. package/.husky/_/husky.sh +0 -30
  96. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  97. package/stat/BookNavigator/BookModel.js +0 -14
  98. package/stat/BookNavigator/BookNavigator.js +0 -482
  99. package/stat/BookNavigator/assets/bookmark-colors.js +0 -15
  100. package/stat/BookNavigator/assets/button-base.js +0 -61
  101. package/stat/BookNavigator/assets/ia-logo.js +0 -17
  102. package/stat/BookNavigator/assets/icon_checkmark.js +0 -6
  103. package/stat/BookNavigator/assets/icon_close.js +0 -3
  104. package/stat/BookNavigator/assets/icon_sort_asc.js +0 -5
  105. package/stat/BookNavigator/assets/icon_sort_desc.js +0 -5
  106. package/stat/BookNavigator/assets/icon_sort_neutral.js +0 -5
  107. package/stat/BookNavigator/assets/icon_volumes.js +0 -11
  108. package/stat/BookNavigator/bookmarks/bookmark-button.js +0 -64
  109. package/stat/BookNavigator/bookmarks/bookmark-edit.js +0 -215
  110. package/stat/BookNavigator/bookmarks/bookmarks-list.js +0 -285
  111. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -28
  112. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +0 -56
  113. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +0 -523
  114. package/stat/BookNavigator/br-fullscreen-mgr.js +0 -82
  115. package/stat/BookNavigator/delete-modal-actions.js +0 -49
  116. package/stat/BookNavigator/downloads/downloads-provider.js +0 -72
  117. package/stat/BookNavigator/downloads/downloads.js +0 -139
  118. package/stat/BookNavigator/provider-config.js +0 -0
  119. package/stat/BookNavigator/search/a-search-result.js +0 -55
  120. package/stat/BookNavigator/search/search-provider.js +0 -180
  121. package/stat/BookNavigator/search/search-results.js +0 -360
  122. package/stat/BookNavigator/sharing.js +0 -31
  123. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -94
  124. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +0 -280
  125. package/stat/BookNavigator/volumes/volumes-provider.js +0 -83
  126. package/stat/BookNavigator/volumes/volumes.js +0 -178
  127. package/stat/BookReader/BookModel.js +0 -518
  128. package/stat/BookReader/DebugConsole.js +0 -54
  129. package/stat/BookReader/DragScrollable.js +0 -233
  130. package/stat/BookReader/ImageCache.js +0 -116
  131. package/stat/BookReader/Mode1Up.js +0 -102
  132. package/stat/BookReader/Mode1UpLit.js +0 -434
  133. package/stat/BookReader/Mode2Up.js +0 -1372
  134. package/stat/BookReader/ModeSmoothZoom.js +0 -177
  135. package/stat/BookReader/ModeThumb.js +0 -344
  136. package/stat/BookReader/Navbar/Navbar.js +0 -310
  137. package/stat/BookReader/PageContainer.js +0 -120
  138. package/stat/BookReader/ReduceSet.js +0 -26
  139. package/stat/BookReader/Toolbar/Toolbar.js +0 -384
  140. package/stat/BookReader/events.js +0 -20
  141. package/stat/BookReader/options.js +0 -324
  142. package/stat/BookReader/utils/HTMLDimensionsCacher.js +0 -44
  143. package/stat/BookReader/utils/classes.js +0 -36
  144. package/stat/BookReader/utils.js +0 -240
  145. package/stat/BookReader.js +0 -2550
  146. package/stat/BookReaderComponent/BookReaderComponent.js +0 -117
  147. package/stat/assets/icons/1up.svg +0 -12
  148. package/stat/assets/icons/2up.svg +0 -15
  149. package/stat/assets/icons/advance.svg +0 -26
  150. package/stat/assets/icons/chevron-right.svg +0 -1
  151. package/stat/assets/icons/close-circle-dark.svg +0 -1
  152. package/stat/assets/icons/close-circle.svg +0 -1
  153. package/stat/assets/icons/fullscreen.svg +0 -17
  154. package/stat/assets/icons/fullscreen_exit.svg +0 -17
  155. package/stat/assets/icons/hamburger.svg +0 -15
  156. package/stat/assets/icons/left-arrow.svg +0 -12
  157. package/stat/assets/icons/magnify-minus.svg +0 -16
  158. package/stat/assets/icons/magnify-plus.svg +0 -17
  159. package/stat/assets/icons/magnify.svg +0 -15
  160. package/stat/assets/icons/pause.svg +0 -23
  161. package/stat/assets/icons/play.svg +0 -22
  162. package/stat/assets/icons/playback-speed.svg +0 -34
  163. package/stat/assets/icons/read-aloud.svg +0 -22
  164. package/stat/assets/icons/review.svg +0 -22
  165. package/stat/assets/icons/thumbnails.svg +0 -17
  166. package/stat/assets/icons/voice.svg +0 -1
  167. package/stat/assets/icons/volume-full.svg +0 -22
  168. package/stat/assets/images/BRicons.png +0 -0
  169. package/stat/assets/images/BRicons.svg +0 -94
  170. package/stat/assets/images/BRicons_ia.png +0 -0
  171. package/stat/assets/images/back_pages.png +0 -0
  172. package/stat/assets/images/book_bottom_icon.png +0 -0
  173. package/stat/assets/images/book_down_icon.png +0 -0
  174. package/stat/assets/images/book_left_icon.png +0 -0
  175. package/stat/assets/images/book_leftmost_icon.png +0 -0
  176. package/stat/assets/images/book_right_icon.png +0 -0
  177. package/stat/assets/images/book_rightmost_icon.png +0 -0
  178. package/stat/assets/images/book_top_icon.png +0 -0
  179. package/stat/assets/images/book_up_icon.png +0 -0
  180. package/stat/assets/images/books_graphic.svg +0 -177
  181. package/stat/assets/images/booksplit.png +0 -0
  182. package/stat/assets/images/control_pause_icon.png +0 -0
  183. package/stat/assets/images/control_play_icon.png +0 -0
  184. package/stat/assets/images/embed_icon.png +0 -0
  185. package/stat/assets/images/icon-home-ia.png +0 -0
  186. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  187. package/stat/assets/images/icon_alert-xs.png +0 -0
  188. package/stat/assets/images/icon_book.svg +0 -12
  189. package/stat/assets/images/icon_bookmark.svg +0 -12
  190. package/stat/assets/images/icon_close-pop.png +0 -0
  191. package/stat/assets/images/icon_download.png +0 -0
  192. package/stat/assets/images/icon_gear.svg +0 -14
  193. package/stat/assets/images/icon_hamburger.svg +0 -20
  194. package/stat/assets/images/icon_home.png +0 -0
  195. package/stat/assets/images/icon_home.svg +0 -21
  196. package/stat/assets/images/icon_home_ia.png +0 -0
  197. package/stat/assets/images/icon_indicator.png +0 -0
  198. package/stat/assets/images/icon_info.svg +0 -11
  199. package/stat/assets/images/icon_one_page.svg +0 -8
  200. package/stat/assets/images/icon_pause.svg +0 -1
  201. package/stat/assets/images/icon_play.svg +0 -1
  202. package/stat/assets/images/icon_playback-rate.svg +0 -15
  203. package/stat/assets/images/icon_return.png +0 -0
  204. package/stat/assets/images/icon_search_button.svg +0 -8
  205. package/stat/assets/images/icon_share.svg +0 -9
  206. package/stat/assets/images/icon_skip-ahead.svg +0 -6
  207. package/stat/assets/images/icon_skip-back.svg +0 -13
  208. package/stat/assets/images/icon_speaker.svg +0 -18
  209. package/stat/assets/images/icon_speaker_open.svg +0 -10
  210. package/stat/assets/images/icon_thumbnails.svg +0 -12
  211. package/stat/assets/images/icon_toc.svg +0 -5
  212. package/stat/assets/images/icon_two_pages.svg +0 -9
  213. package/stat/assets/images/icon_zoomer.png +0 -0
  214. package/stat/assets/images/loading.gif +0 -0
  215. package/stat/assets/images/logo_icon.png +0 -0
  216. package/stat/assets/images/marker_chap-off.png +0 -0
  217. package/stat/assets/images/marker_chap-off.svg +0 -11
  218. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  219. package/stat/assets/images/marker_chap-on.png +0 -0
  220. package/stat/assets/images/marker_chap-on.svg +0 -11
  221. package/stat/assets/images/marker_srch-on.svg +0 -11
  222. package/stat/assets/images/marker_srchchap-off.png +0 -0
  223. package/stat/assets/images/marker_srchchap-on.png +0 -0
  224. package/stat/assets/images/nav_control-dn.png +0 -0
  225. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  226. package/stat/assets/images/nav_control-up.png +0 -0
  227. package/stat/assets/images/nav_control-up_ia.png +0 -0
  228. package/stat/assets/images/nav_control.png +0 -0
  229. package/stat/assets/images/one_page_mode_icon.png +0 -0
  230. package/stat/assets/images/paper-badge.png +0 -0
  231. package/stat/assets/images/print_icon.png +0 -0
  232. package/stat/assets/images/progressbar.gif +0 -0
  233. package/stat/assets/images/right_edges.png +0 -0
  234. package/stat/assets/images/slider.png +0 -0
  235. package/stat/assets/images/slider_ia.png +0 -0
  236. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  237. package/stat/assets/images/transparent.png +0 -0
  238. package/stat/assets/images/two_page_mode_icon.png +0 -0
  239. package/stat/assets/images/zoom_in_icon.png +0 -0
  240. package/stat/assets/images/zoom_out_icon.png +0 -0
  241. package/stat/css/BookReader.scss +0 -89
  242. package/stat/css/_BRBookmarks.scss +0 -29
  243. package/stat/css/_BRComponent.scss +0 -13
  244. package/stat/css/_BRfloat.scss +0 -197
  245. package/stat/css/_BRicon.scss +0 -48
  246. package/stat/css/_BRmain.scss +0 -251
  247. package/stat/css/_BRnav.scss +0 -359
  248. package/stat/css/_BRpages.scss +0 -139
  249. package/stat/css/_BRsearch.scss +0 -226
  250. package/stat/css/_BRtoolbar.scss +0 -84
  251. package/stat/css/_BRvendor.scss +0 -5
  252. package/stat/css/_MobileNav.scss +0 -194
  253. package/stat/css/_TextSelection.scss +0 -32
  254. package/stat/css/_colorbox.scss +0 -52
  255. package/stat/css/_controls.scss +0 -253
  256. package/stat/css/_icons.scss +0 -121
  257. package/stat/jquery-wrapper.js +0 -4
  258. package/stat/plugins/plugin.archive_analytics.js +0 -86
  259. package/stat/plugins/plugin.autoplay.js +0 -129
  260. package/stat/plugins/plugin.chapters.js +0 -248
  261. package/stat/plugins/plugin.iframe.js +0 -48
  262. package/stat/plugins/plugin.mobile_nav.js +0 -288
  263. package/stat/plugins/plugin.resume.js +0 -68
  264. package/stat/plugins/plugin.text_selection.js +0 -291
  265. package/stat/plugins/plugin.url.js +0 -198
  266. package/stat/plugins/plugin.vendor-fullscreen.js +0 -247
  267. package/stat/plugins/search/plugin.search.js +0 -439
  268. package/stat/plugins/search/view.js +0 -439
  269. package/stat/plugins/tts/AbstractTTSEngine.js +0 -249
  270. package/stat/plugins/tts/FestivalTTSEngine.js +0 -169
  271. package/stat/plugins/tts/PageChunk.js +0 -107
  272. package/stat/plugins/tts/PageChunkIterator.js +0 -163
  273. package/stat/plugins/tts/WebTTSEngine.js +0 -357
  274. package/stat/plugins/tts/plugin.tts.js +0 -357
  275. package/stat/plugins/tts/tooltip_dict.js +0 -15
  276. package/stat/plugins/tts/utils.js +0 -91
  277. package/stat/util/browserSniffing.js +0 -30
  278. package/stat/util/debouncer.js +0 -26
  279. package/stat/util/docCookies.js +0 -67
  280. package/stat/util/strings.js +0 -34
@@ -132,7 +132,7 @@ BookReader.prototype._createPageContainer = (function (super_) {
132
132
  * @param {string} term
133
133
  * @param {SearchOptions} overrides
134
134
  */
135
- BookReader.prototype.search = function(term = '', overrides = {}) {
135
+ BookReader.prototype.search = async function(term = '', overrides = {}) {
136
136
  /** @type {SearchOptions} */
137
137
  const defaultOptions = {
138
138
  goToFirstResult: false, /* jump to the first result (default=false) */
@@ -144,6 +144,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
144
144
  };
145
145
  const options = jQuery.extend({}, defaultOptions, overrides);
146
146
  this.suppressFragmentChange = options.suppressFragmentChange;
147
+ this.searchCancelled = false;
147
148
 
148
149
  // strip slashes, since this goes in the url
149
150
  this.searchTerm = term.replace(/\//g, ' ');
@@ -179,13 +180,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
179
180
 
180
181
  const url = `${baseUrl}${paramStr}`;
181
182
 
182
- const cleanup = () => {
183
- this.searchXHR = null;
184
- window.BRSearchInProgress = () => {};
185
- };
186
-
187
183
  const processSearchResults = (searchInsideResults) => {
188
- if (!this.searchXHR) {
184
+ if (this.searchCancelled) {
189
185
  return;
190
186
  }
191
187
  const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
@@ -201,22 +197,15 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
201
197
  ? options.success.call(this, searchInsideResults, options)
202
198
  : this.BRSearchCallback(searchInsideResults, options);
203
199
  }
204
- cleanup();
205
- };
206
-
207
- const beforeSend = (xhr) => {
208
- this.searchXHR = xhr;
209
- window.BRSearchInProgress = processSearchResults;
210
200
  };
211
201
 
212
202
  this.trigger('SearchStarted', { term: this.searchTerm, instance: this });
213
- return $.ajax({
203
+ return processSearchResults(await $.ajax({
214
204
  url: url,
215
205
  dataType: 'jsonp',
216
206
  cache: true,
217
- beforeSend,
218
- jsonpCallback: 'BRSearchInProgress'
219
- }).then(processSearchResults);
207
+ beforeSend: xhr => { this.searchXHR = xhr; },
208
+ }));
220
209
  };
221
210
 
222
211
  /**
@@ -228,8 +217,8 @@ BookReader.prototype._cancelSearch = function () {
228
217
  this.searchView.clearSearchFieldAndResults(false);
229
218
  this.searchTerm = '';
230
219
  this.searchXHR = null;
220
+ this.searchCancelled = true;
231
221
  this.searchResults = [];
232
- window.BRSearchInProgress = () => {};
233
222
  };
234
223
 
235
224
  /**
@@ -237,6 +226,7 @@ BookReader.prototype._cancelSearch = function () {
237
226
  * checks for term & xhr in flight before running
238
227
  */
239
228
  BookReader.prototype.cancelSearchRequest = function () {
229
+ this.searchCancelled = true;
240
230
  if (this.searchXHR !== null) {
241
231
  this._cancelSearch();
242
232
  this.searchView.toggleSearchPending();
@@ -149,10 +149,12 @@ class SearchView {
149
149
  }
150
150
 
151
151
  updateResultsPosition() {
152
+ if (!this.dom.searchNavigation) return;
152
153
  this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
153
154
  }
154
155
 
155
156
  updateSearchNavigationButtons() {
157
+ if (!this.dom.searchNavigation) return;
156
158
  this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
157
159
  this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
158
160
  }
@@ -51,9 +51,7 @@ export default class AbstractTTSEngine {
51
51
  /** @type {SpeechSynthesisVoice} */
52
52
  this.voice = null;
53
53
  // Listen for voice changes (fired by subclasses)
54
- this.events.on('voiceschanged', () => {
55
- this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
56
- });
54
+ this.events.on('voiceschanged', this.updateBestVoice);
57
55
  this.events.trigger('voiceschanged');
58
56
  }
59
57
 
@@ -72,6 +70,10 @@ export default class AbstractTTSEngine {
72
70
  /** @abstract */
73
71
  init() { return null; }
74
72
 
73
+ updateBestVoice = () => {
74
+ this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
75
+ }
76
+
75
77
  /**
76
78
  * @param {number} leafIndex
77
79
  * @param {number} numLeafs total number of leafs in the current book
@@ -134,8 +136,11 @@ export default class AbstractTTSEngine {
134
136
  this.step();
135
137
  }
136
138
 
137
- /** @param {number} newRate */
139
+ /** @param {string} voiceURI */
138
140
  setVoice(voiceURI) {
141
+ // if the user actively selects a voice, don't re-choose best voice anymore
142
+ // MS Edge fires voices changed randomly very often
143
+ this.events.off('voiceschanged', this.updateBestVoice);
139
144
  this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
140
145
  if (this.activeSound) this.activeSound.setVoice(this.voice);
141
146
  }
@@ -91,10 +91,10 @@ export default class FestivalTTSEngine extends AbstractTTSEngine {
91
91
  * See https://stackoverflow.com/questions/12206631/html5-audio-cant-play-through-javascript-unless-triggered-manually-once
92
92
  * @return {PromiseLike}
93
93
  */
94
- iOSCaptureUserIntentHack() {
94
+ async iOSCaptureUserIntentHack() {
95
95
  const sound = soundManager.createSound({ url: SILENCE_1MS[this.audioFormat] });
96
- return new Promise(res => sound.play({onfinish: res}))
97
- .then(() => sound.destruct());
96
+ await new Promise(res => sound.play({onfinish: res}));
97
+ sound.destruct();
98
98
  }
99
99
  }
100
100
 
@@ -122,21 +122,20 @@ class FestivalTTSSound {
122
122
  if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
123
123
  onload();
124
124
  },
125
- onresume: () => {
126
- sleep(25).then(() => {
127
- if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
128
- });
125
+ onresume: async () => {
126
+ await sleep(25);
127
+ if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
129
128
  }
130
129
  });
131
130
  return this.sound.load();
132
131
  }
133
132
 
134
- play() {
135
- return new Promise(res => {
133
+ async play() {
134
+ await new Promise(res => {
136
135
  this._finishResolver = res;
137
136
  this.sound.play({ onfinish: res });
138
- })
139
- .then(() => this.sound.destruct());
137
+ });
138
+ this.sound.destruct();
140
139
  }
141
140
 
142
141
  /** @override */
@@ -21,27 +21,18 @@ export default class PageChunk {
21
21
  * @param {number} leafIndex
22
22
  * @return {Promise<PageChunk[]>}
23
23
  */
24
- static fetch(server, bookPath, leafIndex) {
25
- // jquery's ajax "PromiseLike" implementation is inconsistent with
26
- // modern Promises, so convert it to a full promise (it doesn't forward
27
- // a returned promise to the next handler in the chain, which kind of
28
- // defeats the entire point of using promises to avoid "callback hell")
29
- return new Promise((res, rej) => {
30
- $.ajax({
31
- type: 'GET',
32
- url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,
33
- dataType:'jsonp',
34
- cache: true,
35
- data: {
36
- path: `${bookPath}_djvu.xml`,
37
- page: leafIndex
38
- },
39
- error: rej,
40
- })
41
- .then(chunks => {
42
- res(PageChunk._fromTextWrapperResponse(leafIndex, chunks));
43
- });
24
+ static async fetch(server, bookPath, leafIndex) {
25
+ const chunks = await $.ajax({
26
+ type: 'GET',
27
+ url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,
28
+ dataType:'jsonp',
29
+ cache: true,
30
+ data: {
31
+ path: `${bookPath}_djvu.xml`,
32
+ page: leafIndex
33
+ }
44
34
  });
35
+ return PageChunk._fromTextWrapperResponse(leafIndex, chunks);
45
36
  }
46
37
 
47
38
  /**
@@ -167,7 +167,7 @@ export class WebTTSSound {
167
167
  * left off.
168
168
  * @return {Promise<void>}
169
169
  */
170
- reload() {
170
+ async reload() {
171
171
  // We'll restore the pause state, so copy it here
172
172
  const wasPaused = this.paused;
173
173
  // Use recent event to determine where we'll restart from
@@ -179,14 +179,12 @@ export class WebTTSSound {
179
179
  }
180
180
 
181
181
  // We can't modify the utterance object, so we have to make a new one
182
- return this.stop()
183
- .then(() => {
184
- this.load();
185
- // Instead of playing and immediately pausing, we don't start playing. Note
186
- // this is a requirement because pause doesn't work consistently across
187
- // browsers.
188
- if (!wasPaused) this.play();
189
- });
182
+ await this.stop();
183
+ this.load();
184
+ // Instead of playing and immediately pausing, we don't start playing. Note
185
+ // this is a requirement because pause doesn't work consistently across
186
+ // browsers.
187
+ if (!wasPaused) this.play();
190
188
  }
191
189
 
192
190
  play() {
@@ -222,15 +220,16 @@ export class WebTTSSound {
222
220
  return endPromise;
223
221
  }
224
222
 
225
- finish() {
226
- this.stop().then(() => this.utterance.dispatchEvent(new Event('finish')));
223
+ async finish() {
224
+ await this.stop();
225
+ this.utterance.dispatchEvent(new Event('finish'));
227
226
  }
228
227
 
229
228
  /**
230
229
  * @override
231
230
  * Will fire a pause event unless already paused
232
231
  **/
233
- pause() {
232
+ async pause() {
234
233
  if (this.paused) return;
235
234
 
236
235
  const pausePromise = promisifyEvent(this.utterance, 'pause');
@@ -246,15 +245,14 @@ export class WebTTSSound {
246
245
  if (pauseMightNotFire) {
247
246
  // wait for it just in case
248
247
  const timeoutPromise = sleep(100).then(() => 'timeout');
249
- Promise.race([pausePromise, timeoutPromise])
250
- .then(result => {
251
- // We got our pause event; nothing to do!
252
- if (result != 'timeout') return;
253
-
254
- this.utterance.dispatchEvent(new CustomEvent('pause', this._lastEvents.start));
255
- // if pause might not work, then we'll stop entirely and restart later
256
- if (pauseMightNotWork) this.stop();
257
- });
248
+ const result = await Promise.race([pausePromise, timeoutPromise]);
249
+ // We got our pause event; nothing to do!
250
+ if (result != 'timeout') return;
251
+
252
+ this.utterance.dispatchEvent(new CustomEvent('pause', this._lastEvents.start));
253
+
254
+ // if pause might not work, then we'll stop entirely and restart later
255
+ if (pauseMightNotWork) this.stop();
258
256
  }
259
257
  }
260
258
 
@@ -325,13 +323,11 @@ export class WebTTSSound {
325
323
  // We could do the same as before (but resume+pause instead of pause+resume),
326
324
  // but that means we'd _constantly_ be running in the background. So in that
327
325
  // case, let's just restart the chunk
328
- Promise.race([
326
+ await Promise.race([
329
327
  promisifyEvent(this.utterance, 'resume'),
330
328
  sleep(14000).then(() => 'timeout'),
331
- ])
332
- .then(result => {
333
- result == 'timeout' ? this.reload() : this._chromePausingBugFix();
334
- });
329
+ ]);
330
+ result == 'timeout' ? this.reload() : this._chromePausingBugFix();
335
331
  break;
336
332
  case 'timeout':
337
333
  // We hit Chrome's secret cut off time. Pause/resume
@@ -1,6 +1,6 @@
1
1
  import { runBaseTests } from './helpers/base';
2
2
  import BookReader from './models/BookReader';
3
- // import { runDesktopSearchTests } from './helpers/desktopSearch';
3
+ import { runDesktopSearchTests } from './helpers/desktopSearch';
4
4
  // import { runMobileSearchTests } from './helpers/mobileSearch';
5
5
  import params from './helpers/params';
6
6
 
@@ -22,10 +22,9 @@ ocaids.forEach(ocaid => {
22
22
  runBaseTests(new BookReader());
23
23
 
24
24
 
25
- // Todo: Re-enable when testing side panel
26
- // fixture `Desktop Search Tests for: ${ocaid}`
27
- // .page `${url}`;
28
- // runDesktopSearchTests(new BookReader());
25
+ fixture `Desktop Search Tests for: ${ocaid}`
26
+ .page `${url}`;
27
+ runDesktopSearchTests(new BookReader());
29
28
 
30
29
  // Todo: deprecated, will remove once mmenu is removed.
31
30
  // fixture `Mobile Search Tests for: ${ocaid}`
@@ -19,14 +19,15 @@ export function runDesktopSearchTests(br) {
19
19
  const nav = br.nav;
20
20
 
21
21
  //assuring that the search bar is enabled
22
- await t.expect(nav.desktop.searchBox.visible).ok();
22
+ await t.expect(nav.desktop.searchIcon.visible).ok();
23
+ await t.click(nav.desktop.searchIcon);
23
24
 
24
25
  //testing search for a word found in the book
25
- await t
26
- .selectText(nav.desktop.searchBox.child('.BRsearchInput'))
27
- .pressKey('delete');
28
- await t.typeText(nav.desktop.searchBox.child('.BRsearchInput'), TEST_TEXT_FOUND);
29
- await t.click((nav.desktop.searchBox).child('.BRsearchSubmit'));
26
+ await t.selectText(nav.desktop.searchBox).pressKey('delete');
27
+ // FIXME: Why is it only typing every other letter?!?!
28
+ await t.typeText(nav.desktop.searchBox, TEST_TEXT_FOUND.split('').join('_'));
29
+ await t.pressKey('enter');
30
+
30
31
  await t.expect(nav.desktop.searchPin.exists).ok();
31
32
  await t.expect(nav.desktop.searchPin.child('.BRquery').child('div').exists).ok();
32
33
  await t.expect(nav.desktop.searchPin.child('.BRquery').child('div').innerText).contains(TEST_TEXT_FOUND);
@@ -54,14 +55,14 @@ export function runDesktopSearchTests(br) {
54
55
  const nav = br.nav;
55
56
 
56
57
  //assuring that the search bar is enabled
57
- await t.expect(nav.desktop.searchBox.visible).ok();
58
+ await t.expect(nav.desktop.searchIcon.visible).ok();
59
+ await t.click(nav.desktop.searchIcon);
58
60
 
59
61
  //testing search for a word not found in the book
60
- await t
61
- .selectText(nav.desktop.searchBox.child('.BRsearchInput'))
62
- .pressKey('delete');
63
- await t.typeText(nav.desktop.searchBox.child('.BRsearchInput'), TEST_TEXT_NOT_FOUND);
64
- await t.click((nav.desktop.searchBox).child('.BRsearchSubmit'));
62
+ await t.selectText(nav.desktop.searchBox).pressKey('delete');
63
+ // FIXME: Why is it only typing every other letter?!?!
64
+ await t.typeText(nav.desktop.searchBox, TEST_TEXT_NOT_FOUND.split('').join('_'));
65
+ await t.pressKey('enter');
65
66
  await t.expect(nav.desktop.searchPin.child('.BRquery').child('div').withText(TEST_TEXT_NOT_FOUND).exists).notOk();
66
67
 
67
68
  const getPageUrl = ClientFunction(() => window.location.href.toString());
@@ -6,7 +6,8 @@ export default class Navigation {
6
6
  this.topNavShell = new Selector('.BRtoolbar');
7
7
  this.bottomNavShell = new Selector('.BRfooter');
8
8
  this.mobileMenu = new Selector('.BRmobileMenu');
9
- this.desktop = new DesktopNav(this.bottomNavShell, this.topNavShell);
9
+ this.itemNav = Selector('ia-bookreader').shadowRoot().find('ia-item-navigator').shadowRoot();
10
+ this.desktop = new DesktopNav(this.bottomNavShell, this.itemNav);
10
11
  this.mobile = new MobileNav(this.mobileMenu, this.topNavShell);
11
12
  }
12
13
  }
@@ -17,7 +18,11 @@ export default class Navigation {
17
18
  * @classdesc defines DesktopNav base elements
18
19
  */
19
20
  class DesktopNav {
20
- constructor(bottomToolbar, topToolbar) {
21
+ /**
22
+ * @param {Selector} bottomToolbar
23
+ * @param {Selector} itemNav
24
+ */
25
+ constructor(bottomToolbar, itemNav) {
21
26
  // flipping
22
27
  this.goLeft = bottomToolbar.find('.BRicon.book_left');
23
28
  this.goRight = bottomToolbar.find('.BRicon.book_right');
@@ -35,7 +40,11 @@ class DesktopNav {
35
40
  this.zoomOut = bottomToolbar.find('.BRicon.zoom_out');
36
41
 
37
42
  // search
38
- this.searchBox = topToolbar.find('.BRbooksearch.desktop');
43
+ this.searchIcon = itemNav.find('button.shortcut.search');
44
+ this.searchBox = itemNav
45
+ .find('ia-menu-slider').shadowRoot()
46
+ .find('ia-book-search-results').shadowRoot()
47
+ .find('input[name=query]');
39
48
  this.searchPin = bottomToolbar.find('.BRsearch');
40
49
  this.searchNavigation = bottomToolbar.find('.BRsearch-navigation');
41
50
 
@@ -9,7 +9,7 @@ const ocaids = params.ocaids || [
9
9
  ];
10
10
 
11
11
  ocaids.forEach(ocaid => {
12
- const url = `${params.baseUrl}/BookReaderDemo/demo-internetarchive.html?ocaid=${ocaid}`;
12
+ const url = `${params.getArchiveUrl(ocaid)}`;
13
13
 
14
14
  fixture `Base Tests for right to left book: ${ocaid}`.page `${url}`;
15
15
  runBaseTests(new BookReader({ pageProgression: 'rl' }));
@@ -2,35 +2,41 @@ import { Selector } from 'testcafe';
2
2
  import BookReader from './models/BookReader';
3
3
  import params from './helpers/params';
4
4
 
5
- fixture `Viewmode carousel`.page `${params.baseUrl}/BookReaderDemo/demo-internetarchive.html?ocaid=goody`;
6
-
7
- test('Clicking `view mode` cycles through view modes', async t => {
8
- const { nav } = (new BookReader());
9
-
10
- // viewmode button only appear on mobile devices
11
- await t.resizeWindow(400, 800);
12
- // Flip forward one
13
- await t.pressKey('right');
14
-
15
- // 2up to thumb
16
- await t.click(nav.desktop.viewmode);
17
- const thumbnailContainer = Selector('.BRmodeThumb');
18
- await t.expect(thumbnailContainer.visible).ok();
19
- const thumbImages = thumbnailContainer.find('.BRpageview img');
20
- await t.expect(thumbImages.count).gt(0);
21
-
22
- // thumb to 1up
23
- await t.click(nav.desktop.viewmode);
24
- const onePageViewContainer = Selector('br-mode-1up');
25
- await t.expect(onePageViewContainer.visible).ok();
26
- const onePageImages = onePageViewContainer.find('.BRmode1up .BRpagecontainer');
27
- // we usually pre-fetch the page in question & 1 before/after it
28
- await t.expect(onePageImages.count).gte(3);
29
-
30
- // 1up to 2up
31
- await t.click(nav.desktop.viewmode);
32
- const twoPageContainer = Selector('.BRtwopageview');
33
- await t.expect(twoPageContainer.visible).ok();
34
- const twoPageImages = twoPageContainer.find('img.BRpageimage');
35
- await t.expect(twoPageImages.count).gte(2);
5
+ const ocaids = params.ocaids || ['goody'];
6
+
7
+ ocaids.forEach(ocaid => {
8
+ const url = params.getArchiveUrl(ocaid);
9
+
10
+ fixture `Viewmode carousel`.page `${url}`;
11
+
12
+ test('Clicking `view mode` cycles through view modes', async t => {
13
+ const { nav } = (new BookReader());
14
+
15
+ // viewmode button only appear on mobile devices
16
+ await t.resizeWindow(400, 800);
17
+ // Flip forward one
18
+ await t.pressKey('right');
19
+
20
+ // 2up to thumb
21
+ await t.click(nav.desktop.viewmode);
22
+ const thumbnailContainer = Selector('.BRmodeThumb');
23
+ await t.expect(thumbnailContainer.visible).ok();
24
+ const thumbImages = thumbnailContainer.find('.BRpageview img');
25
+ await t.expect(thumbImages.count).gt(0);
26
+
27
+ // thumb to 1up
28
+ await t.click(nav.desktop.viewmode);
29
+ const onePageViewContainer = Selector('br-mode-1up');
30
+ await t.expect(onePageViewContainer.visible).ok();
31
+ const onePageImages = onePageViewContainer.find('.BRmode1up .BRpagecontainer');
32
+ // we usually pre-fetch the page in question & 1 before/after it
33
+ await t.expect(onePageImages.count).gte(3);
34
+
35
+ // 1up to 2up
36
+ await t.click(nav.desktop.viewmode);
37
+ const twoPageContainer = Selector('.BRtwopageview');
38
+ await t.expect(twoPageContainer.visible).ok();
39
+ const twoPageImages = twoPageContainer.find('img.BRpageimage');
40
+ await t.expect(twoPageImages.count).gte(2);
41
+ });
36
42
  });
@@ -35,7 +35,8 @@ describe('pageTops', () => {
35
35
  const book = new BookModel(br);
36
36
  const mode = new Mode1UpLit(book, br);
37
37
  document.body.appendChild(mode);
38
- await mode.requestUpdate();
38
+ mode.requestUpdate();
39
+ await mode.updateComplete;
39
40
  expect(mode.pageTops).toEqual({});
40
41
  });
41
42
 
@@ -62,17 +62,18 @@ describe('update', () => {
62
62
  expect(pc.$img[0].style.background).toBe('');
63
63
  });
64
64
 
65
- test('removes image between updates', () => {
65
+ test('removes image between updates only if changed', () => {
66
66
  const fakeImageCache = {
67
67
  imageLoaded: () => true,
68
- image: () => $('<img/>'),
68
+ image: (index, reduce) => $(`<img src="page${index}-${reduce}.jpg" />`),
69
69
  };
70
70
  const pc = new PageContainer({index: 12}, {imageCache: fakeImageCache});
71
71
  pc.update({ reduce: 7 });
72
72
  const $im1 = pc.$img;
73
73
  pc.update({ reduce: 7 });
74
- const $im2 = pc.$img;
75
- expect($im1).not.toBe($im2);
74
+ expect(pc.$img).toBe($im1);
75
+ pc.update({ reduce: 16 });
76
+ expect(pc.$img).not.toBe($im1);
76
77
  expect($im1.parent().length).toBe(0);
77
78
  });
78
79
 
@@ -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
+ });
@@ -19,30 +19,32 @@ const FAKE_XML_5COORDS = `<OBJECT data="file://localhost//tmp/derive/goodytwosho
19
19
  const FAKE_XML_EMPTY = '';
20
20
 
21
21
  describe("Generic tests", () => {
22
- let br;
23
- beforeEach(() => {
24
- document.body.innerHTML = '<div id="BookReader">';
25
- br = new BookreaderWithTextSelection({
26
- data: [
27
- [
28
- { width: 800, height: 1200,
29
- uri: '//archive.org/download/BookReader/img/page001.jpg' },
30
- ],
31
- [
32
- { width: 800, height: 1200,
33
- uri: '//archive.org/download/BookReader/img/page002.jpg' },
34
- { width: 800, height: 1200,
35
- uri: '//archive.org/download/BookReader/img/page003.jpg' },
36
- ],
37
- [
38
- { width: 800, height: 1200,
39
- uri: '//archive.org/download/BookReader/img/page004.jpg' },
40
- { width: 800, height: 1200,
41
- uri: '//archive.org/download/BookReader/img/page005.jpg' },
42
- ]
22
+ document.body.innerHTML = '<div id="BookReader">';
23
+ const br = new BookreaderWithTextSelection({
24
+ data: [
25
+ [
26
+ { width: 800, height: 1200,
27
+ uri: '//archive.org/download/BookReader/img/page001.jpg' },
43
28
  ],
44
- });
45
- br.init();
29
+ [
30
+ { width: 800, height: 1200,
31
+ uri: '//archive.org/download/BookReader/img/page002.jpg' },
32
+ { width: 800, height: 1200,
33
+ uri: '//archive.org/download/BookReader/img/page003.jpg' },
34
+ ],
35
+ [
36
+ { width: 800, height: 1200,
37
+ uri: '//archive.org/download/BookReader/img/page004.jpg' },
38
+ { width: 800, height: 1200,
39
+ uri: '//archive.org/download/BookReader/img/page005.jpg' },
40
+ ]
41
+ ],
42
+ });
43
+ br.init();
44
+
45
+ afterEach(() => {
46
+ sinon.restore();
47
+ $('.textSelectionSVG').remove();
46
48
  });
47
49
 
48
50
  test("_createPageContainer overridden function still creates a BRpagecontainer element", () => {