Commit f022ed02 authored by Robert Knight's avatar Robert Knight

Merge pull request #2535 from hypothesis/translate-annotation-mapper

Translate annotation mapper
parents 309df24c fcf99ac0
# Wraps the annotation store to trigger events for the CRUD actions
module.exports = [
'$rootScope', 'threading', 'store',
($rootScope, threading, store) ->
setupAnnotation: (ann) -> ann
loadAnnotations: (annotations) ->
annotations = for annotation in annotations
container = threading.idTable[annotation.id]
if container?.message
angular.copy(annotation, container.message)
$rootScope.$emit('annotationUpdated', container.message)
continue
else
annotation
annotations = (new store.AnnotationResource(a) for a in annotations)
$rootScope.$emit('annotationsLoaded', annotations)
unloadAnnotations: (annotations) ->
for annotation in annotations
container = threading.idTable[annotation.id]
if container?.message
if annotation isnt container.message
annotation = angular.copy(annotation, container.message)
$rootScope.$emit('annotationDeleted', annotation)
createAnnotation: (annotation) ->
annotation = new store.AnnotationResource(annotation)
$rootScope.$emit('beforeAnnotationCreated', annotation)
annotation
deleteAnnotation: (annotation) ->
annotation.$delete(id: annotation.id).then ->
$rootScope.$emit('annotationDeleted', annotation)
annotation
]
'use strict';
// Fetch the container object for the passed annotation from the threading
// service, but only return it if it has an associated message.
function getContainer(threading, annotation) {
var container = threading.idTable[annotation.id];
if (container === null || typeof container === 'undefined') {
return null;
}
// Also return null if the container has no message
if (!container.message) {
return null;
}
return container;
}
// Wraps the annotation store to trigger events for the CRUD actions
// @ngInject
function annotationMapper($rootScope, threading, store) {
function loadAnnotations(annotations) {
var loaded = [];
annotations.forEach(function (annotation) {
var container = getContainer(threading, annotation);
if (container !== null) {
angular.copy(annotation, container.message);
$rootScope.$emit('annotationUpdated', container.message);
return;
}
loaded.push(new store.AnnotationResource(annotation));
});
$rootScope.$emit('annotationsLoaded', loaded);
}
function unloadAnnotations(annotations) {
annotations.forEach(function (annotation) {
var container = getContainer(threading, annotation);
if (container !== null && annotation !== container.message) {
annotation = angular.copy(annotation, container.message);
}
$rootScope.$emit('annotationDeleted', annotation);
});
}
function createAnnotation(annotation) {
annotation = new store.AnnotationResource(annotation);
$rootScope.$emit('beforeAnnotationCreated', annotation);
return annotation;
}
function deleteAnnotation(annotation) {
return annotation.$delete({
id: annotation.id
}).then(function () {
$rootScope.$emit('annotationDeleted', annotation);
return annotation;
});
}
return {
loadAnnotations: loadAnnotations,
unloadAnnotations: unloadAnnotations,
createAnnotation: createAnnotation,
deleteAnnotation: deleteAnnotation
};
}
module.exports = annotationMapper;
{module, inject} = angular.mock
describe 'annotationMapper', ->
sandbox = sinon.sandbox.create()
$rootScope = null
fakeStore = null
fakeThreading = null
annotationMapper = null
before ->
angular.module('h', [])
.service('annotationMapper', require('../annotation-mapper'))
beforeEach module('h')
beforeEach module ($provide) ->
fakeStore =
AnnotationResource: sandbox.stub().returns({})
fakeThreading =
idTable: {}
$provide.value('store', fakeStore)
$provide.value('threading', fakeThreading)
return
beforeEach inject (_annotationMapper_, _$rootScope_) ->
$rootScope = _$rootScope_
annotationMapper = _annotationMapper_
afterEach: -> sandbox.restore()
describe '.loadAnnotations()', ->
it 'triggers the annotationLoaded event', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1}, {id: 2}, {id: 3}]
annotationMapper.loadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationsLoaded', [{}, {}, {}])
it 'triggers the annotationUpdated event for each annotation in the threading cache', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1}, {id: 2}, {id: 3}]
cached = {message: {id: 1, $$tag: 'tag1'}}
fakeThreading.idTable[1] = cached
annotationMapper.loadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationUpdated', cached.message)
it 'replaces the properties on the cached annotation with those from the loaded one', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1, url: 'http://example.com'}]
cached = {message: {id: 1, $$tag: 'tag1'}}
fakeThreading.idTable[1] = cached
annotationMapper.loadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationUpdated', {
id: 1
url: 'http://example.com'
})
it 'excludes cached annotations from the annotationLoaded event', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1, url: 'http://example.com'}]
cached = {message: {id: 1, $$tag: 'tag1'}}
fakeThreading.idTable[1] = cached
annotationMapper.loadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationsLoaded', [])
describe '.unloadAnnotations()', ->
it 'triggers the annotationDeleted event', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1}, {id: 2}, {id: 3}]
annotationMapper.unloadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[0])
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[1])
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[2])
it 'replaces the properties on the cached annotation with those from the deleted one', ->
sandbox.stub($rootScope, '$emit')
annotations = [{id: 1, url: 'http://example.com'}]
cached = {message: {id: 1, $$tag: 'tag1'}}
fakeThreading.idTable[1] = cached
annotationMapper.unloadAnnotations(annotations)
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationDeleted', {
id: 1
url: 'http://example.com'
})
describe '.createAnnotation()', ->
it 'creates a new annotaton resource', ->
ann = {}
fakeStore.AnnotationResource.returns(ann)
ret = annotationMapper.createAnnotation(ann)
assert.equal(ret, ann)
it 'creates a new resource with the new keyword', ->
ann = {}
fakeStore.AnnotationResource.returns(ann)
ret = annotationMapper.createAnnotation()
assert.calledWithNew(fakeStore.AnnotationResource)
it 'emits the "beforeAnnotationCreated" event', ->
sandbox.stub($rootScope, '$emit')
ann = {}
fakeStore.AnnotationResource.returns(ann)
ret = annotationMapper.createAnnotation()
assert.calledWith($rootScope.$emit, 'beforeAnnotationCreated', ann)
describe '.deleteAnnotation()', ->
it 'deletes the annotation on the server', ->
p = Promise.resolve()
ann = {$delete: sandbox.stub().returns(p)}
annotationMapper.deleteAnnotation(ann)
assert.called(ann.$delete)
it 'triggers the "annotationDeleted" event on success', (done) ->
sandbox.stub($rootScope, '$emit')
p = Promise.resolve()
ann = {$delete: sandbox.stub().returns(p)}
annotationMapper.deleteAnnotation(ann).then ->
assert.called($rootScope.$emit)
assert.calledWith($rootScope.$emit, 'annotationDeleted', ann)
done()
$rootScope.$apply()
it 'does nothing on error', (done) ->
sandbox.stub($rootScope, '$emit')
p = Promise.reject()
ann = {$delete: sandbox.stub().returns(p)}
annotationMapper.deleteAnnotation(ann).catch ->
assert.notCalled($rootScope.$emit)
done()
$rootScope.$apply()
it 'return a promise that resolves to the deleted annotation', (done) ->
p = Promise.resolve()
ann = {$delete: sandbox.stub().returns(p)}
annotationMapper.deleteAnnotation(ann).then((value) ->
assert.equal(value, ann)
done()
)
$rootScope.$apply()
'use strict';
describe('annotationMapper', function() {
var sandbox = sinon.sandbox.create();
var $rootScope;
var fakeStore;
var fakeThreading;
var annotationMapper;
before(function () {
angular.module('h', [])
.service('annotationMapper', require('../annotation-mapper'));
});
beforeEach(angular.mock.module('h'));
beforeEach(angular.mock.module(function ($provide) {
fakeStore = {
AnnotationResource: sandbox.stub().returns({})
};
fakeThreading = {
idTable: {}
};
$provide.value('store', fakeStore);
$provide.value('threading', fakeThreading);
}));
beforeEach(angular.mock.inject(function (_annotationMapper_, _$rootScope_) {
$rootScope = _$rootScope_;
annotationMapper = _annotationMapper_;
}));
afterEach(function () {
sandbox.restore();
});
describe('.loadAnnotations()', function () {
it('triggers the annotationLoaded event', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1}, {id: 2}, {id: 3}];
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationsLoaded', [{}, {}, {}]);
});
it('triggers the annotationUpdated event for each annotation in the threading cache', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1}, {id: 2}, {id: 3}];
var cached = {message: {id: 1, $$tag: 'tag1'}};
fakeThreading.idTable[1] = cached;
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationUpdated', cached.message);
});
it('replaces the properties on the cached annotation with those from the loaded one', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1, url: 'http://example.com'}];
var cached = {message: {id: 1, $$tag: 'tag1'}};
fakeThreading.idTable[1] = cached;
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationUpdated', {
id: 1,
url: 'http://example.com'
});
});
it('excludes cached annotations from the annotationLoaded event', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1, url: 'http://example.com'}];
var cached = {message: {id: 1, $$tag: 'tag1'}};
fakeThreading.idTable[1] = cached;
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationsLoaded', []);
});
});
describe('.unloadAnnotations()', function () {
it('triggers the annotationDeleted event', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1}, {id: 2}, {id: 3}];
annotationMapper.unloadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[0]);
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[1]);
assert.calledWith($rootScope.$emit, 'annotationDeleted', annotations[2]);
});
it('replaces the properties on the cached annotation with those from the deleted one', function () {
sandbox.stub($rootScope, '$emit');
var annotations = [{id: 1, url: 'http://example.com'}];
var cached = {message: {id: 1, $$tag: 'tag1'}};
fakeThreading.idTable[1] = cached;
annotationMapper.unloadAnnotations(annotations);
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationDeleted', {
id: 1,
url: 'http://example.com'
});
});
});
describe('.createAnnotation()', function () {
it('creates a new annotaton resource', function () {
var ann = {};
fakeStore.AnnotationResource.returns(ann);
var ret = annotationMapper.createAnnotation(ann);
assert.equal(ret, ann);
});
it('creates a new resource with the new keyword', function () {
var ann = {};
fakeStore.AnnotationResource.returns(ann);
annotationMapper.createAnnotation();
assert.calledWithNew(fakeStore.AnnotationResource);
});
it('emits the "beforeAnnotationCreated" event', function () {
sandbox.stub($rootScope, '$emit');
var ann = {};
fakeStore.AnnotationResource.returns(ann);
annotationMapper.createAnnotation();
assert.calledWith($rootScope.$emit, 'beforeAnnotationCreated', ann);
});
});
describe('.deleteAnnotation()', function () {
it('deletes the annotation on the server', function () {
var p = Promise.resolve();
var ann = {$delete: sandbox.stub().returns(p)};
annotationMapper.deleteAnnotation(ann);
assert.called(ann.$delete);
});
it('triggers the "annotationDeleted" event on success', function (done) {
sandbox.stub($rootScope, '$emit');
var p = Promise.resolve();
var ann = {$delete: sandbox.stub().returns(p)};
annotationMapper.deleteAnnotation(ann).then(function () {
assert.called($rootScope.$emit);
assert.calledWith($rootScope.$emit, 'annotationDeleted', ann);
}).then(done, done);
$rootScope.$apply();
});
it('does nothing on error', function (done) {
sandbox.stub($rootScope, '$emit');
var p = Promise.reject();
var ann = {$delete: sandbox.stub().returns(p)};
annotationMapper.deleteAnnotation(ann).catch(function () {
assert.notCalled($rootScope.$emit);
}).then(done, done);
$rootScope.$apply();
});
it('return a promise that resolves to the deleted annotation', function (done) {
var p = Promise.resolve();
var ann = {$delete: sandbox.stub().returns(p)};
annotationMapper.deleteAnnotation(ann).then(function (value) {
assert.equal(value, ann);
}).then(done, done);
$rootScope.$apply();
});
});
});
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