@internetarchive/bookreader 5.0.0-44-a7 → 5.0.0-46-no-right-click
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.js +33352 -2
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +11 -11
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReaderDemo/demo-internetarchive.html +5 -0
- package/CHANGELOG.md +7 -2
- package/package.json +2 -2
- package/src/BookNavigator/book-navigator.js +23 -0
- package/src/BookReader/Mode2Up.js +7 -0
- package/src/util/manifestGenerator.js +0 -0
- package/tests/jest/BookNavigator/book-navigator.test.js +130 -40
- package/tests/jest/BookNavigator/search/search-provider.test.js +35 -0
- package/tests/jest/BookNavigator/search/search-results.test.js +13 -0
- package/tests/jest/BookReader/Mode2Up.test.js +23 -0
@@ -126,6 +126,11 @@
|
|
126
126
|
const placeholder = document.querySelector('#placeholder');
|
127
127
|
placeholder.innerHTML = 'Dependencies are complete, bookreader has loaded';
|
128
128
|
});
|
129
|
+
|
130
|
+
// analytics stub
|
131
|
+
window.archive_analytics = {
|
132
|
+
send_event_no_sampling: (category, action, label) => console.log('~~~ NO SAMPLE EVENT CALLED: ', { category, action, label }),
|
133
|
+
}
|
129
134
|
</script>
|
130
135
|
|
131
136
|
<!-- IA fetch demo -->
|
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 5.0.0-45
|
2
|
+
# 5.0.0-44
|
3
|
+
Fix: dynamic `q=<term>` url parameter @iisa
|
4
|
+
Dev: dependency updates @renovate
|
5
|
+
|
1
6
|
# 5.0.0-43
|
2
7
|
Fix: search results panel display asserted page numbers @cdrini
|
3
8
|
Dev: dependency updates @renovate
|
@@ -46,12 +51,12 @@ Dev: Re-enable testcafe tests in GH action @iisa
|
|
46
51
|
Fix: Search results bar clears and closes properly @iisa
|
47
52
|
|
48
53
|
# 5.0.0-35
|
49
|
-
Fix: global
|
54
|
+
Fix: global style leak specify colorbox styles @iisa
|
50
55
|
Fix: br menu reinits with shared ro load @iisa
|
51
56
|
Fix: url plugin does not rewrite with multiple slashes @iisa
|
52
57
|
|
53
58
|
# 5.0.0-34
|
54
|
-
Dev:
|
59
|
+
Dev: update test dependencies @cdrini
|
55
60
|
Fix: Update hyphen stitching regex to include dangling "¬" @cdrini
|
56
61
|
Fix: pop open multiple files menu at proper width @iisa
|
57
62
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@internetarchive/bookreader",
|
3
|
-
"version": "5.0.0-
|
3
|
+
"version": "5.0.0-46-no-right-click",
|
4
4
|
"description": "The Internet Archive BookReader.",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -46,7 +46,7 @@
|
|
46
46
|
"@babel/plugin-proposal-class-properties": "7.16.7",
|
47
47
|
"@babel/plugin-proposal-decorators": "7.17.9",
|
48
48
|
"@babel/preset-env": "7.16.11",
|
49
|
-
"@open-wc/testing-helpers": "^2.1.
|
49
|
+
"@open-wc/testing-helpers": "^2.1.3",
|
50
50
|
"@types/jest": "^27.5.1",
|
51
51
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
52
52
|
"babel-loader": "8.2.5",
|
@@ -443,6 +443,29 @@ export class BookNavigator extends LitElement {
|
|
443
443
|
this.downloadableTypes = downloadURLs;
|
444
444
|
this.bookIsRestricted = isRestricted;
|
445
445
|
});
|
446
|
+
window.addEventListener('contextmenu', (e) => this.manageContextMenuVisibility(e), { capture: true });
|
447
|
+
}
|
448
|
+
|
449
|
+
/** Display an element's context menu */
|
450
|
+
manageContextMenuVisibility(e) {
|
451
|
+
if (window.archive_analytics) {
|
452
|
+
window.archive_analytics?.send_event_no_sampling(
|
453
|
+
'BookReader',
|
454
|
+
`contextmenu-${this.bookIsRestricted ? 'restricted' : 'unrestricted'}`,
|
455
|
+
e.target.classList.value
|
456
|
+
);
|
457
|
+
}
|
458
|
+
if (!this.bookIsRestricted) {
|
459
|
+
return;
|
460
|
+
}
|
461
|
+
|
462
|
+
const imagePane = e.target.classList.value.match(/BRscreen|BRpageimage/g);
|
463
|
+
if (!imagePane) {
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
|
467
|
+
e.preventDefault();
|
468
|
+
return false;
|
446
469
|
}
|
447
470
|
|
448
471
|
loadSharedObserver() {
|
@@ -843,6 +843,13 @@ export class Mode2Up {
|
|
843
843
|
this.pageContainers[this.br.twoPage.currentIndexR].$container.animate({width: '0px'}, speed, 'easeInSine', () => {
|
844
844
|
this.br.$('BRgutter').css({left: `${gutter - this.br.twoPage.bookSpineDivWidth * 0.5}px`});
|
845
845
|
$(this.br.leafEdgeTmp).animate({left: `${gutter - newWidthL - leafEdgeTmpW}px`}, speed, 'easeOutSine');
|
846
|
+
|
847
|
+
// Ensure the new left leaf is right-positioned before animating its width.
|
848
|
+
// Otherwise, it animates in the wrong direction.
|
849
|
+
this.pageContainers[newIndexL].$container.css({
|
850
|
+
right: `${$twoPageViewEl.prop('clientWidth') - gutter}px`,
|
851
|
+
left: ''
|
852
|
+
});
|
846
853
|
this.pageContainers[newIndexL].$container.animate({width: `${newWidthL}px`}, speed, 'easeOutSine', () => {
|
847
854
|
this.pageContainers[newIndexR].$container.css('zIndex', 2);
|
848
855
|
|
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,
|
@@ -513,4 +524,83 @@ describe('<book-navigator>', () => {
|
|
513
524
|
expect(el.manageFullScreenBehavior.callCount).toEqual(1);
|
514
525
|
});
|
515
526
|
});
|
527
|
+
describe('Handles Restricted Books', () => {
|
528
|
+
describe('contextMenu is prevented when book is restricted', () => {
|
529
|
+
it('watches on `div.BRscreen`', async () => {
|
530
|
+
window.archive_analytics = { send_event_no_sampling: sinon.fake() };
|
531
|
+
|
532
|
+
const el = fixtureSync(container());
|
533
|
+
const brStub = {
|
534
|
+
options: { restricted: true },
|
535
|
+
};
|
536
|
+
|
537
|
+
el.bookreader = brStub;
|
538
|
+
el.bookIsRestricted = true;
|
539
|
+
|
540
|
+
const elSpy = sinon.spy(el.manageContextMenuVisibility);
|
541
|
+
await el.elementUpdated;
|
542
|
+
|
543
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
544
|
+
false
|
545
|
+
);
|
546
|
+
expect(elSpy.called).toEqual(false);
|
547
|
+
|
548
|
+
const body = document.querySelector('body');
|
549
|
+
|
550
|
+
const divBRscreen = document.createElement('div');
|
551
|
+
divBRscreen.classList.add('BRscreen');
|
552
|
+
body.appendChild(divBRscreen);
|
553
|
+
|
554
|
+
const contextMenuEvent = new Event('contextmenu', { bubbles: true });
|
555
|
+
|
556
|
+
// Set spy on contextMenuEvent to check if `preventDefault` is called
|
557
|
+
const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
|
558
|
+
expect(preventDefaultSpy.called).toEqual(false);
|
559
|
+
|
560
|
+
divBRscreen.dispatchEvent(contextMenuEvent);
|
561
|
+
|
562
|
+
// analytics fires
|
563
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
564
|
+
true
|
565
|
+
);
|
566
|
+
// we prevent default
|
567
|
+
expect(preventDefaultSpy.called).toEqual(true);
|
568
|
+
});
|
569
|
+
it('watches on `img.BRpageimage`', async () => {
|
570
|
+
window.archive_analytics = { send_event_no_sampling: sinon.fake() };
|
571
|
+
|
572
|
+
const el = fixtureSync(container());
|
573
|
+
const brStub = {
|
574
|
+
options: { restricted: true },
|
575
|
+
};
|
576
|
+
|
577
|
+
el.bookreader = brStub;
|
578
|
+
el.bookIsRestricted = true;
|
579
|
+
|
580
|
+
await el.elementUpdated;
|
581
|
+
|
582
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
583
|
+
false
|
584
|
+
);
|
585
|
+
|
586
|
+
const body = document.querySelector('body');
|
587
|
+
// const element stub for img.BRpageimage
|
588
|
+
const imgBRpageimage = document.createElement('img');
|
589
|
+
imgBRpageimage.classList.add('BRpageimage');
|
590
|
+
body.appendChild(imgBRpageimage);
|
591
|
+
const contextMenuEvent = new Event('contextmenu', { bubbles: true });
|
592
|
+
|
593
|
+
// Set spy on contextMenuEvent to check if `preventDefault` is called
|
594
|
+
const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
|
595
|
+
expect(preventDefaultSpy.called).toEqual(false);
|
596
|
+
|
597
|
+
imgBRpageimage.dispatchEvent(contextMenuEvent);
|
598
|
+
|
599
|
+
// analytics fires
|
600
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(true);
|
601
|
+
// we prevent default
|
602
|
+
expect(preventDefaultSpy.called).toEqual(true);
|
603
|
+
});
|
604
|
+
});
|
605
|
+
});
|
516
606
|
});
|
@@ -128,5 +128,40 @@ describe('Search Provider', () => {
|
|
128
128
|
expect(urlPluginMock.pullFromAddressBar.callCount).toEqual(2);
|
129
129
|
expect(urlPluginMock.removeUrlParam.callCount).toEqual(2);
|
130
130
|
});
|
131
|
+
it('updateSearchInUrl', async () => {
|
132
|
+
let fieldToSet;
|
133
|
+
let valueOfFieldToSet;
|
134
|
+
let setUrlParamCalled = false;
|
135
|
+
const urlPluginMock = {
|
136
|
+
pullFromAddressBar: sinon.fake(),
|
137
|
+
removeUrlParam: sinon.fake(),
|
138
|
+
setUrlParam: (field, val) => {
|
139
|
+
fieldToSet = field;
|
140
|
+
valueOfFieldToSet = val;
|
141
|
+
setUrlParamCalled = true;
|
142
|
+
}
|
143
|
+
};
|
144
|
+
const provider = new searchProvider({
|
145
|
+
onProviderChange: sinon.fake(),
|
146
|
+
bookreader: {
|
147
|
+
leafNumToIndex: sinon.fake(),
|
148
|
+
_searchPluginGoToResult: sinon.fake(),
|
149
|
+
urlPlugin: urlPluginMock,
|
150
|
+
search: sinon.fake()
|
151
|
+
}
|
152
|
+
});
|
153
|
+
|
154
|
+
const searchInitiatedEvent = new CustomEvent('bookSearchInitiated', { detail: { query: 'foobar' } });
|
155
|
+
// set initial seachState with a query
|
156
|
+
provider.onBookSearchInitiated(searchInitiatedEvent);
|
157
|
+
await provider.updateComplete;
|
158
|
+
// checking this fn:
|
159
|
+
provider.updateSearchInUrl();
|
160
|
+
await provider.updateComplete;
|
161
|
+
|
162
|
+
expect(fieldToSet).toEqual('q');
|
163
|
+
expect(valueOfFieldToSet).toEqual('foobar');
|
164
|
+
expect(setUrlParamCalled).toBe(true);
|
165
|
+
});
|
131
166
|
});
|
132
167
|
});
|
@@ -236,4 +236,17 @@ describe('<ia-book-search-results>', () => {
|
|
236
236
|
|
237
237
|
expect(response).toBeDefined();
|
238
238
|
});
|
239
|
+
it('cancels search when input is cleared', async () => {
|
240
|
+
const el = await fixture(container(results));
|
241
|
+
|
242
|
+
el.cancelSearch = sinon.fake();
|
243
|
+
await el.updateComplete;
|
244
|
+
|
245
|
+
const searchInput = el.shadowRoot.querySelector('[name="query"]');
|
246
|
+
|
247
|
+
searchInput.value = '';
|
248
|
+
searchInput.dispatchEvent(new Event('search'));
|
249
|
+
|
250
|
+
expect(el.cancelSearch.callCount).toEqual(1);
|
251
|
+
});
|
239
252
|
});
|
@@ -47,6 +47,29 @@ describe('zoom', () => {
|
|
47
47
|
});
|
48
48
|
});
|
49
49
|
|
50
|
+
describe('page flip directions', () => {
|
51
|
+
test('animates the left page in the correct direction', () => {
|
52
|
+
const br = new BookReader({ data: SAMPLE_DATA });
|
53
|
+
br.init();
|
54
|
+
|
55
|
+
const fake = sinon.fake();
|
56
|
+
const fakeAnimWithCB = sinon.fake.yields();
|
57
|
+
const fakeAnim = sinon.fake((...args) =>
|
58
|
+
typeof args[args.length - 1] === 'function' ? fakeAnimWithCB(...args) : fake
|
59
|
+
);
|
60
|
+
sinon.replace(jQuery.prototype, 'animate', fakeAnim);
|
61
|
+
|
62
|
+
const fakeCSS = sinon.spy(jQuery.prototype, 'css');
|
63
|
+
|
64
|
+
br.next();
|
65
|
+
|
66
|
+
expect(fakeAnimWithCB.callCount).toBe(2);
|
67
|
+
// Find the call to .css() immediately preceding the second animation with a callback (i.e., the left page animation)
|
68
|
+
const preSecondAnimCssCallIndex = fakeCSS.getCalls().findIndex(call => call.calledAfter(fakeAnimWithCB.getCall(1))) - 1;
|
69
|
+
expect(fakeCSS.getCall(preSecondAnimCssCallIndex).args[0].left).toBe('');
|
70
|
+
});
|
71
|
+
});
|
72
|
+
|
50
73
|
describe('prefetch', () => {
|
51
74
|
test('loads nearby pages', () => {
|
52
75
|
const br = new BookReader({ data: SAMPLE_DATA });
|