Skip to content

Commit

Permalink
feat(annotations): Add support for image annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
jstoffan committed Jun 15, 2020
1 parent e9d21a0 commit 11e8caf
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 27 deletions.
15 changes: 15 additions & 0 deletions src/lib/viewers/BaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ class BaseViewer extends EventEmitter {
this.handleAnnotationCreateEvent = this.handleAnnotationCreateEvent.bind(this);
this.handleFullscreenEnter = this.handleFullscreenEnter.bind(this);
this.handleFullscreenExit = this.handleFullscreenExit.bind(this);
this.handleRegionClick = this.handleRegionClick.bind(this);
this.createAnnotator = this.createAnnotator.bind(this);
this.viewerLoadHandler = this.viewerLoadHandler.bind(this);
this.initAnnotations = this.initAnnotations.bind(this);
Expand Down Expand Up @@ -243,6 +244,10 @@ class BaseViewer extends EventEmitter {
});
}

if (this.annotationControls) {
this.annotationControls.destroy();
}

fullscreen.removeAllListeners();
document.defaultView.removeEventListener('resize', this.debouncedResizeHandler);
this.removeAllListeners();
Expand Down Expand Up @@ -1025,6 +1030,16 @@ class BaseViewer extends EventEmitter {
return permissions.can_annotate || permissions.can_create_annotations;
}

/**
* Handler for annotation toolbar region comment button click event.
*
* @private
* @return {void}
*/
handleRegionClick() {
this.annotator.toggleAnnotationMode(AnnotationMode.REGION);
}

/**
* Handles the 'scrolltoannotation' event and calls the annotator scroll method
* @param {string | Object} event - Annotation Event
Expand Down
14 changes: 12 additions & 2 deletions src/lib/viewers/__tests__/BaseViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ describe('lib/viewers/BaseViewer', () => {
toggleAnnotationMode: sandbox.mock(),
};
base.annotationControls = {
destroy: sandbox.mock(),
resetControls: sandbox.mock(),
};
sandbox.stub(base, 'areNewAnnotationsEnabled').returns(true);
Expand Down Expand Up @@ -618,10 +619,18 @@ describe('lib/viewers/BaseViewer', () => {
expect(base.emit).to.be.calledWith('destroy');
});

it('should clean up the annotation controls', () => {
base.annotationControls = {
destroy: sandbox.stub(),
};
base.destroy();
expect(base.annotationControls.destroy).to.be.called;
});

it('should clean up annotator', () => {
base.annotator = {
removeAllListeners: sandbox.mock(),
destroy: sandbox.mock(),
removeAllListeners: sandbox.stub(),
destroy: sandbox.stub(),
};
base.destroy();
expect(base.annotator.removeAllListeners).to.be.called;
Expand Down Expand Up @@ -1175,6 +1184,7 @@ describe('lib/viewers/BaseViewer', () => {
CONSTRUCTOR: sandbox.stub().returns(base.annotator),
};
base.annotationControls = {
destroy: sandbox.stub(),
resetControls: sandbox.stub(),
};
sandbox.stub(base, 'areNewAnnotationsEnabled').returns(true);
Expand Down
25 changes: 5 additions & 20 deletions src/lib/viewers/doc/DocBaseViewer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import throttle from 'lodash/throttle';
import AnnotationControls, { AnnotationMode } from '../../AnnotationControls';
import AnnotationControls from '../../AnnotationControls';
import BaseViewer from '../BaseViewer';
import Browser from '../../Browser';
import Controls from '../../Controls';
Expand Down Expand Up @@ -97,7 +97,6 @@ class DocBaseViewer extends BaseViewer {
this.pinchToZoomEndHandler = this.pinchToZoomEndHandler.bind(this);
this.pinchToZoomStartHandler = this.pinchToZoomStartHandler.bind(this);
this.print = this.print.bind(this);
this.regionClickHandler = this.regionClickHandler.bind(this);
this.setPage = this.setPage.bind(this);
this.throttledScrollHandler = this.getScrollHandler().bind(this);
this.toggleThumbnails = this.toggleThumbnails.bind(this);
Expand Down Expand Up @@ -164,10 +163,6 @@ class DocBaseViewer extends BaseViewer {
URL.revokeObjectURL(this.printURL);
}

if (this.annotationControls) {
this.annotationControls.destroy();
}

if (this.pageControls) {
this.pageControls.removeListener('pagechange', this.setPage);
}
Expand Down Expand Up @@ -1014,11 +1009,13 @@ class DocBaseViewer extends BaseViewer {
loadUI() {
this.controls = new Controls(this.containerEl);
this.pageControls = new PageControls(this.controls, this.docEl);
this.pageControls.addListener('pagechange', this.setPage);
this.zoomControls = new ZoomControls(this.controls);

if (this.areNewAnnotationsEnabled() && this.hasAnnotationCreatePermission()) {
this.annotationControls = new AnnotationControls(this.controls);
}
this.pageControls.addListener('pagechange', this.setPage);

this.bindControlListeners();
}

Expand Down Expand Up @@ -1101,22 +1098,10 @@ class DocBaseViewer extends BaseViewer {
this.controls.add(__('exit_fullscreen'), this.toggleFullscreen, 'bp-exit-fullscreen-icon', ICON_FULLSCREEN_OUT);

if (this.areNewAnnotationsEnabled() && this.hasAnnotationCreatePermission()) {
this.annotationControls.init({
onRegionClick: this.regionClickHandler,
});
this.annotationControls.init({ onRegionClick: this.handleRegionClick });
}
}

/**
* Handler for annotation toolbar region comment button click event.
*
* @private
* @return {void}
*/
regionClickHandler() {
this.annotator.toggleAnnotationMode(AnnotationMode.REGION);
}

/**
* Handler for 'pagesinit' event.
*
Expand Down
2 changes: 1 addition & 1 deletion src/lib/viewers/doc/__tests__/DocBaseViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2303,7 +2303,7 @@ describe('src/lib/viewers/doc/DocBaseViewer', () => {
ICON_FULLSCREEN_OUT,
);
expect(docBase.annotationControls.init).to.be.calledWith({
onRegionClick: docBase.regionClickHandler,
onRegionClick: docBase.handleRegionClick,
});
});

Expand Down
13 changes: 9 additions & 4 deletions src/lib/viewers/image/ImageViewer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import AnnotationControls from '../../AnnotationControls';
import ImageBaseViewer from './ImageBaseViewer';
import { ICON_FULLSCREEN_IN, ICON_FULLSCREEN_OUT, ICON_ROTATE_LEFT } from '../../icons/icons';
import { CLASS_INVISIBLE } from '../../constants';

import { ICON_FULLSCREEN_IN, ICON_FULLSCREEN_OUT, ICON_ROTATE_LEFT } from '../../icons/icons';
import './Image.scss';

const CSS_CLASS_IMAGE = 'bp-image';
Expand Down Expand Up @@ -285,6 +285,11 @@ class ImageViewer extends ImageBaseViewer {
ICON_FULLSCREEN_IN,
);
this.controls.add(__('exit_fullscreen'), this.toggleFullscreen, 'bp-exit-fullscreen-icon', ICON_FULLSCREEN_OUT);

if (this.areNewAnnotationsEnabled() && this.hasAnnotationCreatePermission()) {
this.annotationControls = new AnnotationControls(this.controls);
this.annotationControls.init({ onRegionClick: this.handleRegionClick });
}
}

/**
Expand Down Expand Up @@ -339,8 +344,8 @@ class ImageViewer extends ImageBaseViewer {
this.imageEl.style.top = `${topPadding}px`;

// Fix the scroll position of the image to be centered
this.wrapperEl.scrollLeft = (this.wrapperEl.scrollWidth - viewport.width) / 2;
this.wrapperEl.scrollTop = (this.wrapperEl.scrollHeight - viewport.height) / 2;
this.wrapperEl.scrollLeft = (this.imageEl.clientWidth - viewport.width) / 2;
this.wrapperEl.scrollTop = (this.imageEl.clientHeight - viewport.height) / 2;
}

//--------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions src/lib/viewers/image/__tests__/ImageViewer-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-unused-expressions */
import AnnotationControls from '../../../AnnotationControls';
import ImageViewer from '../ImageViewer';
import BaseViewer from '../../BaseViewer';
import Browser from '../../../Browser';
Expand Down Expand Up @@ -351,6 +352,15 @@ describe('lib/viewers/image/ImageViewer', () => {
expect(image.controls).to.not.be.undefined;
expect(image.controls.buttonRefs.length).to.equal(5);
expect(image.zoomControls.currentScale).to.equal(50);
expect(image.annotationControls).to.be.undefined; // Not enabled by default
});

it('should add annotations controls', () => {
sandbox.stub(image, 'areNewAnnotationsEnabled').returns(true);
sandbox.stub(image, 'hasAnnotationCreatePermission').returns(true);

image.loadUI();
expect(image.annotationControls instanceof AnnotationControls).to.be.true;
});
});

Expand Down

0 comments on commit 11e8caf

Please sign in to comment.