@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.
- package/BookReader/BookReader.js +1 -1
- package/BookReader/ia-bookreader-bundle.js +31 -31
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/jquery-1.10.1.js +2 -0
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReaderDemo/IADemoBr.js +13 -17
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -1
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -1
- package/BookReaderDemo/demo-fullscreen.html +1 -1
- package/BookReaderDemo/demo-iiif.html +1 -1
- package/BookReaderDemo/demo-internetarchive.html +1 -3
- package/BookReaderDemo/demo-multiple.html +1 -1
- package/BookReaderDemo/demo-preview-pages.html +1 -1
- package/BookReaderDemo/demo-simple.html +1 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -1
- package/BookReaderDemo/immersion-1up.html +1 -1
- package/BookReaderDemo/immersion-mode.html +1 -1
- package/BookReaderDemo/toggle_controls.html +1 -1
- package/BookReaderDemo/view_mode.html +1 -1
- package/BookReaderDemo/viewmode-cycle.html +1 -1
- package/CHANGELOG.md +0 -12
- package/package.json +7 -7
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +1 -15
- package/src/BookNavigator/search/a-search-result.js +4 -12
- package/src/plugins/search/view.js +5 -10
- package/src/util/manifestGenerator.js +0 -0
- package/tests/jest/BookNavigator/book-navigator.test.js +51 -75
- package/tests/jest/BookNavigator/search/search-results.test.js +1 -33
- package/tests/jest/plugins/search/plugin.search.view.test.js +0 -29
- package/webpack.config.js +1 -1
- package/BookReader/jquery-3.js +0 -2
- 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('{{{(.+?)}}}', '
|
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
|
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
|
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=
|
36
|
-
<div id=
|
37
|
-
<p class=
|
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(
|
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(
|
89
|
-
|
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(
|
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(
|
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(
|
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(
|
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
|
-
|
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', () => {
|