@internetarchive/bookreader 5.0.0-45 → 5.0.0-46
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.js +1 -1
- 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 +7 -0
- package/CHANGELOG.md +5 -0
- 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 +114 -0
- package/tests/jest/BookReader/Mode2Up.test.js +23 -0
@@ -126,6 +126,13 @@
|
|
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
|
+
send_event: (category, action, label) => console.log('~~~ send_event SAMPLE EVENT CALLED: ', { category, action, label }),
|
134
|
+
send_ping: (category, action, label) => console.log('~~~ send_ping SAMPLE EVENT CALLED: ', { category, action, label }),
|
135
|
+
}
|
129
136
|
</script>
|
130
137
|
|
131
138
|
<!-- IA fetch demo -->
|
package/CHANGELOG.md
CHANGED
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",
|
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
|
@@ -513,4 +513,118 @@ describe('<book-navigator>', () => {
|
|
513
513
|
expect(el.manageFullScreenBehavior.callCount).toEqual(1);
|
514
514
|
});
|
515
515
|
});
|
516
|
+
describe('Handles Restricted Books', () => {
|
517
|
+
describe('contextMenu is prevented when book is restricted', () => {
|
518
|
+
it('watches on `div.BRscreen`', async () => {
|
519
|
+
window.archive_analytics = { send_event_no_sampling: sinon.fake() };
|
520
|
+
|
521
|
+
const el = fixtureSync(container());
|
522
|
+
const brStub = {
|
523
|
+
options: { restricted: true },
|
524
|
+
};
|
525
|
+
|
526
|
+
el.bookreader = brStub;
|
527
|
+
el.bookIsRestricted = true;
|
528
|
+
|
529
|
+
const elSpy = sinon.spy(el.manageContextMenuVisibility);
|
530
|
+
await el.elementUpdated;
|
531
|
+
|
532
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
533
|
+
false
|
534
|
+
);
|
535
|
+
expect(elSpy.called).toEqual(false);
|
536
|
+
|
537
|
+
const body = document.querySelector('body');
|
538
|
+
|
539
|
+
const divBRscreen = document.createElement('div');
|
540
|
+
divBRscreen.classList.add('BRscreen');
|
541
|
+
body.appendChild(divBRscreen);
|
542
|
+
|
543
|
+
const contextMenuEvent = new Event('contextmenu', { bubbles: true });
|
544
|
+
|
545
|
+
// Set spy on contextMenuEvent to check if `preventDefault` is called
|
546
|
+
const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
|
547
|
+
expect(preventDefaultSpy.called).toEqual(false);
|
548
|
+
|
549
|
+
divBRscreen.dispatchEvent(contextMenuEvent);
|
550
|
+
|
551
|
+
// analytics fires
|
552
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
553
|
+
true
|
554
|
+
);
|
555
|
+
// we prevent default
|
556
|
+
expect(preventDefaultSpy.called).toEqual(true);
|
557
|
+
});
|
558
|
+
it('watches on `img.BRpageimage`', async () => {
|
559
|
+
window.archive_analytics = { send_event_no_sampling: sinon.fake() };
|
560
|
+
|
561
|
+
const el = fixtureSync(container());
|
562
|
+
const brStub = {
|
563
|
+
options: { restricted: true },
|
564
|
+
};
|
565
|
+
|
566
|
+
el.bookreader = brStub;
|
567
|
+
el.bookIsRestricted = true;
|
568
|
+
|
569
|
+
await el.elementUpdated;
|
570
|
+
|
571
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
|
572
|
+
false
|
573
|
+
);
|
574
|
+
|
575
|
+
const body = document.querySelector('body');
|
576
|
+
// const element stub for img.BRpageimage
|
577
|
+
const imgBRpageimage = document.createElement('img');
|
578
|
+
imgBRpageimage.classList.add('BRpageimage');
|
579
|
+
body.appendChild(imgBRpageimage);
|
580
|
+
const contextMenuEvent = new Event('contextmenu', { bubbles: true });
|
581
|
+
|
582
|
+
// Set spy on contextMenuEvent to check if `preventDefault` is called
|
583
|
+
const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
|
584
|
+
expect(preventDefaultSpy.called).toEqual(false);
|
585
|
+
|
586
|
+
imgBRpageimage.dispatchEvent(contextMenuEvent);
|
587
|
+
|
588
|
+
// analytics fires
|
589
|
+
expect(window.archive_analytics.send_event_no_sampling.called).toEqual(true);
|
590
|
+
// we prevent default
|
591
|
+
expect(preventDefaultSpy.called).toEqual(true);
|
592
|
+
});
|
593
|
+
});
|
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
|
+
});
|
516
630
|
});
|
@@ -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 });
|