Skip to content

Commit

Permalink
New: Draw annotations UI (#403)
Browse files Browse the repository at this point in the history
* Chore: turning on drawing

* New: Updating draw UI

* Chore: Adding unit tests

* Chore: Fix header buttons and update doc background when drawing
  • Loading branch information
Jeremy Press authored Sep 25, 2017
1 parent 54fa047 commit 4cbfc0f
Show file tree
Hide file tree
Showing 18 changed files with 255 additions and 70 deletions.
22 changes: 21 additions & 1 deletion src/lib/PreviewUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { insertTemplate } from './util';
import {
CLASS_HIDDEN,
CLASS_INVISIBLE,
CLASS_BOX_PREVIEW_BASE_HEADER,
CLASS_BOX_PREVIEW_HAS_HEADER,
CLASS_BOX_PREVIEW_HEADER,
CLASS_BOX_PREVIEW_THEME_DARK,
Expand Down Expand Up @@ -311,6 +312,25 @@ class PreviewUI {
this.notification.hide();
}

/**
* Replaces the currently active header with a specified header
*
* @public
* @param {string} replacementHeader - Class name of new header
* @return {void}
*/
replaceHeader(replacementHeader) {
// First hide all possible headers
const headers = this.container.querySelectorAll(`.${CLASS_BOX_PREVIEW_HEADER}`);
[].forEach.call(headers, (header) => {
header.classList.add(CLASS_HIDDEN);
});

// Show the specified header
const headerToShow = this.container.querySelector(replacementHeader);
headerToShow.classList.remove(CLASS_HIDDEN);
}

//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
Expand All @@ -324,7 +344,7 @@ class PreviewUI {
*/
setupHeader(headerTheme, logoUrl) {
const headerEl = this.container.firstElementChild;
headerEl.className = CLASS_BOX_PREVIEW_HEADER;
headerEl.className = `${CLASS_BOX_PREVIEW_HEADER} ${CLASS_BOX_PREVIEW_BASE_HEADER}`;
this.contentContainer.classList.add(CLASS_BOX_PREVIEW_HAS_HEADER);

// Setup theme, default is 'light'
Expand Down
21 changes: 20 additions & 1 deletion src/lib/__tests__/PreviewUI-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('lib/PreviewUI', () => {
fixture.load('__tests__/PreviewUI-test.html');
containerEl = document.querySelector('.ui');
options = {
container: containerEl
container: containerEl,
};
});

Expand Down Expand Up @@ -247,4 +247,23 @@ describe('lib/PreviewUI', () => {
expect(ui.notification.hide).to.be.called;
});
});


describe('replaceHeader()', () => {
it('should hide all headers and then show the specified header', () => {
containerEl = ui.setup(options);
const newHeader = document.createElement('div');
newHeader.className = 'bp-header bp-draw-header bp-is-hidden';

containerEl.appendChild(newHeader);

ui.replaceHeader('.bp-draw-header');

expect(newHeader.classList.contains('bp-is-hidden')).to.be.false;

const baseHeader = containerEl.querySelector('.bp-base-header');
expect(baseHeader.classList.contains('bp-is-hidden')).to.be.true;

});
});
});
14 changes: 14 additions & 0 deletions src/lib/annotations/AnnotationModeController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import EventEmitter from 'events';
import { insertTemplate } from './annotatorUtil';

class AnnotationModeController extends EventEmitter {
/** @property {Array} - The array of annotation threads */
Expand Down Expand Up @@ -171,6 +172,19 @@ class AnnotationModeController extends EventEmitter {
type
});
}

/**
* Setups the header for the annotation mode
*
* @protected
* @param {HTMLElement} container - Container element
* @param {HTMLElement} header - Header to add to DOM
* @return {void}
*/
setupHeader(container, header) {
const baseHeaderEl = container.firstElementChild;
insertTemplate(container, header, baseHeaderEl);
}
}

export default AnnotationModeController;
34 changes: 7 additions & 27 deletions src/lib/annotations/Annotator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@ import './Annotator.scss';
import {
CLASS_ACTIVE,
CLASS_HIDDEN,
SELECTOR_BOX_PREVIEW_BASE_HEADER,
DATA_TYPE_ANNOTATION_DIALOG,
CLASS_MOBILE_ANNOTATION_DIALOG,
CLASS_ANNOTATION_DIALOG,
CLASS_ANNOTATION_MODE,
CLASS_ANNNOTATION_DRAWING_BACKGROUND,
CLASS_MOBILE_DIALOG_HEADER,
CLASS_DIALOG_CLOSE,
ID_MOBILE_ANNOTATION_DIALOG,
SELECTOR_ANNOTATION_BUTTON_DRAW_CANCEL,
SELECTOR_ANNOTATION_BUTTON_DRAW_ENTER,
SELECTOR_ANNOTATION_BUTTON_DRAW_POST,
SELECTOR_ANNOTATION_BUTTON_DRAW_UNDO,
SELECTOR_ANNOTATION_BUTTON_DRAW_REDO,
SELECTOR_ANNOTATION_DRAWING_HEADER,
TYPES,
THREAD_EVENT,
ANNOTATOR_EVENT
Expand Down Expand Up @@ -414,17 +412,8 @@ class Annotator extends EventEmitter {
buttonEl.classList.remove(CLASS_ACTIVE);

if (mode === TYPES.draw) {
const drawEnterEl = buttonEl.querySelector(SELECTOR_ANNOTATION_BUTTON_DRAW_ENTER);
const drawCancelEl = buttonEl.querySelector(SELECTOR_ANNOTATION_BUTTON_DRAW_CANCEL);
const postButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_POST);
const undoButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_UNDO);
const redoButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_REDO);

annotatorUtil.showElement(drawEnterEl);
annotatorUtil.hideElement(drawCancelEl);
annotatorUtil.hideElement(postButtonEl);
annotatorUtil.hideElement(undoButtonEl);
annotatorUtil.hideElement(redoButtonEl);
this.annotatedElement.classList.remove(CLASS_ANNNOTATION_DRAWING_BACKGROUND);
this.emit(ANNOTATOR_EVENT.replaceHeader, SELECTOR_BOX_PREVIEW_BASE_HEADER);
}
}

Expand All @@ -446,17 +435,8 @@ class Annotator extends EventEmitter {
buttonEl.classList.add(CLASS_ACTIVE);

if (mode === TYPES.draw) {
const drawEnterEl = buttonEl.querySelector(SELECTOR_ANNOTATION_BUTTON_DRAW_ENTER);
const drawCancelEl = buttonEl.querySelector(SELECTOR_ANNOTATION_BUTTON_DRAW_CANCEL);
const postButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_POST);
const undoButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_UNDO);
const redoButtonEl = this.getAnnotateButton(SELECTOR_ANNOTATION_BUTTON_DRAW_REDO);

annotatorUtil.hideElement(drawEnterEl);
annotatorUtil.showElement(drawCancelEl);
annotatorUtil.showElement(postButtonEl);
annotatorUtil.showElement(undoButtonEl);
annotatorUtil.showElement(redoButtonEl);
this.annotatedElement.classList.add(CLASS_ANNNOTATION_DRAWING_BACKGROUND);
this.emit(ANNOTATOR_EVENT.replaceHeader, SELECTOR_ANNOTATION_DRAWING_HEADER);
}
}

Expand Down
72 changes: 66 additions & 6 deletions src/lib/annotations/Annotator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,71 @@ $avatar-color-7: #159f45;
$avatar-color-8: #b800b2;
$avatar-color-9: #f22c44;

$tablet: 'max-width: 768px';

.bp-annotate-draw-background {
background-color: $fours;
}

.bp-annotate-draw-header {
background-color: $twos;
border: none;
position: relative;
}

.bp-btn-annotate-draw-cancel {
background-color: $twos;
border: solid $off-white 1px;
color: $off-white;

&:hover {
background-color: $black;
}
}

.bp-btn-annotate-draw-post {
background-color: $off-white;
color: $twos;

&:hover {
background-color: $white;
}
}

.bp-annotate-draw-post-cancel-container {
margin-right: 20px;
position: absolute;
right: 0;
top: 0;

button {
height: 32px;
margin: 8px;
}
}

.bp-annotate-draw-undo-redo-container {
margin: 0 auto;

.bp-btn-annotate-draw-undo,
.bp-btn-annotate-draw-redo {
background: none;
border: none;
margin: 5px;

svg {
fill: $off-white;
vertical-align: middle;
}
}
}

@media (max-width: 768px) {
.bp-annotate-draw-undo-redo-container {
margin: 0;
}
}

.bp-annotation-caret {
left: 50%;
position: absolute;
Expand Down Expand Up @@ -381,12 +446,7 @@ $avatar-color-9: #f22c44;
}

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

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

.bp-highlight-comment-btn {
Expand Down
15 changes: 15 additions & 0 deletions src/lib/annotations/__tests__/AnnotationModeController-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AnnotationModeController from '../AnnotationModeController';
import * as util from '../annotatorUtil';

let annotationModeController;
let stubs;
Expand Down Expand Up @@ -156,4 +157,18 @@ describe('lib/annotations/AnnotationModeController', () => {
});
});
});

describe('setupHeader()', () => {
it('should insert the new header into the container before the baseheader', () => {
stubs.insertTemplate = sandbox.stub(util, 'insertTemplate');
const container = {
firstElementChild: 'child'
};
const header = document.createElement('div');

annotationModeController.setupHeader(container, header);

expect(stubs.insertTemplate).to.be.calledWith(container, header);
});
});
});
12 changes: 4 additions & 8 deletions src/lib/annotations/__tests__/Annotator-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
SELECTOR_ANNOTATION_BUTTON_DRAW_POST,
SELECTOR_ANNOTATION_BUTTON_DRAW_UNDO,
SELECTOR_ANNOTATION_BUTTON_DRAW_REDO,
SELECTOR_ANNOTATION_DRAWING_HEADER,
SELECTOR_BOX_PREVIEW_BASE_HEADER,
ANNOTATOR_EVENT,
THREAD_EVENT
} from '../annotationConstants';
Expand Down Expand Up @@ -388,8 +390,6 @@ describe('lib/annotations/Annotator', () => {
stubs.emit = sandbox.stub(annotator, 'emit');
stubs.unbindMode = sandbox.stub(annotator, 'unbindModeListeners');
stubs.bindDOM = sandbox.stub(annotator, 'bindDOMListeners');
stubs.hide = sandbox.stub(annotatorUtil, 'hideElement');
stubs.show = sandbox.stub(annotatorUtil, 'showElement');
});

it('should do nothing when the mode is not annotatable', () => {
Expand Down Expand Up @@ -419,8 +419,7 @@ describe('lib/annotations/Annotator', () => {
const btn = document.querySelector('.bp-btn-annotate');
annotator.disableAnnotationMode(TYPES.draw, btn);
expect(btn).to.not.have.class(CLASS_ACTIVE);
expect(stubs.show).to.be.called;
expect(stubs.hide).to.have.callCount(4);
expect(stubs.emit).to.be.calledWith(ANNOTATOR_EVENT.replaceHeader, SELECTOR_BOX_PREVIEW_BASE_HEADER);
});
});

Expand All @@ -429,8 +428,6 @@ describe('lib/annotations/Annotator', () => {
stubs.emit = sandbox.stub(annotator, 'emit');
stubs.unbindDOM = sandbox.stub(annotator, 'unbindDOMListeners');
stubs.bindMode = sandbox.stub(annotator, 'bindModeListeners');
stubs.hide = sandbox.stub(annotatorUtil, 'hideElement');
stubs.show = sandbox.stub(annotatorUtil, 'showElement');
});

it('should enter annotation mode', () => {
Expand All @@ -451,8 +448,7 @@ describe('lib/annotations/Annotator', () => {
const btn = document.querySelector('.bp-btn-annotate');
annotator.enableAnnotationMode(TYPES.draw, btn);
expect(btn).to.have.class(CLASS_ACTIVE);
expect(stubs.hide).to.be.called;
expect(stubs.show).to.have.callCount(4);
expect(stubs.emit).to.be.calledWith(ANNOTATOR_EVENT.replaceHeader, SELECTOR_ANNOTATION_DRAWING_HEADER);
});
});

Expand Down
2 changes: 2 additions & 0 deletions src/lib/annotations/__tests__/annotatorUtil-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@
<div class="bp-annotation-dialog">
<div class="bp-annotation-caret"></div>
</div>

<div class="container"></div>
14 changes: 13 additions & 1 deletion src/lib/annotations/__tests__/annotatorUtil-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {
createLocation,
round,
prevDefAndStopProp,
canLoadAnnotations
canLoadAnnotations,
insertTemplate
} from '../annotatorUtil';
import {
STATES,
Expand Down Expand Up @@ -222,6 +223,17 @@ describe('lib/annotations/annotatorUtil', () => {
});
});


describe('insertTemplate()', () => {
it('should insert template into node', () => {
const node = document.createElement('div');
document.querySelector('.container').appendChild(node);

insertTemplate(node, '<div class="foo"></div>');
assert.equal(node.firstElementChild.className, 'foo');
});
});

describe('isElementInViewport()', () => {
it('should return true for an element fully in the viewport', () => {
assert.ok(isElementInViewport(childEl));
Expand Down
8 changes: 7 additions & 1 deletion src/lib/annotations/annotationConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const CLASS_ANNOTATION_POINT_MARKER = 'bp-point-annotation-marker';
export const CLASS_ANNOTATION_MODE = 'bp-annotation-mode';
export const CLASS_ANNOTATION_CARET = 'bp-annotation-caret';
export const CLASS_ANNOTATION_TEXTAREA = 'annotation-textarea';
export const CLASS_BOX_PREVIEW_BASE_HEADER = 'bp-base-header';
export const CLASS_BUTTON_CONTAINER = 'button-container';
export const CLASS_ANNOTATION_CONTAINER = 'annotation-container';
export const CLASS_ANIMATE_DIALOG = 'bp-animate-show-dialog';
Expand All @@ -37,6 +38,8 @@ 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_ANNOTATION_DRAWING_HEADER = 'bp-annotate-draw-header';
export const CLASS_ANNNOTATION_DRAWING_BACKGROUND = 'bp-annotate-draw-background';
export const CLASS_ADD_DRAWING_BTN = 'bp-btn-annotate-draw-add';
export const CLASS_DELETE_DRAWING_BTN = 'bp-btn-annotate-draw-delete';

Expand All @@ -56,6 +59,7 @@ export const DATA_TYPE_CONFIRM_DELETE = 'confirm-delete-btn';
export const SECTION_CREATE = '[data-section="create"]';
export const SECTION_SHOW = '[data-section="show"]';

export const SELECTOR_BOX_PREVIEW_BASE_HEADER = `.${CLASS_BOX_PREVIEW_BASE_HEADER}`;
export const SELECTOR_ANNOTATION_BUTTON_POINT = `.${CLASS_ANNOTATION_BUTTON_POINT}`;
export const SELECTOR_ANNOTATION_BUTTON_DRAW_UNDO = `.${CLASS_ANNOTATION_BUTTON_DRAW_UNDO}`;
export const SELECTOR_ANNOTATION_BUTTON_DRAW_REDO = `.${CLASS_ANNOTATION_BUTTON_DRAW_REDO}`;
Expand All @@ -64,6 +68,7 @@ export const SELECTOR_ANNOTATION_BUTTON_DRAW_CANCEL = `.${CLASS_ANNOTATION_BUTTO
export const SELECTOR_ANNOTATION_BUTTON_DRAW_ENTER = `.${CLASS_ANNOTATION_BUTTON_DRAW_ENTER}`;
export const SELECTOR_ANNOTATION_BUTTON_CANCEL = `.${CLASS_ANNOTATION_BUTTON_CANCEL}`;
export const SELECTOR_ANNOTATION_BUTTON_POST = `.${CLASS_ANNOTATION_BUTTON_POST}`;
export const SELECTOR_ANNOTATION_DRAWING_HEADER = `.${CLASS_ANNOTATION_DRAWING_HEADER}`;
export const SELECTOR_ANNOTATION_DIALOG = `.${CLASS_ANNOTATION_DIALOG}`;
export const SELECTOR_ANNOTATION_HIGHLIGHT_DIALOG = `.${CLASS_ANNOTATION_HIGHLIGHT_DIALOG}`;
export const SELECTOR_ANNOTATION_POINT_BUTTON = `.${CLASS_ANNOTATION_POINT_MARKER}`;
Expand Down Expand Up @@ -114,7 +119,8 @@ export const ANNOTATOR_EVENT = {
modeExit: 'annotationmodeexit',
fetch: 'annotationsfetched',
error: 'annotationerror',
scale: 'scaleannotations'
scale: 'scaleannotations',
replaceHeader: 'replaceheader'
};

export const THREAD_EVENT = {
Expand Down
Loading

0 comments on commit 4cbfc0f

Please sign in to comment.