Commit 58d19bf0 authored by Robert Knight's avatar Robert Knight

Merge pull request #2762 from hypothesis/2728-refactor-highlight-saving

Refactor saving highlights in AnnotationController
parents 696909f7 6b10b936
......@@ -186,7 +186,81 @@ function AnnotationController(
// Set the permissions of new annotations.
model.permissions = model.permissions || permissions['default'](model.group);
var highlight = model.$highlight;
/**
* `true` if this AnnotationController instance was created as a result of
* the highlight button being clicked.
*
* `false` if the annotation button was clicked, or if this is a highlight or
* annotation that was fetched from the server (as opposed to created new
* client-side).
*/
var newlyCreatedByHighlightButton = model.$highlight || false;
/**
* @ngdoc method
* @name annotation.AnnotationController#isHighlight.
* @returns {boolean} true if the annotation is a highlight, false otherwise
*/
vm.isHighlight = function() {
if (newlyCreatedByHighlightButton) {
return true;
} else if (!model.id) {
// If an annotation has no model.id (i.e. it has not been saved to the
// server yet) and newlyCreatedByHighlightButton is false, then it must
// be an annotation not a highlight (even though it may not have any
// text or tags yet).
return false;
} else {
// Once an annotation has been saved to the server there's no longer a
// simple property that says whether it's a highlight or not. For
// example there's no model.highlight: true. Instead a highlight is
// defined as an annotation that isn't a page note or a reply and that
// has no text or tags.
var isPageNote = (model.target || []).length === 0;
var isReply = (model.references || []).length !== 0;
return (!isPageNote && !isReply && !vm.hasContent());
}
};
/** Save this annotation if it's a new highlight.
*
* The highlight will be saved to the server if the user is logged in,
* saved to drafts if they aren't.
*
* If the annotation is not new (it has already been saved to the server) or
* is not a highlight then nothing will happen.
*
*/
function saveNewHighlight() {
if (model.id) {
// Already saved.
return;
}
if (!vm.isHighlight()) {
// Not a highlight,
return;
}
if (model.user) {
// User is logged in, save to server.
// Highlights are always private.
model.permissions = permissions.private();
model.$create().then(function() {
$rootScope.$emit('annotationCreated', model);
});
} else {
// User isn't logged in, save to drafts.
updateDraft(model);
}
}
// Automatically save new highlights to the server when they're created.
// Note that this line also gets called when the user logs in (since
// AnnotationController instances are re-created on login) so serves to
// automatically save highlights that were created while logged out when you
// log in.
saveNewHighlight();
/**
* @ngdoc method
......@@ -229,18 +303,6 @@ function AnnotationController(
return $q.when(tags.filter(query));
};
/**
* @ngdoc method
* @name annotation.AnnotationController#isHighlight.
* @returns {boolean} True if the annotation is a highlight.
*/
vm.isHighlight = function() {
var targetLength = (model.target || []).length;
var referencesLength = (model.references || []).length;
var tagsLength = (model.tags || []).length;
return (targetLength && !referencesLength && !(model.text || tagsLength));
};
/**
* @ngdoc method
* @name annotation.AnnotationController#isPrivate
......@@ -302,8 +364,8 @@ function AnnotationController(
/**
* @ngdoc method
* @name annotation.AnnotaitonController#hasContent
* @returns {boolean} True if the currently edited annotation has
* content (ie. is not just a highlight)
* @returns {boolean} `true` if this annotation has content, `false`
* otherwise.
*/
vm.hasContent = function() {
var textLength = (vm.annotation.text || '').length;
......@@ -573,19 +635,6 @@ function AnnotationController(
drafts.remove(model);
}
// Save highlights once logged in.
if (vm.isHighlight() && highlight) {
if (model.user && !model.id) {
model.permissions = permissions.private();
model.$create().then(function() {
$rootScope.$emit('annotationCreated', model);
});
highlight = false; // Prevents double highlight creation.
} else {
updateDraft(model);
}
}
updateTimestamp(model === old); // Repeat on first run.
vm.render();
}, true);
......@@ -604,11 +653,13 @@ function AnnotationController(
}
});
// If this is a new annotation or we have unsaved changes,
// then start editing immediately.
var isNewAnnotation = !(model.id || (vm.isHighlight() && highlight));
if (isNewAnnotation || drafts.get(model)) {
vm.edit();
// If this annotation is not a highlight and if it's new (has just been
// created by the annotate button) or it has edits not yet saved to the
// server - then open the editor on AnnotationController instantiation.
if (!newlyCreatedByHighlightButton) {
if (!model.id || drafts.get(model)) {
vm.edit();
}
}
// When the current group changes, persist any unsaved changes using
......
......@@ -303,7 +303,6 @@ describe('annotation.js', function() {
var $scope;
var $timeout;
var $window;
var annotation;
var fakeAnnotationMapper;
var fakeAnnotationUI;
var fakeDocumentDomainFilter;
......@@ -321,19 +320,118 @@ describe('annotation.js', function() {
var fakeUrlEncodeFilter;
var sandbox;
function createDirective() {
function createDirective(annotation) {
annotation = annotation || defaultAnnotation();
$scope.annotation = annotation;
var element = angular.element('<div annotation="annotation">');
compileService()(element)($scope);
$scope.$digest();
var controller = element.controller('annotation');
var scope = element.isolateScope();
return {
annotation: annotation,
controller: controller,
element: element,
scope: scope
};
}
/** Return the default domain model object that createDirective() uses if
* no custom one is passed to it. */
function defaultAnnotation() {
return {
id: 'deadbeef',
document: {
title: 'A special document'
},
target: [{}],
uri: 'http://example.com',
user: 'acct:bill@localhost'
};
}
/** Return an annotation domain model object for a new annotation
* (newly-created client-side, not yet saved to the server).
*/
function newAnnotation() {
// A new annotation won't have any saved drafts yet.
fakeDrafts.get.returns(null);
return {
id: undefined,
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: 'Annotation text',
tags: ['tag_1', 'tag_2']
};
}
/** Return an annotation domain model object for a new highlight
* (newly-created client-side, not yet saved to the server).
*/
function newHighlight() {
// A new highlight won't have any saved drafts yet.
fakeDrafts.get.returns(null);
return {
id: undefined,
$highlight: true
};
}
/** Return an annotation domain model object for an existing annotation
* received from the server.
*/
function oldAnnotation() {
return {
id: 'annotation_id',
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: 'This is my annotation',
tags: ['tag_1', 'tag_2']
};
}
/** Return an annotation domain model object for an existing highlight
* received from the server.
*/
function oldHighlight() {
return {
id: 'annotation_id',
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: '',
tags: []
};
}
/** Return an annotation domain model object for an existing page note
* received from the server.
*/
function oldPageNote() {
return {
highlight: undefined,
target: [],
references: [],
text: '',
tags: []
};
}
/** Return an annotation domain model object for an existing reply
* received from the server.
*/
function oldReply() {
return {
highlight: undefined,
target: ['foo'],
references: ['parent_annotation_id'],
text: '',
tags: []
};
}
before(function() {
angular.module('h', [])
.directive('annotation', require('../annotation').directive);
......@@ -453,15 +551,6 @@ describe('annotation.js', function() {
$timeout = _$timeout_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$scope.annotation = annotation = {
id: 'deadbeef',
document: {
title: 'A special document'
},
target: [{}],
uri: 'http://example.com',
user: 'acct:bill@localhost'
};
}
)
);
......@@ -470,6 +559,112 @@ describe('annotation.js', function() {
sandbox.restore();
});
describe('AnnotationController() initialization', function() {
it('saves new highlights to the server on initialization', function() {
var annotation = newHighlight();
// The user is logged-in.
annotation.user = fakeSession.state.userid = 'acct:bill@localhost';
annotation.$create = sandbox.stub().returns({
then: function() {}
});
createDirective(annotation);
assert.called(annotation.$create);
});
it('saves new highlights to drafts if not logged in', function() {
var annotation = newHighlight();
// The user is not logged-in.
annotation.user = fakeSession.state.userid = undefined;
annotation.$create = sandbox.stub().returns({
then: function() {}
});
createDirective(annotation);
assert.notCalled(annotation.$create);
assert.called(fakeDrafts.update);
});
it('does not save new annotations on initialization', function() {
var annotation = newAnnotation();
annotation.$create = sandbox.stub().returns({
then: function() {}
});
createDirective(annotation);
assert.notCalled(annotation.$create);
});
it('does not save old highlights on initialization', function() {
var annotation = oldHighlight();
annotation.$create = sandbox.stub().returns({
then: function() {}
});
createDirective(annotation);
assert.notCalled(annotation.$create);
});
it('does not save old annotations on initialization', function() {
var annotation = oldAnnotation();
annotation.$create = sandbox.stub().returns({
then: function() {}
});
createDirective(annotation);
assert.notCalled(annotation.$create);
});
it('edits new annotations on initialization', function() {
var annotation = newAnnotation();
var controller = createDirective(annotation).controller;
assert.isTrue(controller.editing());
});
it('edits annotations with drafts on initialization', function() {
var annotation = oldAnnotation();
// The drafts service has some draft changes for this annotation.
fakeDrafts.get.returns('foo');
var controller = createDirective(annotation).controller;
assert.isTrue(controller.editing());
});
it('does not edit new highlights on initialization', function() {
var annotation = newHighlight();
// We have to set annotation.$create() because it'll try to call it.
annotation.$create = sandbox.stub().returns({
then: function() {}
});
var controller = createDirective(annotation).controller;
assert.isFalse(controller.editing());
});
it('edits highlights with drafts on initialization', function() {
var annotation = oldHighlight();
// You can edit a highlight, enter some text or tags, and save it (the
// highlight then becomes an annotation). You can also edit a highlight
// and then change focus to another group and back without saving the
// highlight, in which case the highlight will have draft edits.
// This highlight has draft edits.
fakeDrafts.get.returns('foo');
var controller = createDirective(annotation).controller;
assert.isTrue(controller.editing());
});
});
describe('AnnotationController.editing()', function() {
it('returns true if action is "create"', function() {
var controller = createDirective().controller;
......@@ -490,8 +685,77 @@ describe('annotation.js', function() {
});
});
describe('AnnotationController.isHighlight()', function() {
it('returns true for new highlights', function() {
var annotation = newHighlight();
// We need to define $create because it'll try to call it.
annotation.$create = function() {return {then: function() {}};};
var vm = createDirective(annotation).controller;
assert.isTrue(vm.isHighlight());
});
it('returns false for new annotations', function() {
var annotation = newAnnotation();
var vm = createDirective(annotation).controller;
assert.isFalse(vm.isHighlight());
});
it('returns false for page notes', function() {
var annotation = oldPageNote();
var vm = createDirective(annotation).controller;
assert.isFalse(vm.isHighlight());
});
it('returns false for replies', function() {
var annotation = oldReply();
var vm = createDirective(annotation).controller;
assert.isFalse(vm.isHighlight());
});
it('returns false for annotations with text but no tags', function() {
var annotation = oldAnnotation();
annotation.text = 'This is my annotation';
annotation.tags = [];
var vm = createDirective(annotation).controller;
assert.isFalse(vm.isHighlight());
});
it('returns false for annotations with tags but no text', function() {
var annotation = oldAnnotation();
annotation.text = '';
annotation.tags = ['foo'];
var vm = createDirective(annotation).controller;
assert.isFalse(vm.isHighlight());
});
it('returns true for annotations with no text or tags', function() {
var annotation = oldAnnotation();
annotation.text = '';
annotation.tags = [];
var vm = createDirective(annotation).controller;
assert.isTrue(vm.isHighlight());
});
});
describe('when the annotation is a highlight', function() {
var annotation;
beforeEach(function() {
annotation = defaultAnnotation();
annotation.$highlight = true;
annotation.$create = sinon.stub().returns({
then: angular.noop,
......@@ -500,22 +764,9 @@ describe('annotation.js', function() {
});
});
it('persists upon login', function() {
delete annotation.id;
delete annotation.user;
fakeSession.state.userid = null;
createDirective();
$scope.$digest();
assert.notCalled(annotation.$create);
fakeSession.state.userid = 'acct:ted@wyldstallyns.com';
$scope.$broadcast(events.USER_CHANGED, {});
$scope.$digest();
assert.calledOnce(annotation.$create);
});
it('is private', function() {
delete annotation.id;
createDirective();
createDirective(annotation);
$scope.$digest();
assert.deepEqual(annotation.permissions, {
read: ['justme']
......@@ -524,7 +775,10 @@ describe('annotation.js', function() {
});
describe('#reply', function() {
var annotation;
beforeEach(function() {
annotation = defaultAnnotation();
annotation.permissions = {
read: ['acct:joe@localhost'],
update: ['acct:joe@localhost'],
......@@ -534,7 +788,7 @@ describe('annotation.js', function() {
});
it('creates a new reply with the proper uri and references', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
controller.reply();
var match = sinon.match({
references: [annotation.id],
......@@ -544,7 +798,7 @@ describe('annotation.js', function() {
});
it('makes the annotation shared if the parent is shared', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
var reply = {};
fakeAnnotationMapper.createAnnotation.returns(reply);
fakePermissions.isShared.returns(true);
......@@ -555,7 +809,7 @@ describe('annotation.js', function() {
});
it('makes the annotation shared if the parent is shared', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
$scope.annotation.group = 'my group';
$scope.annotation.permissions = {
read: ['my group']
......@@ -577,7 +831,7 @@ describe('annotation.js', function() {
it(
'does not add the world readable principal if the parent is private',
function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
var reply = {};
fakeAnnotationMapper.createAnnotation.returns(reply);
fakePermissions.isShared.returns(false);
......@@ -589,7 +843,7 @@ describe('annotation.js', function() {
);
it('sets the reply\'s group to be the same as its parent\'s', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
$scope.annotation.group = 'my group';
var reply = {};
fakeAnnotationMapper.createAnnotation.returns(reply);
......@@ -600,58 +854,58 @@ describe('annotation.js', function() {
describe('#setPrivacy', function() {
it('makes the annotation private when level is "private"', function() {
var controller = createDirective().controller;
annotation.$update = sinon.stub().returns(Promise.resolve());
controller.edit();
controller.setPrivacy('private');
return controller.save().then(function() {
var parts = createDirective();
parts.annotation.$update = sinon.stub().returns(Promise.resolve());
parts.controller.edit();
parts.controller.setPrivacy('private');
return parts.controller.save().then(function() {
// Verify that the permissions are updated once the annotation
// is saved.
assert.deepEqual(annotation.permissions, {
assert.deepEqual(parts.annotation.permissions, {
read: ['justme']
});
});
});
it('makes the annotation shared when level is "shared"', function() {
var controller = createDirective().controller;
annotation.$update = sinon.stub().returns(Promise.resolve());
controller.edit();
controller.setPrivacy('shared');
return controller.save().then(function() {
assert.deepEqual(annotation.permissions, {
var parts = createDirective();
parts.annotation.$update = sinon.stub().returns(Promise.resolve());
parts.controller.edit();
parts.controller.setPrivacy('shared');
return parts.controller.save().then(function() {
assert.deepEqual(parts.annotation.permissions, {
read: ['everybody']
});
});
});
it('saves the "shared" visibility level to localStorage', function() {
var controller = createDirective().controller;
annotation.$update = sinon.stub().returns(Promise.resolve());
controller.edit();
controller.setPrivacy('shared');
return controller.save().then(function() {
var parts = createDirective();
parts.annotation.$update = sinon.stub().returns(Promise.resolve());
parts.controller.edit();
parts.controller.setPrivacy('shared');
return parts.controller.save().then(function() {
assert(fakePermissions.setDefault.calledWithExactly('shared'));
});
});
it('saves the "private" visibility level to localStorage', function() {
var controller = createDirective().controller;
annotation.$update = sinon.stub().returns(Promise.resolve());
controller.edit();
controller.setPrivacy('private');
return controller.save().then(function() {
var parts = createDirective();
parts.annotation.$update = sinon.stub().returns(Promise.resolve());
parts.controller.edit();
parts.controller.setPrivacy('private');
return parts.controller.save().then(function() {
assert(fakePermissions.setDefault.calledWithExactly('private'));
});
});
it('doesn\'t save the visibility if the annotation is a reply', function() {
var controller = createDirective().controller;
annotation.$update = sinon.stub().returns(Promise.resolve());
annotation.references = ['parent id'];
controller.edit();
controller.setPrivacy('private');
return controller.save().then(function() {
var parts = createDirective();
parts.annotation.$update = sinon.stub().returns(Promise.resolve());
parts.annotation.references = ['parent id'];
parts.controller.edit();
parts.controller.setPrivacy('private');
return parts.controller.save().then(function() {
assert(!fakePermissions.setDefault.called);
});
});
......@@ -707,15 +961,15 @@ describe('annotation.js', function() {
});
it('is called exactly once on model changes', function() {
var controller = createDirective().controller;
sandbox.spy(controller, 'render');
assert.notCalled(controller.render);
annotation['delete'] = true;
var parts = createDirective();
sandbox.spy(parts.controller, 'render');
assert.notCalled(parts.controller.render);
parts.annotation['delete'] = true;
$scope.$digest();
assert.calledOnce(controller.render);
annotation.booz = 'baz';
assert.calledOnce(parts.controller.render);
parts.annotation.booz = 'baz';
$scope.$digest();
assert.calledTwice(controller.render);
assert.calledTwice(parts.controller.render);
});
it('provides a document title', function() {
......@@ -725,18 +979,18 @@ describe('annotation.js', function() {
});
it('uses the first title when there are more than one', function() {
var controller = createDirective().controller;
annotation.document.title = ['first title', 'second title'];
controller.render();
assert.equal(controller.document.title, 'first title');
var parts = createDirective();
parts.annotation.document.title = ['first title', 'second title'];
parts.controller.render();
assert.equal(parts.controller.document.title, 'first title');
});
it('truncates long titles', function() {
var controller = createDirective().controller;
annotation.document.title = 'A very very very long title that really\nshouldn\'t be found on a page on the internet.';
controller.render();
var parts = createDirective();
parts.annotation.document.title = 'A very very very long title that really\nshouldn\'t be found on a page on the internet.';
parts.controller.render();
assert.equal(
controller.document.title, 'A very very very long title th…');
parts.controller.document.title, 'A very very very long title th…');
});
it('provides a document uri', function() {
......@@ -752,47 +1006,49 @@ describe('annotation.js', function() {
});
it('uses the domain for the title if the title is not present', function() {
var controller = createDirective().controller;
delete annotation.document.title;
controller.render();
assert.equal(controller.document.title, 'example.com');
var parts = createDirective();
delete parts.annotation.document.title;
parts.controller.render();
assert.equal(parts.controller.document.title, 'example.com');
});
it(
'still sets the uri correctly if the annotation has no document',
function() {
var controller = createDirective().controller;
delete annotation.document;
controller.render();
assert(controller.document.uri === $scope.annotation.uri);
var parts = createDirective();
delete parts.annotation.document;
parts.controller.render();
assert(parts.controller.document.uri === $scope.annotation.uri);
}
);
it(
'still sets the domain correctly if the annotation has no document',
function() {
var controller = createDirective().controller;
delete annotation.document;
controller.render();
assert(controller.document.domain === 'example.com');
var parts = createDirective();
delete parts.annotation.document;
parts.controller.render();
assert(parts.controller.document.domain === 'example.com');
}
);
it(
'uses the domain for the title when the annotation has no document',
function() {
var controller = createDirective().controller;
delete annotation.document;
controller.render();
assert(controller.document.title === 'example.com');
var parts = createDirective();
delete parts.annotation.document;
parts.controller.render();
assert(parts.controller.document.title === 'example.com');
}
);
describe('timestamp', function() {
var annotation;
var clock;
beforeEach(function() {
clock = sinon.useFakeTimers();
annotation = defaultAnnotation();
annotation.created = (new Date()).toString();
annotation.updated = (new Date()).toString();
});
......@@ -803,7 +1059,7 @@ describe('annotation.js', function() {
it('is not updated for unsaved annotations', function() {
annotation.updated = null;
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
// Unsaved annotations don't have an updated time yet so a timestamp
// string can't be computed for them.
$scope.$digest();
......@@ -811,13 +1067,13 @@ describe('annotation.js', function() {
});
it('is updated on first digest', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
$scope.$digest();
assert.equal(controller.timestamp, 'a while ago');
});
it('is updated after a timeout', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
fakeTime.nextFuzzyUpdate.returns(10);
fakeTime.toFuzzyString.returns('ages ago');
$scope.$digest();
......@@ -827,7 +1083,7 @@ describe('annotation.js', function() {
});
it('is no longer updated after the scope is destroyed', function() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
$scope.$digest();
$scope.$destroy();
$timeout.flush();
......@@ -837,13 +1093,10 @@ describe('annotation.js', function() {
describe('share', function() {
it('sets and unsets the open class on the share wrapper', function() {
var components = createDirective();
var controller = components.controller;
var element = components.element;
var scope = components.scope;
var dialog = element.find('.share-dialog-wrapper');
var parts = createDirective();
var dialog = parts.element.find('.share-dialog-wrapper');
dialog.find('button').click();
scope.$digest();
parts.scope.$digest();
assert.ok(dialog.hasClass('open'));
documentService().click();
assert.notOk(dialog.hasClass('open'));
......@@ -860,11 +1113,13 @@ describe('annotation.js', function() {
it(
'calls annotationMapper.delete() if the delete is confirmed',
function(done) {
var controller = createDirective().controller;
var parts = createDirective();
sandbox.stub($window, 'confirm').returns(true);
fakeAnnotationMapper.deleteAnnotation.returns($q.resolve());
controller['delete']().then(function() {
assert(fakeAnnotationMapper.deleteAnnotation.calledWith(annotation));
parts.controller['delete']().then(function() {
assert(
fakeAnnotationMapper.deleteAnnotation.calledWith(
parts.annotation));
done();
});
$timeout.flush();
......@@ -926,13 +1181,16 @@ describe('annotation.js', function() {
});
describe('saving a new annotation', function() {
var annotation;
beforeEach(function() {
fakeFlash.error = sandbox.stub();
annotation = defaultAnnotation();
annotation.$create = sandbox.stub();
});
function controllerWithActionCreate() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
controller.action = 'create';
return controller;
}
......@@ -994,13 +1252,16 @@ describe('annotation.js', function() {
});
describe('saving an edited an annotation', function() {
var annotation;
beforeEach(function() {
fakeFlash.error = sandbox.stub();
annotation = defaultAnnotation();
annotation.$update = sandbox.stub();
});
function controllerWithActionEdit() {
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
controller.action = 'edit';
return controller;
}
......@@ -1050,9 +1311,9 @@ describe('annotation.js', function() {
describe('drafts', function() {
it('creates a draft when editing an annotation', function() {
var controller = createDirective().controller;
controller.edit();
assert.calledWith(fakeDrafts.update, annotation);
var parts = createDirective();
parts.controller.edit();
assert.calledWith(fakeDrafts.update, parts.annotation);
});
it(
......@@ -1062,14 +1323,15 @@ describe('annotation.js', function() {
// "changes" object that aren't actually set on the annotation. In this
// case, both permissions and tags are null so shouldn't be saved in
// the draft.
var controller = createDirective().controller;
annotation.permissions = null;
annotation.text = 'Hello!';
annotation.tags = null;
var parts = createDirective();
parts.annotation.permissions = null;
parts.annotation.text = 'Hello!';
parts.annotation.tags = null;
controller.edit();
parts.controller.edit();
assert.calledWith(fakeDrafts.update, annotation, {text: 'Hello!'});
assert.calledWith(
fakeDrafts.update, parts.annotation, {text: 'Hello!'});
}
);
......@@ -1101,15 +1363,16 @@ describe('annotation.js', function() {
});
it('removes the draft when changes are discarded', function() {
var controller = createDirective().controller;
controller.edit();
controller.revert();
assert.calledWith(fakeDrafts.remove, annotation);
var parts = createDirective();
parts.controller.edit();
parts.controller.revert();
assert.calledWith(fakeDrafts.remove, parts.annotation);
});
it('removes the draft when changes are saved', function() {
var annotation = defaultAnnotation();
annotation.$update = sandbox.stub().returns(Promise.resolve());
var controller = createDirective().controller;
var controller = createDirective(annotation).controller;
controller.edit();
controller.save();
......@@ -1125,17 +1388,17 @@ describe('annotation.js', function() {
describe('when the focused group changes', function() {
it('updates the current draft', function() {
var controller = createDirective().controller;
controller.edit();
controller.annotation.text = 'unsaved-text';
controller.annotation.tags = [];
controller.annotation.permissions = 'new permissions';
var parts = createDirective();
parts.controller.edit();
parts.controller.annotation.text = 'unsaved-text';
parts.controller.annotation.tags = [];
parts.controller.annotation.permissions = 'new permissions';
fakeDrafts.get = sinon.stub().returns({
text: 'old-draft'
});
fakeDrafts.update = sinon.stub();
$rootScope.$broadcast(events.GROUP_FOCUSED);
assert.calledWith(fakeDrafts.update, annotation, {
assert.calledWith(fakeDrafts.update, parts.annotation, {
text: 'unsaved-text',
tags: [],
permissions: 'new permissions'
......@@ -1152,8 +1415,9 @@ describe('annotation.js', function() {
});
it('moves new annotations to the focused group', function() {
var annotation = defaultAnnotation();
annotation.id = null;
createDirective();
createDirective(annotation);
fakeGroups.focused = sinon.stub().returns({
id: 'new-group'
});
......@@ -1167,6 +1431,7 @@ describe('annotation.js', function() {
function() {
// id must be null so that AnnotationController considers this a new
// annotation.
var annotation = defaultAnnotation();
annotation.id = null;
annotation.group = 'old-group';
annotation.permissions = {
......@@ -1174,7 +1439,7 @@ describe('annotation.js', function() {
};
// This is a shared annotation.
fakePermissions.isShared.returns(true);
createDirective();
createDirective(annotation);
// Make permissions.shared() behave like we expect it to.
fakePermissions.shared = function(groupId) {
return {
......@@ -1192,6 +1457,7 @@ describe('annotation.js', function() {
it('saves shared permissions for the new group to drafts', function() {
// id must be null so that AnnotationController considers this a new
// annotation.
var annotation = defaultAnnotation();
annotation.id = null;
annotation.group = 'old-group';
annotation.permissions = {
......@@ -1199,7 +1465,7 @@ describe('annotation.js', function() {
};
// This is a shared annotation.
fakePermissions.isShared.returns(true);
createDirective();
createDirective(annotation);
// drafts.get() needs to return something truthy, otherwise
// AnnotationController won't try to update the draft for the annotation.
fakeDrafts.get.returns(true);
......@@ -1223,12 +1489,13 @@ describe('annotation.js', function() {
it('does not change perms when moving new private annotations', function() {
// id must be null so that AnnotationController considers this a new
// annotation.
var annotation = defaultAnnotation();
annotation.id = null;
annotation.group = 'old-group';
annotation.permissions = {
read: ['acct:bill@localhost']
};
createDirective();
createDirective(annotation);
// This is a private annotation.
fakePermissions.isShared.returns(false);
fakeGroups.focused = sinon.stub().returns({
......
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