@internetarchive/bookreader 5.0.0-35 → 5.0.0-36

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.
@@ -258,7 +258,7 @@ export class WebTTSSound {
258
258
  }
259
259
  }
260
260
 
261
- resume() {
261
+ async resume() {
262
262
  if (!this.started) {
263
263
  this.play();
264
264
  return;
@@ -278,16 +278,15 @@ export class WebTTSSound {
278
278
  speechSynthesis.resume();
279
279
 
280
280
  if (resumeMightNotFire) {
281
- Promise.race([resumePromise, sleep(100).then(() => 'timeout')])
282
- .then(result => {
283
- if (result != 'timeout') return;
281
+ const result = await Promise.race([resumePromise, sleep(100).then(() => 'timeout')]);
284
282
 
285
- this.utterance.dispatchEvent(new CustomEvent('resume', {}));
286
- if (resumeMightNotWork) {
287
- const reloadPromise = this.reload();
288
- reloadPromise.then(() => this.play());
289
- }
290
- });
283
+ if (result != 'timeout') return;
284
+
285
+ this.utterance.dispatchEvent(new CustomEvent('resume', {}));
286
+ if (resumeMightNotWork) {
287
+ await this.reload();
288
+ this.play();
289
+ }
291
290
  }
292
291
  }
293
292
 
@@ -308,45 +307,41 @@ export class WebTTSSound {
308
307
  * We avoid this (as described here: https://bugs.chromium.org/p/chromium/issues/detail?id=679437#c15 )
309
308
  * by pausing after 14 seconds and ~instantly resuming.
310
309
  */
311
- _chromePausingBugFix() {
310
+ async _chromePausingBugFix() {
312
311
  const timeoutPromise = sleep(14000).then(() => 'timeout');
313
312
  const pausePromise = promisifyEvent(this.utterance, 'pause').then(() => 'paused');
314
313
  const endPromise = promisifyEvent(this.utterance, 'end').then(() => 'ended');
315
- return Promise.race([timeoutPromise, pausePromise, endPromise])
316
- .then(result => {
317
- if (location.toString().indexOf('_debugReadAloud=true') != -1) {
318
- console.log(`CHROME-PAUSE-HACK: ${result}`);
319
- }
320
- switch (result) {
321
- case 'ended':
322
- // audio was stopped/finished; nothing to do
323
- break;
324
- case 'paused':
325
- // audio was paused; wait for resume
326
- // Chrome won't let you resume the audio if 14s have passed 🤷‍
327
- // We could do the same as before (but resume+pause instead of pause+resume),
328
- // but that means we'd _constantly_ be running in the background. So in that
329
- // case, let's just restart the chunk
330
- Promise.race([
331
- promisifyEvent(this.utterance, 'resume'),
332
- sleep(14000).then(() => 'timeout'),
333
- ])
334
- .then(result => {
335
- result == 'timeout' ? this.reload() : this._chromePausingBugFix();
336
- });
337
- break;
338
- case 'timeout':
339
- // We hit Chrome's secret cut off time. Pause/resume
340
- // to be able to keep TTS-ing
341
- speechSynthesis.pause();
342
- sleep(25)
343
- .then(() => {
344
- speechSynthesis.resume();
345
- this._chromePausingBugFix();
346
- });
347
- break;
348
- }
349
- });
314
+ const result = await Promise.race([timeoutPromise, pausePromise, endPromise]);
315
+ if (location.toString().indexOf('_debugReadAloud=true') != -1) {
316
+ console.log(`CHROME-PAUSE-HACK: ${result}`);
317
+ }
318
+ switch (result) {
319
+ case 'ended':
320
+ // audio was stopped/finished; nothing to do
321
+ break;
322
+ case 'paused':
323
+ // audio was paused; wait for resume
324
+ // Chrome won't let you resume the audio if 14s have passed 🤷‍
325
+ // We could do the same as before (but resume+pause instead of pause+resume),
326
+ // but that means we'd _constantly_ be running in the background. So in that
327
+ // case, let's just restart the chunk
328
+ Promise.race([
329
+ promisifyEvent(this.utterance, 'resume'),
330
+ sleep(14000).then(() => 'timeout'),
331
+ ])
332
+ .then(result => {
333
+ result == 'timeout' ? this.reload() : this._chromePausingBugFix();
334
+ });
335
+ break;
336
+ case 'timeout':
337
+ // We hit Chrome's secret cut off time. Pause/resume
338
+ // to be able to keep TTS-ing
339
+ speechSynthesis.pause();
340
+ await sleep(25);
341
+ speechSynthesis.resume();
342
+ this._chromePausingBugFix();
343
+ break;
344
+ }
350
345
  }
351
346
  }
352
347
 
@@ -261,9 +261,7 @@ BookReader.prototype.ttsStop = function () {
261
261
  BookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {
262
262
  await this.ttsMaybeFlipToIndex(chunk.leafIndex);
263
263
  this.ttsHighlightChunk(chunk);
264
- // This appears not to work; ttsMaybeFlipToIndex causes a scroll to the top of
265
- // the active page :/ Disabling cause the extra scroll just adds an odd jitter.
266
- // this.ttsScrollToChunk(chunk);
264
+ this.ttsScrollToChunk(chunk);
267
265
  };
268
266
 
269
267
  /**
@@ -292,10 +290,7 @@ BookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {
292
290
  resolve();
293
291
  } else {
294
292
  this.animationFinishedCallback = resolve;
295
- const mustGoNext = leafIndex > Math.max(this.twoPage.currentIndexR, this.twoPage.currentIndexL);
296
- if (mustGoNext) this.next();
297
- else this.prev();
298
- promise.then(this.ttsMaybeFlipToIndex.bind(this, leafIndex));
293
+ this.jumpToIndex(leafIndex);
299
294
  }
300
295
  }
301
296
 
@@ -329,9 +324,20 @@ BookReader.prototype.ttsHighlightChunk = function(chunk) {
329
324
  * @param {PageChunk} chunk
330
325
  */
331
326
  BookReader.prototype.ttsScrollToChunk = function(chunk) {
332
- if (this.constMode1up != this.mode) return;
333
-
334
- $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`)[0]?.scrollIntoView();
327
+ // It behaves weird if used in thumb mode
328
+ if (this.constModeThumb == this.mode) return;
329
+
330
+ $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({
331
+ // Only vertically center the highlight if we're in 1up or in full screen. In
332
+ // 2up, if we're not fullscreen, the whole body gets scrolled around to try to
333
+ // center the highlight 🙄 See:
334
+ // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
335
+ // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
336
+ // full-width, and covers up the last line of the highlight.
337
+ block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
338
+ inline: 'center',
339
+ behavior: 'smooth',
340
+ });
335
341
  };
336
342
 
337
343
  // ttsRemoveHilites()
@@ -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
 
@@ -21,10 +21,13 @@ ocaids.forEach(ocaid => {
21
21
  fixture `Base Tests for: ${ocaid}`.page `${url}`;
22
22
  runBaseTests(new BookReader());
23
23
 
24
- fixture `Desktop Search Tests for: ${ocaid}`
25
- .page `${url}`;
26
- runDesktopSearchTests(new BookReader());
27
24
 
25
+ // Todo: Re-enable when testing side panel
26
+ // fixture `Desktop Search Tests for: ${ocaid}`
27
+ // .page `${url}`;
28
+ // runDesktopSearchTests(new BookReader());
29
+
30
+ // Todo: deprecated, will remove once mmenu is removed.
28
31
  // fixture `Mobile Search Tests for: ${ocaid}`
29
32
  // .page `${url}`
30
33
  // runMobileSearchTests(new BookReader());
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  class TestParams {
3
3
  baseUrl = process.env.BASE_URL?.replace(/\/+$/, '') ?? 'http://127.0.0.1:8000'
4
- ocaids = process.env.OCAIDS?.split(',') ?? [];
4
+ ocaids = process.env.OCAIDS?.split(',') ?? null;
5
5
  /** Whether the url we're testing is a prod (or near prod) IA url, or a demos url */
6
6
  isIA = new URL(this.baseUrl).hostname.endsWith('archive.org');
7
7
 
@@ -1,36 +1,36 @@
1
- // import { Selector } from 'testcafe';
2
- // import BookReader from './models/BookReader';
3
- // import params from './helpers/params';
1
+ import { Selector } from 'testcafe';
2
+ import BookReader from './models/BookReader';
3
+ import params from './helpers/params';
4
4
 
5
- // fixture `Viewmode carousel`.page `${params.baseUrl}/BookReaderDemo/viewmode-cycle.html`;
5
+ fixture `Viewmode carousel`.page `${params.baseUrl}/BookReaderDemo/demo-internetarchive.html?ocaid=goody`;
6
6
 
7
- // test('Clicking `view mode` cycles through view modes', async t => {
8
- // const { nav } = (new BookReader());
7
+ test('Clicking `view mode` cycles through view modes', async t => {
8
+ const { nav } = (new BookReader());
9
9
 
10
- // // viewmode button only appear on mobile devices
11
- // await t.resizeWindow(400, 800);
12
- // // Flip forward one
13
- // await t.pressKey('right');
10
+ // viewmode button only appear on mobile devices
11
+ await t.resizeWindow(400, 800);
12
+ // Flip forward one
13
+ await t.pressKey('right');
14
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);
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
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);
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
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);
36
- // });
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);
36
+ });