Commit fa7c1a7f authored by Sean Hammond's avatar Sean Hammond Committed by GitHub

Merge pull request #349 from hypothesis/extract-annotation-action

Extract annotation action buttons into a separate component
parents 8e1dfb7a c3d85be7
......@@ -131,6 +131,7 @@ module.exports = angular.module('h', [
// UI components
.component('annotation', require('./components/annotation'))
.component('annotationHeader', require('./components/annotation-header'))
.component('annotationActionButton', require('./components/annotation-action-button'))
.component('annotationShareDialog', require('./components/annotation-share-dialog'))
.component('annotationThread', require('./components/annotation-thread'))
.component('annotationViewerContent', require('./components/annotation-viewer-content'))
......
'use strict';
module.exports = {
controllerAs: 'vm',
bindings: {
icon: '<',
isDisabled: '<',
label: '<',
onClick: '&',
},
template: require('../templates/annotation-action-button.html'),
};
......@@ -24,6 +24,21 @@ function annotationComponent() {
});
}
/**
* Returns the controller for the action button with the given `label`.
*
* @param {Element} annotationEl - Annotation element
* @param {string} label - Button label
*/
function findActionButton(annotationEl, label) {
var btns = Array.from(annotationEl[0].querySelectorAll('annotation-action-button'));
var match = btns.find(function (btn) {
var ctrl = angular.element(btn).controller('annotationActionButton');
return ctrl.label === label;
});
return match ? angular.element(match).controller('annotationActionButton') : null;
}
describe('annotation', function() {
describe('updateModel()', function() {
var updateModel = require('../annotation').updateModel;
......@@ -105,10 +120,11 @@ describe('annotation', function() {
before(function() {
angular.module('h', [])
.component('annotation', annotationComponent())
.component('annotationActionButton', {
bindings: require('../annotation-action-button').bindings,
})
.component('markdown', {
bindings: {
customTextClass: '<?',
},
bindings: require('../markdown').bindings,
});
});
......@@ -983,25 +999,25 @@ describe('annotation', function() {
it('renders hidden annotations with a custom text class', function () {
var ann = fixtures.moderatedAnnotation({ hidden: true });
var el = createDirective(ann).element;
assert.deepEqual(el.find('markdown').controller('markdown'), {
assert.match(el.find('markdown').controller('markdown'), sinon.match({
customTextClass: {
'annotation-body is-hidden': true,
},
});
}));
});
it('flags the annotation when the user clicks the "Flag" button', function () {
fakeAnnotationMapper.flagAnnotation.returns(Promise.resolve());
var el = createDirective().element;
var flagBtn = el[0].querySelector('button[aria-label="Flag"]');
flagBtn.click();
var flagBtn = findActionButton(el, 'Flag');
flagBtn.onClick();
assert.called(fakeAnnotationMapper.flagAnnotation);
});
it('highlights the "Flag" button if the annotation is flagged', function () {
var ann = Object.assign(fixtures.defaultAnnotation(), { flagged: true });
var el = createDirective(ann).element;
var flaggedBtn = el[0].querySelector('button[aria-label="Annotation has been flagged"]');
var flaggedBtn = findActionButton(el, 'Annotation has been flagged');
assert.ok(flaggedBtn);
});
});
......
<button class="btn btn-clean annotation-action-btn"
ng-click="vm.onClick()"
ng-disabled="vm.isDisabled"
aria-label="{{ vm.label }}"
h-tooltip>
<i class="{{ vm.icon }} btn-icon"></i>
</button>
......@@ -109,37 +109,33 @@
<div class="annotation-actions" ng-if="!vm.isSaving && !vm.editing() && vm.id()">
<div ng-show="vm.isSaving">Saving…</div>
<button class="btn btn-clean annotation-action-btn"
<annotation-action-button
icon="'h-icon-annotation-edit'"
is-disabled="vm.isDeleted()"
label="'Edit'"
ng-show="vm.authorize('update') && !vm.isSaving"
ng-click="vm.edit()"
ng-disabled="vm.isDeleted()"
aria-label="Edit"
h-tooltip>
<i class="h-icon-annotation-edit btn-icon "></i>
</button>
<button class="btn btn-clean annotation-action-btn"
on-click="vm.edit()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-delete'"
is-disabled="vm.isDeleted()"
label="'Delete'"
ng-show="vm.authorize('delete')"
ng-click="vm.delete()"
ng-disabled="vm.isDeleted()"
aria-label="Delete"
h-tooltip>
<i class="h-icon-annotation-delete btn-icon "></i>
</button>
<button class="btn btn-clean annotation-action-btn"
ng-click="vm.reply()"
ng-disabled="vm.isDeleted()"
aria-label="Reply"
h-tooltip>
<i class="h-icon-annotation-reply btn-icon "></i>
</button>
on-click="vm.delete()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-reply'"
is-disabled="vm.isDeleted()"
label="'Reply'"
on-click="vm.reply()"
></annotation-action-button>
<span class="annotation-share-dialog-wrapper">
<button class="btn btn-clean annotation-action-btn"
ng-click="vm.showShareDialog = true"
ng-disabled="vm.isDeleted()"
aria-label="Share"
h-tooltip>
<i class="h-icon-annotation-share btn-icon "></i>
</button>
<annotation-action-button
icon="'h-icon-annotation-share'"
is-disabled="vm.isDeleted()"
label="'Share'"
on-click="vm.showShareDialog = true"
></annotation-action-button>
<annotation-share-dialog
group="vm.group()"
uri="vm.incontextLink()"
......@@ -149,21 +145,19 @@
</annotation-share-dialog>
</span>
<span ng-if="vm.canFlag()">
<button class="btn btn-clean annotation-action-btn"
ng-if="!vm.isFlagged()"
ng-click="vm.flag()"
ng-disabled="vm.isDeleted()"
aria-label="Flag"
h-tooltip>
<i class="h-icon-annotation-flag btn-icon"></i>
</button>
<button class="btn btn-clean annotation-action-btn"
ng-if="vm.isFlagged()"
ng-disabled="vm.isDeleted()"
aria-label="Annotation has been flagged"
h-tooltip>
<i class="h-icon-annotation-flag annotation--flagged btn-icon"></i>
</button>
<annotation-action-button
icon="'h-icon-annotation-flag'"
is-disabled="vm.isDeleted()"
label="'Flag'"
ng-if="!vm.isFlagged()"
on-click="vm.flag()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-flag annotation--flagged'"
is-disabled="vm.isDeleted()"
label="'Annotation has been flagged'"
ng-if="vm.isFlagged()"
></annotation-action-button>
</span>
</div>
</footer>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment