Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: drawing dialog #364

Merged
merged 21 commits into from
Sep 8, 2017
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ annotation_highlight_toggle=Highlight text
annotation_highlight_comment=Add comment to highlighted text
# Text for which user made the highlight annotation
annotation_who_highlighted={1} highlighted
# Text for which user made the drawn annotation
annotation_who_drew={1} drew
# Accessibilty text for button that soft commits drawing
annotation_draw_save=Save drawing
# Accessibilty text for button that soft deletes drawing
annotation_draw_delete=Delete drawing
# Text for when annotations fail to load
annotations_load_error=We're sorry, annotations failed to load for this file.
# Text for when the annotation can't be created
Expand Down
7 changes: 7 additions & 0 deletions src/lib/annotations/AnnotationModeController.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ class AnnotationModeController extends EventEmitter {
this.threads = this.threads.filter((item) => item !== thread);
}

/**
* Clean up the annotation selector
*
* @return {void}
*/
cleanSelector() {}

/**
* Binds custom event listeners for a thread.
*
Expand Down
16 changes: 8 additions & 8 deletions src/lib/annotations/Annotator.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ class Annotator extends EventEmitter {
const buttonEl = event.target || this.getAnnotateButton(buttonSelector);

// Exit any other annotation mode
this.exitAnnotationModes(mode, buttonEl);
this.exitAnnotationModesExcept(mode);

// If in annotation mode, turn it off
if (this.isInAnnotationMode(mode)) {
Expand Down Expand Up @@ -413,8 +413,6 @@ class Annotator extends EventEmitter {
annotatorUtil.hideElement(postButtonEl);
annotatorUtil.hideElement(undoButtonEl);
annotatorUtil.hideElement(redoButtonEl);
annotatorUtil.disableElement(undoButtonEl);
annotatorUtil.disableElement(redoButtonEl);
}
}

Expand Down Expand Up @@ -458,18 +456,20 @@ class Annotator extends EventEmitter {
* Exits all annotation modes except the specified mode
*
* @param {string} mode - Current annotation mode
* @param {HTMLElement} buttonEl - Annotation mode button DOM element
* @return {void}
*/
exitAnnotationModes(mode, buttonEl) {
exitAnnotationModesExcept(mode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe exitInactiveAnnotationModes?

Object.keys(this.modeButtons).forEach((type) => {
if (mode === type) {
return;
}

const buttonSelector = this.modeButtons[type].selector;
const modeButtonEl = buttonEl || this.getAnnotateButton(buttonSelector);
this.disableAnnotationMode(type, modeButtonEl);
if (!this.modeButtons[type].button) {
this.modeButtons[type].button = this.getAnnotateButton(buttonSelector);
}

this.disableAnnotationMode(type, this.modeButtons[type].button);
});
}

Expand Down Expand Up @@ -543,7 +543,7 @@ class Annotator extends EventEmitter {
// Do not load any pre-existing annotations if the user does not have
// the correct permissions
if (!this.permissions.canViewAllAnnotations || !this.permissions.canViewOwnAnnotations) {
return this.threads;
return Promise.resolve(this.threads);
}

return this.annotationService.getThreadMap(this.fileVersionId).then((threadMap) => {
Expand Down
12 changes: 12 additions & 0 deletions src/lib/annotations/Annotator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ $avatar-color-9: #f22c44;
}
}

.bp-annotation-drawing-dialog,
.bp-annotation-highlight-dialog .bp-btn-plain,
.bp-annotation-highlight-dialog .bp-btn-plain:hover {
padding-left: 5px;
Expand Down Expand Up @@ -360,6 +361,7 @@ $avatar-color-9: #f22c44;
}
}

.bp-annotation-drawing-dialog,
.bp-annotation-highlight-dialog,
.bp-annotation-highlight-dialog:hover {
background-color: $white;
Expand All @@ -372,6 +374,15 @@ $avatar-color-9: #f22c44;
padding-top: 1px;
}

.bp-btn-annotate-draw-add {
padding-bottom: 3px;
padding-right: 6px;
}

.bp-btn-annotate-draw-delete {
padding-bottom: 3px;
}

.bp-highlight-comment-btn {
padding-top: 3px;
}
Expand Down Expand Up @@ -428,6 +439,7 @@ $avatar-color-9: #f22c44;
}
}

.bp-annotation-drawing-label,
.bp-annotation-highlight-label {
padding-left: 5px;
padding-right: 5px;
Expand Down
22 changes: 21 additions & 1 deletion src/lib/annotations/__tests__/Annotator-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,31 @@ describe('lib/annotations/Annotator', () => {
});
});

describe('exitAnnotationModesExcept()', () => {
it('should call disableAnnotationMode on all modes except the specified one', () => {
annotator.modeButtons = {
'type1': {
selector: 'bogus',
button: 'button1'
},
'type2': {
selector: 'test',
button: 'button2'
}
};

sandbox.stub(annotator, 'disableAnnotationMode');
annotator.exitAnnotationModesExcept('type2');
expect(annotator.disableAnnotationMode).to.be.calledWith('type1', 'button1');
expect(annotator.disableAnnotationMode).to.not.be.calledWith('type2', 'button2');
});
});

describe('toggleAnnotationHandler()', () => {
beforeEach(() => {
stubs.destroyStub = sandbox.stub(annotator, 'destroyPendingThreads');
stubs.annotationMode = sandbox.stub(annotator, 'isInAnnotationMode');
stubs.exitModes = sandbox.stub(annotator, 'exitAnnotationModes');
stubs.exitModes = sandbox.stub(annotator, 'exitAnnotationModesExcept');
stubs.disable = sandbox.stub(annotator, 'disableAnnotationMode');
stubs.enable = sandbox.stub(annotator, 'enableAnnotationMode');
sandbox.stub(annotator, 'getAnnotateButton');
Expand Down
67 changes: 43 additions & 24 deletions src/lib/annotations/__tests__/annotatorUtil-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
getHeaders,
replacePlaceholders,
createLocation,
round
round,
prevDefAndStopProp
} from '../annotatorUtil';
import {
STATES,
Expand All @@ -36,6 +37,8 @@ import {

const DIALOG_WIDTH = 81;

const sandbox = sinon.sandbox.create();

describe('lib/annotations/annotatorUtil', () => {
let childEl;
let parentEl;
Expand All @@ -52,6 +55,7 @@ describe('lib/annotations/annotatorUtil', () => {
});

afterEach(() => {
sandbox.verifyAndRestore();
fixture.cleanup();
});

Expand Down Expand Up @@ -403,39 +407,54 @@ describe('lib/annotations/annotatorUtil', () => {
});

describe('eventToLocationHandler()', () => {
it('should not call the callback when the location is valid', () => {
const annotator = {
isChanged: false
}
const getLocation = ((event) => 'location');
const callback = ((location) => {
annotator.isChanged = true
});
const locationHandler = eventToLocationHandler(getLocation, callback);
let getLocation;
let annotator;
let callback;
let locationHandler;
let event;

beforeEach(() => {
getLocation = ((event) => 'location');
callback = sandbox.stub();
locationHandler = eventToLocationHandler(getLocation, callback);
event = {
preventDefault: () => {},
stopPropagation: () => {}
};
});

it('should not call the callback when the location is valid', () => {
locationHandler(undefined);
expect(annotator.isChanged).to.be.false;
expect(callback).to.not.be.called;
});

it('should call the callback when the location is valid', () => {
const annotator = {
isChanged: false
}
const getLocation = ((event) => 'location');
const callback = ((location) => {
annotator.isChanged = true
});
const locationHandler = eventToLocationHandler(getLocation, callback);
const event = {
preventDefault: () => {},
stopPropagation: () => {}
};
locationHandler(event);
expect(callback).to.be.calledWith('location');
});

it('should do nothing when the target exists and it is not the textLayer', () => {
event.target = {
className: 'button'
};
locationHandler(event);
expect(annotator.isChanged).to.be.true;
expect(callback).to.not.be.called;
});
});

describe('prevDefAndStopProp()', () => {
it('should prevent default and stop propogation on an event', () => {
const event = {
preventDefault: sandbox.stub(),
stopPropagation: sandbox.stub()
};

prevDefAndStopProp(event);
expect(event.preventDefault).to.be.called;
expect(event.stopPropagation).to.be.called;
})
});

describe('createLocation()', () => {
it('should create a location object without dimensions', () => {
const location = createLocation(1,2, undefined);
Expand Down
7 changes: 7 additions & 0 deletions src/lib/annotations/annotationConstants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const USER_ANONYMOUS = 'Anonymous';

export const CLASS_ACTIVE = 'bp-is-active';
export const CLASS_HIDDEN = 'bp-is-hidden';
export const CLASS_INVISIBLE = 'bp-is-invisible';
Expand Down Expand Up @@ -32,6 +34,11 @@ export const CLASS_ANNOTATION_BUTTON_DRAW_REDO = 'bp-btn-annotate-draw-redo';
export const CLASS_ANNOTATION_BUTTON_DRAW_POST = 'bp-btn-annotate-draw-post';
export const CLASS_ANNOTATION_BUTTON_DRAW_CANCEL = 'bp-btn-annotate-draw-cancel';
export const CLASS_ANNOTATION_BUTTON_DRAW_ENTER = 'bp-btn-annotate-draw-enter';
export const CLASS_ANNOTATION_DRAWING_LABEL = 'bp-annotation-drawing-label';
export const CLASS_ANNOTATION_DRAWING_DIALOG = 'bp-annotation-drawing-dialog';
export const CLASS_ANNOTATION_DRAWING_BTNS = 'bp-annotation-drawing-btns';
export const CLASS_ADD_DRAWING_BTN = 'bp-btn-annotate-draw-add';
export const CLASS_DELETE_DRAWING_BTN = 'bp-btn-annotate-draw-delete';

export const DATA_TYPE_ANNOTATION_DIALOG = 'annotation-dialog';
export const DATA_TYPE_ANNOTATION_INDICATOR = 'annotation-indicator';
Expand Down
19 changes: 17 additions & 2 deletions src/lib/annotations/annotatorUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ export function validateThreadParams(thread) {
}

/**
* Returns a function that passes a callback a location when given an event
* Returns a function that passes a callback a location when given an event on the document text layer
*
* @param {Function} locationFunction - The function to get a location from an event
* @param {Function} callback - Callback to be called upon receiving an event
Expand All @@ -448,7 +448,8 @@ export function validateThreadParams(thread) {
export function eventToLocationHandler(locationFunction, callback) {
return (event) => {
const evt = event || window.event;
if (!evt) {
// Do nothing when the target isn't the text layer in case the text layer receives event precedence over buttons
if (!evt || (event.target && event.target.className !== 'textLayer')) {
return;
}

Expand All @@ -459,6 +460,20 @@ export function eventToLocationHandler(locationFunction, callback) {
};
}

/**
* Call preventDefault and stopPropagation on an event
*
* @param {event} event - Event object to stop event bubbling
* @return {void}
*/
export function prevDefAndStopProp(event) {
if (!event) {
return;
}

event.preventDefault();
event.stopPropagation();
}
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline after the block!

* Create a JSON object containing x/y coordinates and optionally dimensional information
*
Expand Down
10 changes: 10 additions & 0 deletions src/lib/annotations/doc/DocAnnotator.js
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ class DocAnnotator extends Annotator {
bindDOMListeners() {
super.bindDOMListeners();

if (!this.permissions.canAnnotate) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment on #362

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove

return;
}

this.annotatedElement.addEventListener('mouseup', this.highlightMouseupHandler);

if (this.hasTouch && this.isMobile) {
Expand Down Expand Up @@ -485,6 +489,12 @@ class DocAnnotator extends Annotator {
this.highlightThrottleHandle = null;
}

if (!this.permissions.canAnnotate) {
return;
}

Object.values(this.modeControllers).forEach((controller) => controller.cleanSelector());

if (this.hasTouch && this.isMobile) {
document.removeEventListener('selectionchange', this.onSelectionChange);
this.annotatedElement.removeEventListener('touchstart', this.drawingSelectionHandler);
Expand Down
Loading