@internetarchive/bookreader 5.0.0-37 → 5.0.0-38

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # 5.0.0-38
2
+ Dev: Add Renovate Bot @cdrini
3
+ Dev: Update node-fetch @cdrini
4
+ Fix: Search request promise err & fix tests @cdrini
5
+ Dev: Split node workflow into different jobs @cdrini
6
+ Dev: Give cache steps better names in GHA @cdrini
7
+ Dev: Update concurrently + Small speedup to build & test @cdrini
8
+ Dev: Renovate - Auto-update dev dependencies for minor/patch @cdrini
9
+ Fix: Better MS Edge voice selection @cdrini
10
+ Dev: Allow small drops in codecov coverage (< 0.5%) @cdrini
11
+ Dev: Renovate - add `^@internetarchive/icon-` @cdrini
12
+
1
13
  # 5.0.0-37
2
14
  Fix: Update all `.then()` to async/await @sancodes
3
15
  Fix: Upgrade to Lit 2 @Aadilhassan
package/codecov.yml CHANGED
@@ -1,6 +1,12 @@
1
1
  codecov:
2
2
  notify:
3
3
  require_ci_to_pass: yes
4
+ status:
5
+ project:
6
+ default:
7
+ # Allow small drops in coverage
8
+ threshold: 0.005 # .5 %
9
+ if_not_found: failure
4
10
 
5
11
  coverage:
6
12
  precision: 2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/bookreader",
3
- "version": "5.0.0-37",
3
+ "version": "5.0.0-38",
4
4
  "description": "The Internet Archive BookReader.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,25 +41,25 @@
41
41
  "lit": "^2.1.3"
42
42
  },
43
43
  "devDependencies": {
44
- "@babel/core": "7.15.0",
45
- "@babel/eslint-parser": "^7.16.5",
46
- "@babel/plugin-proposal-class-properties": "^7.14.5",
47
- "@babel/plugin-proposal-decorators": "^7.14.5",
48
- "@babel/preset-env": "7.15.0",
44
+ "@babel/core": "7.17.5",
45
+ "@babel/eslint-parser": "7.17.0",
46
+ "@babel/plugin-proposal-class-properties": "7.16.7",
47
+ "@babel/plugin-proposal-decorators": "7.17.2",
48
+ "@babel/preset-env": "7.16.11",
49
49
  "@open-wc/testing": "^3.0.4",
50
50
  "@open-wc/testing-karma": "^4.0.9",
51
51
  "@types/jest": "^27.4.0",
52
52
  "@webcomponents/webcomponentsjs": "^2.6.0",
53
- "babel-loader": "8.2.2",
53
+ "babel-loader": "8.2.3",
54
54
  "codecov": "^3.8.3",
55
- "concurrently": "6.0.2",
55
+ "concurrently": "7.0.0",
56
56
  "core-js": "3.16.2",
57
57
  "cpx2": "3.0.0",
58
58
  "eslint": "^7.32.0",
59
59
  "eslint-plugin-no-jquery": "^2.7.0",
60
60
  "eslint-plugin-testcafe": "^0.2.1",
61
61
  "hammerjs": "^2.0.8",
62
- "http-server": "0.12.3",
62
+ "http-server": "14.1.0",
63
63
  "iso-language-codes": "1.1.0",
64
64
  "jest": "^27.4.7",
65
65
  "jquery": "1.11.3",
@@ -70,7 +70,7 @@
70
70
  "jquery.mmenu": "5.6.5",
71
71
  "karma-coverage": "^2.1.0",
72
72
  "live-server": "1.2.1",
73
- "node-fetch": "2.6.1",
73
+ "node-fetch": "2.6.7",
74
74
  "regenerator-runtime": "0.13.9",
75
75
  "sass": "1.38.2",
76
76
  "sinon": "^12.0.1",
@@ -102,7 +102,7 @@
102
102
  "preversion": "npm run test && node scripts/preversion.js",
103
103
  "version": "node scripts/version.js",
104
104
  "postversion": "node scripts/postversion.js",
105
- "build": "npm run clean && npm run build-js && npm run build-css && npm run build-assets",
105
+ "build": "npm run clean && npx concurrently --group npm:build-js npm:build-css npm:build-assets",
106
106
  "build-assets": "npx cpx \"src/assets/**/*\" BookReader && npx svgo -f BookReader/icons && npx svgo -f BookReader/images",
107
107
  "build-assets:watch": "npx cpx --watch --verbose \"src/assets/**/*\" BookReader",
108
108
  "build-js": "npx webpack",
@@ -115,7 +115,7 @@
115
115
  "serve": "npx http-server . --port 8000",
116
116
  "serve-live": "npx live-server . --port 8000 --watch=index.html,BookReader,BookReaderDemo",
117
117
  "serve-dev": "npm run build-css && npx concurrently --kill-others npm:serve-live npm:build-*:watch",
118
- "test": "npm run test-jest && npm run test-karma",
118
+ "test": "npx concurrently --group npm:test-jest npm:test-karma",
119
119
  "test:e2e": "npm run build && npx testcafe",
120
120
  "test:e2e:dev": "npx testcafe --live --dev",
121
121
  "test-jest:watch": "npx jest --watch",
package/renovate.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "extends": [
3
+ "config:base"
4
+ ],
5
+ "packageRules": [
6
+ {
7
+ "matchPackageNames": [
8
+ "@babel/eslint-parser",
9
+ "@open-wc/testing",
10
+ "@open-wc/testing-karma",
11
+ "@types/jest",
12
+ "codecov",
13
+ "eslint",
14
+ "eslint-plugin-no-jquery",
15
+ "eslint-plugin-testcafe",
16
+ "jest",
17
+ "karma-coverage",
18
+ "sinon",
19
+ "testcafe"
20
+ ],
21
+ "automerge": true
22
+ },
23
+ {
24
+ "matchPackageNames": [
25
+ "concurrently",
26
+ "http-server",
27
+ "live-server",
28
+ "node-fetch"
29
+ ],
30
+ "matchUpdateTypes": ["minor", "patch"],
31
+ "automerge": true
32
+ },
33
+ {
34
+ "matchPackagePatterns": ["^@internetarchive/icon-"],
35
+ "groupName": "@internetarchive icons",
36
+ "rangeStrategy": "bump"
37
+ },
38
+ {
39
+ "matchPackagePatterns": ["^@internetarchive"],
40
+ "rangeStrategy": "bump"
41
+ }
42
+ ]
43
+ }
@@ -144,6 +144,7 @@ BookReader.prototype.search = async 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 = async 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,12 +197,6 @@ BookReader.prototype.search = async 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 });
@@ -214,8 +204,7 @@ BookReader.prototype.search = async function(term = '', overrides = {}) {
214
204
  url: url,
215
205
  dataType: 'jsonp',
216
206
  cache: true,
217
- beforeSend,
218
- jsonpCallback: 'BRSearchInProgress'
207
+ beforeSend: xhr => { this.searchXHR = xhr; },
219
208
  }));
220
209
  };
221
210
 
@@ -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
  }
@@ -1,3 +1,44 @@
1
+ /*
2
+ <script src="foo-plugin.js"></script>
3
+
4
+ foo-plugin.js
5
+
6
+ $('#foo-plugin').dataSet('MainController', 'bar');
7
+
8
+ <ia-bookreader>
9
+ <div slot="plugins">
10
+ <ia-search></ia-search>
11
+ <book-marks></book-marks>
12
+ </div>
13
+ </ia-bookreader>
14
+
15
+ iaBookreader.registerPlugin('foo-plugin', Class);
16
+
17
+
18
+ class IABr extends LItElement {
19
+
20
+ render() {
21
+
22
+ registerPlugins() {
23
+ this.pluginSlots.map(slot => {
24
+ .. to slot registry
25
+ each slot - do handshake
26
+
27
+
28
+ });
29
+ }
30
+
31
+ html`
32
+ <div slot="plugins" @onslotchange=${() => x}></div>
33
+ `;
34
+ }
35
+ }
36
+ */
37
+
38
+
39
+
40
+
41
+
1
42
  import { css, html, LitElement } from 'lit-element';
2
43
  import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
3
44
  import SearchProvider from './search/search-provider.js';
@@ -113,6 +154,7 @@ export class BookNavigator extends LitElement {
113
154
  // };
114
155
 
115
156
  this.menuProviders = {
157
+ // if enableSearch ?
116
158
  search: new SearchProvider(
117
159
  /**
118
160
  * Search specific menu updates
@@ -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
  });
@@ -1,8 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: npm
4
- directory: "/"
5
- schedule:
6
- interval: monthly
7
- time: "13:00"
8
- open-pull-requests-limit: 10