@internetarchive/bookreader 5.0.0-44 → 5.0.0-46-no-right-click-2

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.
@@ -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
@@ -1,6 +1,6 @@
1
+ # 5.0.0-45
1
2
  # 5.0.0-44
2
3
  Fix: dynamic `q=<term>` url parameter @iisa
3
- Fix: lcp download links @iisa
4
4
  Dev: dependency updates @renovate
5
5
 
6
6
  # 5.0.0-43
@@ -51,12 +51,12 @@ Dev: Re-enable testcafe tests in GH action @iisa
51
51
  Fix: Search results bar clears and closes properly @iisa
52
52
 
53
53
  # 5.0.0-35
54
- Fix: global syle leak specify colorbox styles @iisa
54
+ Fix: global style leak specify colorbox styles @iisa
55
55
  Fix: br menu reinits with shared ro load @iisa
56
56
  Fix: url plugin does not rewrite with multiple slashes @iisa
57
57
 
58
58
  # 5.0.0-34
59
- Dev: udpate test dependencies @cdrini
59
+ Dev: update test dependencies @cdrini
60
60
  Fix: Update hyphen stitching regex to include dangling "¬" @cdrini
61
61
  Fix: pop open multiple files menu at proper width @iisa
62
62
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/bookreader",
3
- "version": "5.0.0-44",
3
+ "version": "5.0.0-46-no-right-click-2",
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.2",
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 });