@internetarchive/bookreader 5.0.0-46-alpha2 → 5.0.0-46-no-right-click

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 (36) hide show
  1. package/BookReader/BookReader.js +1 -1
  2. package/BookReader/ia-bookreader-bundle.js +31 -31
  3. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  4. package/BookReader/jquery-1.10.1.js +2 -0
  5. package/BookReader/jquery-1.10.1.js.LICENSE.txt +24 -0
  6. package/BookReader/plugins/plugin.search.js +1 -1
  7. package/BookReader/plugins/plugin.search.js.map +1 -1
  8. package/BookReaderDemo/IADemoBr.js +13 -17
  9. package/BookReaderDemo/demo-advanced.html +1 -1
  10. package/BookReaderDemo/demo-autoplay.html +1 -1
  11. package/BookReaderDemo/demo-embed-iframe-src.html +1 -1
  12. package/BookReaderDemo/demo-fullscreen-mobile.html +1 -1
  13. package/BookReaderDemo/demo-fullscreen.html +1 -1
  14. package/BookReaderDemo/demo-iiif.html +1 -1
  15. package/BookReaderDemo/demo-internetarchive.html +1 -3
  16. package/BookReaderDemo/demo-multiple.html +1 -1
  17. package/BookReaderDemo/demo-preview-pages.html +1 -1
  18. package/BookReaderDemo/demo-simple.html +1 -1
  19. package/BookReaderDemo/demo-vendor-fullscreen.html +1 -1
  20. package/BookReaderDemo/immersion-1up.html +1 -1
  21. package/BookReaderDemo/immersion-mode.html +1 -1
  22. package/BookReaderDemo/toggle_controls.html +1 -1
  23. package/BookReaderDemo/view_mode.html +1 -1
  24. package/BookReaderDemo/viewmode-cycle.html +1 -1
  25. package/CHANGELOG.md +0 -12
  26. package/package.json +7 -7
  27. package/src/BookNavigator/bookmarks/ia-bookmarks.js +1 -15
  28. package/src/BookNavigator/search/a-search-result.js +4 -12
  29. package/src/plugins/search/view.js +5 -10
  30. package/src/util/manifestGenerator.js +0 -0
  31. package/tests/jest/BookNavigator/book-navigator.test.js +51 -75
  32. package/tests/jest/BookNavigator/search/search-results.test.js +1 -33
  33. package/tests/jest/plugins/search/plugin.search.view.test.js +0 -29
  34. package/webpack.config.js +1 -1
  35. package/BookReader/jquery-3.js +0 -2
  36. package/BookReader/jquery-3.js.LICENSE.txt +0 -24
@@ -1,5 +1,3 @@
1
- import { escapeHTML } from "../../BookReader/utils.js";
2
-
3
1
  class SearchView {
4
2
  /**
5
3
  * @param {object} params
@@ -15,7 +13,7 @@ class SearchView {
15
13
  // Search results are returned as a text blob with the hits wrapped in
16
14
  // triple mustaches. Hits occasionally include text beyond the search
17
15
  // term, so everything within the staches is captured and wrapped.
18
- this.matcher = new RegExp('{{{(.+?)}}}', 'gs');
16
+ this.matcher = new RegExp('{{{(.+?)}}}', 'g');
19
17
  this.matches = [];
20
18
  this.cacheDOMElements();
21
19
  this.bindEvents();
@@ -236,18 +234,15 @@ class SearchView {
236
234
 
237
235
  const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.getNumLeafs() - 1);
238
236
 
239
- const escapedQueryString = escapeHTML(queryString);
240
- const queryStringWithB = escapedQueryString.replace(this.matcher, '<b>$1</b>');
237
+ const queryStringWithB = queryString.replace(this.matcher, '<b>$1</b>');
241
238
 
242
239
  let queryStringWithBTruncated = '';
243
240
 
244
241
  if (queryString.length > 100) {
245
- queryStringWithBTruncated = queryString.replace(/^(.{100}[^\s]*).*/, "$1");
246
-
247
- // If truncating, we must escape *after* truncation occurs (but before wrapping in <b>)
248
- queryStringWithBTruncated = escapeHTML(queryStringWithBTruncated)
242
+ queryStringWithBTruncated = queryString
243
+ .replace(/^(.{100}[^\s]*).*/, "$1")
249
244
  .replace(this.matcher, '<b>$1</b>')
250
- + '...';
245
+ + '...';
251
246
  }
252
247
 
253
248
  // draw marker
File without changes
@@ -13,8 +13,9 @@ import VolumesProvider from '@/src/BookNavigator/volumes/volumes-provider.js';
13
13
  import { ModalManager } from '@internetarchive/modal-manager';
14
14
  import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
15
15
  import '@/src/BookNavigator/book-navigator.js';
16
+ import { sleep } from '@/src/BookReader/utils';
16
17
 
17
- const promise0 = () => new Promise(res => setTimeout(res, 0));
18
+ const promise0 = () => new Promise((res) => setTimeout(res, 0));
18
19
 
19
20
  const container = (sharedObserver = null) => {
20
21
  const itemStub = {
@@ -22,7 +23,7 @@ const container = (sharedObserver = null) => {
22
23
  identifier: 'foo',
23
24
  creator: 'bar',
24
25
  title: 'baz',
25
- }
26
+ },
26
27
  };
27
28
  const modalMgr = new ModalManager();
28
29
  return html`
@@ -32,18 +33,18 @@ const container = (sharedObserver = null) => {
32
33
  .sharedObserver=${sharedObserver || new SharedResizeObserver()}
33
34
  .modal=${modalMgr}
34
35
  >
35
- <div slot="main">
36
- <div id="BookReader"></div>
37
- <p class="visible-in-reader">now showing</p>
36
+ <div slot='main'>
37
+ <div id='BookReader'></div>
38
+ <p class='visible-in-reader'>now showing</p>
38
39
  <\div>
39
40
  </book-navigator>
40
41
  `;
41
42
  };
42
43
 
43
44
  window.ResizeObserver = class ResizeObserver {
44
- observe = sinon.fake()
45
- unobserve = sinon.fake()
46
- disconnect = sinon.fake()
45
+ observe = sinon.fake();
46
+ unobserve = sinon.fake();
47
+ disconnect = sinon.fake();
47
48
  };
48
49
 
49
50
  afterEach(() => {
@@ -52,11 +53,11 @@ afterEach(() => {
52
53
  const body = document.querySelector('body');
53
54
  body.innerHTML = '';
54
55
  sinon.restore();
56
+ window.archive_analytics = null;
55
57
  });
56
58
 
57
-
58
59
  describe('<book-navigator>', () => {
59
- describe("How it loads", () => {
60
+ describe('How it loads', () => {
60
61
  describe('Attaches BookReader listeners before `br.init` is called', () => {
61
62
  test('binds global event listeners', async () => {
62
63
  const el = fixtureSync(container());
@@ -71,7 +72,7 @@ describe('<book-navigator>', () => {
71
72
  jumpToIndex: sinon.fake(),
72
73
  options: { enableMultipleBooks: false }, // for multipleBooks
73
74
  el: '#BookReader',
74
- refs: {}
75
+ refs: {},
75
76
  };
76
77
 
77
78
  const sharedObserver = new SharedResizeObserver();
@@ -85,9 +86,11 @@ describe('<book-navigator>', () => {
85
86
 
86
87
  expect(brStub.resize.callCount).toEqual(0);
87
88
 
88
- window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
89
- detail: { props: brStub }
90
- }));
89
+ window.dispatchEvent(
90
+ new CustomEvent('BookReader:PostInit', {
91
+ detail: { props: brStub },
92
+ })
93
+ );
91
94
  await elementUpdated(el);
92
95
 
93
96
  expect(el.emitLoadingStatusUpdate.callCount).toEqual(1);
@@ -120,13 +123,15 @@ describe('<book-navigator>', () => {
120
123
  const itemImage = fixtureSync(el.itemImage);
121
124
  expect(itemImage).toBeInstanceOf(HTMLImageElement);
122
125
  expect(itemImage.getAttribute('class')).toEqual('cover-img');
123
- expect(itemImage.getAttribute('src')).toEqual('https://https://foo.archive.org/services/img/foo');
126
+ expect(itemImage.getAttribute('src')).toEqual(
127
+ 'https://https://foo.archive.org/services/img/foo'
128
+ );
124
129
  });
125
130
  });
126
131
  describe('Menu/Layer Provider', () => {
127
132
  describe('Connecting with a provider:', () => {
128
133
  // loads Providers with base shared resources
129
- test('We load 3 Sub Menus by default', async() => {
134
+ test('We load 3 Sub Menus by default', async () => {
130
135
  const el = fixtureSync(container());
131
136
  const $brContainer = document.createElement('div');
132
137
  const brStub = {
@@ -135,8 +140,8 @@ describe('<book-navigator>', () => {
135
140
  jumpToIndex: sinon.fake(),
136
141
  options: {},
137
142
  refs: {
138
- $brContainer
139
- }
143
+ $brContainer,
144
+ },
140
145
  };
141
146
  el.bookreader = brStub;
142
147
  await el.elementUpdated;
@@ -151,10 +156,12 @@ describe('<book-navigator>', () => {
151
156
  expect(el.menuProviders.share).toBeInstanceOf(SharingProvider);
152
157
 
153
158
  expect(defaultMenus).toContain('visualAdjustments');
154
- expect(el.menuProviders.visualAdjustments).toBeInstanceOf(VisualAdjustmentsProvider);
159
+ expect(el.menuProviders.visualAdjustments).toBeInstanceOf(
160
+ VisualAdjustmentsProvider
161
+ );
155
162
  });
156
163
  describe('Loading Sub Menus By Plugin Flags', () => {
157
- test('Search: uses `enableSearch` flag', async() => {
164
+ test('Search: uses `enableSearch` flag', async () => {
158
165
  const el = fixtureSync(container());
159
166
  const $brContainer = document.createElement('div');
160
167
  const brStub = {
@@ -163,8 +170,8 @@ describe('<book-navigator>', () => {
163
170
  jumpToIndex: sinon.fake(),
164
171
  options: { enableSearch: true },
165
172
  refs: {
166
- $brContainer
167
- }
173
+ $brContainer,
174
+ },
168
175
  };
169
176
  el.bookreader = brStub;
170
177
  await el.elementUpdated;
@@ -176,9 +183,9 @@ describe('<book-navigator>', () => {
176
183
  expect(el.menuProviders.search).toBeInstanceOf(SearchProvider);
177
184
 
178
185
  // also adds a menu shortcut
179
- expect(el.menuShortcuts.find(m => m.id === 'search')).toBeDefined();
186
+ expect(el.menuShortcuts.find((m) => m.id === 'search')).toBeDefined();
180
187
  });
181
- test('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
188
+ test('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async () => {
182
189
  const el = fixtureSync(container());
183
190
  const $brContainer = document.createElement('div');
184
191
  const brStub = {
@@ -189,13 +196,13 @@ describe('<book-navigator>', () => {
189
196
  enableMultipleBooks: true,
190
197
  multipleBooksList: {
191
198
  by_subprefix: {
192
- fooSubprefix: 'beep'
193
- }
194
- }
199
+ fooSubprefix: 'beep',
200
+ },
201
+ },
195
202
  },
196
203
  refs: {
197
- $brContainer
198
- }
204
+ $brContainer,
205
+ },
199
206
  };
200
207
  el.bookreader = brStub;
201
208
  await el.elementUpdated;
@@ -207,7 +214,9 @@ describe('<book-navigator>', () => {
207
214
  expect(el.menuProviders.volumes).toBeInstanceOf(VolumesProvider);
208
215
 
209
216
  // also adds a menu shortcut
210
- expect(el.menuShortcuts.find(m => m.id === 'volumes')).toBeDefined();
217
+ expect(
218
+ el.menuShortcuts.find((m) => m.id === 'volumes')
219
+ ).toBeDefined();
211
220
  });
212
221
  });
213
222
  test('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
@@ -315,7 +324,9 @@ describe('<book-navigator>', () => {
315
324
  console.log();
316
325
  sidePanelConfig = e.detail;
317
326
  });
318
- const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
327
+ const toggleSearchMenuEvent = new Event(
328
+ 'BookReader:ToggleSearchMenu'
329
+ );
319
330
  window.dispatchEvent(toggleSearchMenuEvent);
320
331
 
321
332
  await elementUpdated(el);
@@ -327,15 +338,15 @@ describe('<book-navigator>', () => {
327
338
  });
328
339
  });
329
340
 
330
- describe('Resizing',() => {
341
+ describe('Resizing', () => {
331
342
  test('keeps track of `brWidth` and `brHeight`', async () => {
332
343
  const el = fixtureSync(container());
333
344
  const brStub = {
334
345
  resize: sinon.fake(),
335
346
  options: {},
336
347
  refs: {
337
- $brContainer: document.createElement('div')
338
- }
348
+ $brContainer: document.createElement('div'),
349
+ },
339
350
  };
340
351
  el.bookreader = brStub;
341
352
  await elementUpdated(el);
@@ -345,9 +356,9 @@ describe('<book-navigator>', () => {
345
356
  const mockResizeEvent = {
346
357
  contentRect: {
347
358
  height: 500,
348
- width: 900
359
+ width: 900,
349
360
  },
350
- target: el.mainBRContainer
361
+ target: el.mainBRContainer,
351
362
  };
352
363
  el.handleResize(mockResizeEvent);
353
364
 
@@ -364,8 +375,8 @@ describe('<book-navigator>', () => {
364
375
  resize: sinon.fake(),
365
376
  options: {},
366
377
  refs: {
367
- $brContainer: document.createElement('div')
368
- }
378
+ $brContainer: document.createElement('div'),
379
+ },
369
380
  };
370
381
 
371
382
  el.bookreader = brStub;
@@ -470,7 +481,7 @@ describe('<book-navigator>', () => {
470
481
 
471
482
  expect(el.closeFullscreen.callCount).toEqual(1);
472
483
  });
473
- test('removes Fullscreen shortcut when leaving fullscreen', async() => {
484
+ test('removes Fullscreen shortcut when leaving fullscreen', async () => {
474
485
  const el = fixtureSync(container());
475
486
  const brStub = {
476
487
  isFullscreen: () => false,
@@ -489,7 +500,7 @@ describe('<book-navigator>', () => {
489
500
  expect(el.menuShortcuts.length).toEqual(0);
490
501
  expect(el.emitMenuShortcutsUpdated.callCount).toEqual(1);
491
502
  });
492
- test('Event: Listens for `BookReader:FullscreenToggled', async() => {
503
+ test('Event: Listens for `BookReader:FullscreenToggled', async () => {
493
504
  const el = fixtureSync(container());
494
505
  const brStub = {
495
506
  isFullscreen: () => true,
@@ -591,40 +602,5 @@ describe('<book-navigator>', () => {
591
602
  expect(preventDefaultSpy.called).toEqual(true);
592
603
  });
593
604
  });
594
- it('Allows unrestricted books access to context menu', async () => {
595
- window.archive_analytics = { send_event_no_sampling: sinon.fake() };
596
-
597
- const el = fixtureSync(container());
598
- const brStub = {
599
- options: { restricted: false },
600
- };
601
-
602
- el.bookreader = brStub;
603
- el.bookIsRestricted = false;
604
-
605
- await el.elementUpdated;
606
-
607
- expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
608
- false
609
- );
610
-
611
- const body = document.querySelector('body');
612
- // const element stub for img.BRpageimage
613
- const imgBRpageimage = document.createElement('img');
614
- imgBRpageimage.classList.add('not-targeted-element');
615
- body.appendChild(imgBRpageimage);
616
- const contextMenuEvent = new Event('contextmenu', { bubbles: true });
617
-
618
- // Set spy on contextMenuEvent to check if `preventDefault` is called
619
- const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
620
- expect(preventDefaultSpy.called).toEqual(false);
621
-
622
- imgBRpageimage.dispatchEvent(contextMenuEvent);
623
-
624
- // analytics fires
625
- expect(window.archive_analytics.send_event_no_sampling.called).toEqual(true);
626
- // we do not prevent default
627
- expect(preventDefaultSpy.called).toEqual(false);
628
- });
629
605
  });
630
606
  });
@@ -46,25 +46,6 @@ const results = [{
46
46
  }],
47
47
  }];
48
48
 
49
- const resultWithScript = [{
50
- text: `foo bar <script>const msg = 'test' + ' failure'; document.write(msg);</script> {{{${searchQuery}}}} baz`,
51
- cover: '//placehold.it/30x44',
52
- title: 'Book title',
53
- displayPageNumber: 'Page 24',
54
- par: [{
55
- boxes: [{
56
- r: 2672, b: 792, t: 689, page: 24, l: 2424,
57
- }],
58
- b: 1371,
59
- t: 689,
60
- page_width: 3658,
61
- r: 3192,
62
- l: 428,
63
- page_height: 5357,
64
- page: 24,
65
- }],
66
- }];
67
-
68
49
  describe('<ia-book-search-results>', () => {
69
50
  afterEach(() => {
70
51
  sinon.restore();
@@ -107,20 +88,7 @@ describe('<ia-book-search-results>', () => {
107
88
  sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
108
89
  const el = await fixture(container(results));
109
90
 
110
- // Lit inserts HTML comments that inhibit searching for exact innerHTML matches.
111
- // So query the DOM for the match instead.
112
- const match = el.querySelector('book-search-result mark');
113
- expect(match?.textContent).toEqual(searchQuery);
114
- });
115
-
116
- test('renders results that contain sanitized HTML tags', async () => {
117
- sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
118
- // A result whose text contains a <script> tag that will insert 'test failure' into the element if not sanitized
119
- const el = await fixture(container(resultWithScript));
120
-
121
- const match = el.querySelector('book-search-result mark');
122
- expect(match?.textContent).toEqual(searchQuery);
123
- expect(el.innerHTML).not.toContain('test failure');
91
+ expect(el.innerHTML).toContain(`<mark>${searchQuery}</mark>`);
124
92
  });
125
93
 
126
94
  test('renders results that contain an optional cover image', async () => {
@@ -27,27 +27,6 @@ const results = {
27
27
  }]
28
28
  }]
29
29
  };
30
- const resultWithScript = {
31
- ia: "adventuresofoli00dick",
32
- q: "child",
33
- indexed: true,
34
- page_count: 644,
35
- body_length: 666,
36
- leaf0_missing: false,
37
- matches: [{
38
- text: 'foo bar <script>alert(1);</script> {{{keyword}}} baz',
39
- par: [{
40
- boxes: [{r: 1221, b: 2121, t: 2075, page: 37, l: 1107}],
41
- b: 2535,
42
- t: 1942,
43
- page_width: 1790,
44
- r: 1598,
45
- l: 50,
46
- page_height: 2940,
47
- page: 37
48
- }]
49
- }]
50
- };
51
30
  beforeEach(() => {
52
31
  $.ajax = jest.fn().mockImplementation(() => {
53
32
  // return from:
@@ -102,14 +81,6 @@ describe('View: Plugin: Search', () => {
102
81
  expect(searchResultsNav.querySelector('.prev')).toBeDefined();
103
82
  expect(searchResultsNav.querySelector('.next')).toBeDefined();
104
83
  });
105
- test('disallows xss from search results', () => {
106
- br.init();
107
- const event = new CustomEvent(`${namespace}SearchCallback`);
108
- const options = { goToFirstResult: false };
109
- br.searchView.handleSearchCallback(event, { results: resultWithScript, options });
110
-
111
- expect(br.searchView.dom.searchNavigation.parent().html()).not.toContain('<script>alert(1);</script>');
112
- });
113
84
 
114
85
  describe('Click events handlers', () => {
115
86
  it('triggers custom event when toggling side menu', () => {
package/webpack.config.js CHANGED
@@ -86,7 +86,7 @@ module.exports = [
86
86
  ...shared,
87
87
 
88
88
  entry: {
89
- 'jquery-3.js': { import: './src/jquery-wrapper.js' },
89
+ 'jquery-1.10.1.js': { import: './src/jquery-wrapper.js' },
90
90
  },
91
91
  },
92
92
  ];