Unverified Commit cf10d9f3 authored by Sean Hammond's avatar Sean Hammond Committed by GitHub

Merge pull request #695 from hypothesis/rename-annotationui-to-store

Rename "annotationUI" => "store"
parents 8b15381f f5a519be
......@@ -24,12 +24,12 @@ function fetchThread(api, id) {
// @ngInject
function AnnotationViewerContentController (
$location, $routeParams, annotationUI, api, rootThread, streamer,
$location, $routeParams, store, api, rootThread, streamer,
streamFilter, annotationMapper
) {
var self = this;
annotationUI.setAppIsSidebar(false);
store.setAppIsSidebar(false);
var id = $routeParams.id;
......@@ -37,12 +37,12 @@ function AnnotationViewerContentController (
$location.path('/stream').search('q', query);
};
annotationUI.subscribe(function () {
self.rootThread = rootThread.thread(annotationUI.getState());
store.subscribe(function () {
self.rootThread = rootThread.thread(store.getState());
});
this.setCollapsed = function (id, collapsed) {
annotationUI.setCollapsed(id, collapsed);
store.setCollapsed(id, collapsed);
};
this.ready = fetchThread(api, id).then(function (annots) {
......@@ -64,11 +64,11 @@ function AnnotationViewerContentController (
streamer.connect();
annots.forEach(function (annot) {
annotationUI.setCollapsed(annot.id, false);
store.setCollapsed(annot.id, false);
});
if (topLevelAnnot.id !== id) {
annotationUI.highlightAnnotations([id]);
store.highlightAnnotations([id]);
}
});
}
......
......@@ -25,7 +25,7 @@ function updateModel(annotation, changes, permissions) {
// @ngInject
function AnnotationController(
$document, $rootScope, $scope, $timeout, $window, analytics, annotationUI,
$document, $rootScope, $scope, $timeout, $window, analytics, store,
annotationMapper, api, drafts, flash, groups, permissions, serviceUrl,
session, settings, streamer) {
......@@ -199,7 +199,7 @@ function AnnotationController(
};
annotationMapper.flagAnnotation(self.annotation).then(function(){
analytics.track(analytics.events.ANNOTATION_FLAGGED);
annotationUI.updateFlagStatus(self.annotation.id, true);
store.updateFlagStatus(self.annotation.id, true);
}, onRejected);
};
......
......@@ -9,7 +9,7 @@
module.exports = {
controllerAs: 'vm',
// @ngInject
controller: function ($scope, $window, annotationUI, serviceUrl) {
controller: function ($scope, $window, store, serviceUrl) {
this.userAgent = $window.navigator.userAgent;
this.version = '__VERSION__'; // replaced by versionify
this.dateTime = new Date();
......@@ -17,7 +17,7 @@ module.exports = {
$scope.$watch(
function () {
return annotationUI.frames();
return store.frames();
},
function (frames) {
if (frames.length === 0) {
......
......@@ -35,7 +35,7 @@ function authStateFromProfile(profile) {
// @ngInject
function HypothesisAppController(
$document, $location, $rootScope, $route, $scope,
$window, analytics, annotationUI, auth, bridge, drafts, features,
$window, analytics, store, auth, bridge, drafts, features,
flash, frameSync, groups, serviceUrl, session, settings, streamer
) {
var self = this;
......@@ -58,14 +58,14 @@ function HypothesisAppController(
}
this.sortKey = function () {
return annotationUI.getState().sortKey;
return store.getState().sortKey;
};
this.sortKeysAvailable = function () {
return annotationUI.getState().sortKeysAvailable;
return store.getState().sortKeysAvailable;
};
this.setSortKey = annotationUI.setSortKey;
this.setSortKey = store.setSortKey;
// Reload the view when the user switches accounts
$scope.$on(events.USER_CHANGED, function (event, data) {
......@@ -168,10 +168,10 @@ function HypothesisAppController(
this.search = {
query: function () {
return annotationUI.getState().filterQuery;
return store.getState().filterQuery;
},
update: function (query) {
annotationUI.setFilterQuery(query);
store.setFilterQuery(query);
},
};
......
......@@ -3,7 +3,7 @@
var annotationMetadata = require('../annotation-metadata');
// @ngInject
function ModerationBannerController(annotationUI, flash, api) {
function ModerationBannerController(store, flash, api) {
var self = this;
this.flagCount = function () {
......@@ -28,7 +28,7 @@ function ModerationBannerController(annotationUI, flash, api) {
*/
this.hideAnnotation = function () {
api.annotation.hide({id: self.annotation.id}).then(function () {
annotationUI.hideAnnotation(self.annotation.id);
store.hideAnnotation(self.annotation.id);
}).catch(function () {
flash.error('Failed to hide annotation');
});
......@@ -39,7 +39,7 @@ function ModerationBannerController(annotationUI, flash, api) {
*/
this.unhideAnnotation = function () {
api.annotation.unhide({id: self.annotation.id}).then(function () {
annotationUI.unhideAnnotation(self.annotation.id);
store.unhideAnnotation(self.annotation.id);
}).catch(function () {
flash.error('Failed to unhide annotation');
});
......
......@@ -5,9 +5,9 @@ var events = require('../events');
module.exports = {
controllerAs: 'vm',
//@ngInject
controller: function ($rootScope, annotationUI) {
controller: function ($rootScope, store) {
this.onNewNoteBtnClick = function(){
var topLevelFrame = annotationUI.frames().find(f=>!f.id);
var topLevelFrame = store.frames().find(f=>!f.id);
var annot = {
target: [],
uri: topLevelFrame.uri,
......
......@@ -6,7 +6,7 @@ var uiConstants = require('../ui-constants');
module.exports = {
controllerAs: 'vm',
//@ngInject
controller: function ($element, annotationUI, features, session, settings) {
controller: function ($element, store, features, session, settings) {
this.TAB_ANNOTATIONS = uiConstants.TAB_ANNOTATIONS;
this.TAB_NOTES = uiConstants.TAB_NOTES;
this.TAB_ORPHANS = uiConstants.TAB_ORPHANS;
......@@ -16,8 +16,8 @@ module.exports = {
this.enableExperimentalNewNoteButton = settings.enableExperimentalNewNoteButton;
this.selectTab = function (type) {
annotationUI.clearSelectedAnnotations();
annotationUI.selectTab(type);
store.clearSelectedAnnotations();
store.selectTab(type);
};
this.showAnnotationsUnavailableMessage = function () {
......
......@@ -3,7 +3,7 @@
var VIA_PREFIX = 'https://via.hypothes.is/';
// @ngInject
function ShareDialogController($scope, $element, analytics, annotationUI) {
function ShareDialogController($scope, $element, analytics, store) {
var self = this;
function updateViaLink(frames) {
......@@ -24,7 +24,7 @@ function ShareDialogController($scope, $element, analytics, annotationUI) {
viaInput.focus();
viaInput.select();
$scope.$watch(function () { return annotationUI.frames(); },
$scope.$watch(function () { return store.frames(); },
updateViaLink);
$scope.onShareClick = function(target){
......
......@@ -34,17 +34,17 @@ function groupIDFromSelection(selection, results) {
// @ngInject
function SidebarContentController(
$scope, analytics, annotationUI, annotationMapper, api, drafts, features, frameSync,
$scope, analytics, store, annotationMapper, api, drafts, features, frameSync,
groups, rootThread, settings, streamer, streamFilter
) {
var self = this;
function thread() {
return rootThread.thread(annotationUI.getState());
return rootThread.thread(store.getState());
}
var unsubscribeAnnotationUI = annotationUI.subscribe(function () {
var state = annotationUI.getState();
var unsubscribeAnnotationUI = store.subscribe(function () {
var state = store.getState();
self.rootThread = thread();
self.selectedTab = state.selectedTab;
......@@ -79,13 +79,13 @@ function SidebarContentController(
/**
* Returns the Annotation object for the first annotation in the
* selected annotation set. Note that 'first' refers to the order
* of annotations passed to annotationUI when selecting annotations,
* of annotations passed to store when selecting annotations,
* not the order in which they appear in the document.
*/
function firstSelectedAnnotation() {
if (annotationUI.getState().selectedAnnotationMap) {
var id = Object.keys(annotationUI.getState().selectedAnnotationMap)[0];
return annotationUI.getState().annotations.find(function (annot) {
if (store.getState().selectedAnnotationMap) {
var id = Object.keys(store.getState().selectedAnnotationMap)[0];
return store.getState().annotations.find(function (annot) {
return annot.id === id;
});
} else {
......@@ -96,7 +96,7 @@ function SidebarContentController(
var searchClients = [];
function _resetAnnotations() {
annotationMapper.unloadAnnotations(annotationUI.savedAnnotations());
annotationMapper.unloadAnnotations(store.savedAnnotations());
}
function _loadAnnotationsFor(uris, group) {
......@@ -109,11 +109,11 @@ function SidebarContentController(
});
searchClients.push(searchClient);
searchClient.on('results', function (results) {
if (annotationUI.hasSelectedAnnotations()) {
if (store.hasSelectedAnnotations()) {
// Focus the group containing the selected annotation and filter
// annotations to those from this group
var groupID = groupIDFromSelection(
annotationUI.getState().selectedAnnotationMap, results);
store.getState().selectedAnnotationMap, results);
if (!groupID) {
// If the selected annotation is not available, fall back to
// loading annotations for the currently focused group
......@@ -139,9 +139,9 @@ function SidebarContentController(
searchClients.splice(searchClients.indexOf(searchClient), 1);
});
annotationUI.frames().forEach(function (frame) {
store.frames().forEach(function (frame) {
if (0 <= uris.indexOf(frame.uri)) {
annotationUI.updateFrameAnnotationFetchStatus(frame.uri, true);
store.updateFrameAnnotationFetchStatus(frame.uri, true);
}
});
});
......@@ -149,7 +149,7 @@ function SidebarContentController(
}
function isLoading() {
if (!annotationUI.frames().some(function (frame) { return frame.uri; })) {
if (!store.frames().some(function (frame) { return frame.uri; })) {
// The document's URL isn't known so the document must still be loading.
return true;
}
......@@ -183,10 +183,10 @@ function SidebarContentController(
// the batch size, this saves an extra roundtrip to the server
// to fetch the selected annotation in order to determine which group
// it is in before fetching the remaining annotations.
var group = annotationUI.hasSelectedAnnotations() ?
var group = store.hasSelectedAnnotations() ?
null : groups.focused().id;
var searchUris = annotationUI.searchUris();
var searchUris = store.searchUris();
if (searchUris.length > 0) {
_loadAnnotationsFor(searchUris, group);
......@@ -227,15 +227,15 @@ function SidebarContentController(
focusAnnotation(selectedAnnot);
scrollToAnnotation(selectedAnnot);
annotationUI.selectTab(tabs.tabForAnnotation(selectedAnnot));
store.selectTab(tabs.tabForAnnotation(selectedAnnot));
});
// Re-fetch annotations when focused group, logged-in user or connected frames
// change.
$scope.$watch(() => ([
groups.focused().id,
annotationUI.profile().userid,
...annotationUI.searchUris(),
store.profile().userid,
...store.searchUris(),
]), ([currentGroupId], [prevGroupId]) => {
if (currentGroupId !== prevGroupId) {
......@@ -246,20 +246,20 @@ function SidebarContentController(
if (isLoading()) {
return;
}
annotationUI.clearSelectedAnnotations();
store.clearSelectedAnnotations();
}
loadAnnotations();
}, true);
this.setCollapsed = function (id, collapsed) {
annotationUI.setCollapsed(id, collapsed);
store.setCollapsed(id, collapsed);
};
this.forceVisible = function (thread) {
annotationUI.setForceVisible(thread.id, true);
store.setForceVisible(thread.id, true);
if (thread.parent) {
annotationUI.setCollapsed(thread.parent.id, false);
store.setCollapsed(thread.parent.id, false);
}
};
......@@ -267,7 +267,7 @@ function SidebarContentController(
this.scrollTo = scrollToAnnotation;
this.selectedAnnotationCount = function () {
var selection = annotationUI.getState().selectedAnnotationMap;
var selection = store.getState().selectedAnnotationMap;
if (!selection) {
return 0;
}
......@@ -275,10 +275,10 @@ function SidebarContentController(
};
this.selectedAnnotationUnavailable = function () {
var selectedID = firstKey(annotationUI.getState().selectedAnnotationMap);
var selectedID = firstKey(store.getState().selectedAnnotationMap);
return !isLoading() &&
!!selectedID &&
!annotationUI.annotationExists(selectedID);
!store.annotationExists(selectedID);
};
this.shouldShowLoggedOutMessage = function () {
......@@ -302,10 +302,10 @@ function SidebarContentController(
// The user is logged out and has landed on a direct linked
// annotation. If there is an annotation selection and that
// selection is available to the user, show the CTA.
var selectedID = firstKey(annotationUI.getState().selectedAnnotationMap);
var selectedID = firstKey(store.getState().selectedAnnotationMap);
return !isLoading() &&
!!selectedID &&
annotationUI.annotationExists(selectedID);
store.annotationExists(selectedID);
};
this.isLoading = isLoading;
......@@ -325,13 +325,13 @@ function SidebarContentController(
};
this.clearSelection = function () {
var selectedTab = annotationUI.getState().selectedTab;
if (!annotationUI.getState().selectedTab || annotationUI.getState().selectedTab === uiConstants.TAB_ORPHANS) {
var selectedTab = store.getState().selectedTab;
if (!store.getState().selectedTab || store.getState().selectedTab === uiConstants.TAB_ORPHANS) {
selectedTab = uiConstants.TAB_ANNOTATIONS;
}
annotationUI.clearSelectedAnnotations();
annotationUI.selectTab(selectedTab);
store.clearSelectedAnnotations();
store.selectTab(selectedTab);
};
}
......
......@@ -2,12 +2,12 @@
// @ngInject
function StreamContentController(
$scope, $location, $route, $routeParams, annotationMapper, annotationUI,
$scope, $location, $route, $routeParams, annotationMapper, store,
api, queryParser, rootThread, searchFilter, streamFilter, streamer
) {
var self = this;
annotationUI.setAppIsSidebar(false);
store.setAppIsSidebar(false);
/** `offset` parameter for the next search API call. */
var offset = 0;
......@@ -39,7 +39,7 @@ function StreamContentController(
var lastQuery = $routeParams.q;
$scope.$on('$routeUpdate', function () {
if ($routeParams.q !== lastQuery) {
annotationUI.clearAnnotations();
store.clearAnnotations();
$route.reload();
}
});
......@@ -57,9 +57,9 @@ function StreamContentController(
// Perform the initial search
fetch(20);
this.setCollapsed = annotationUI.setCollapsed;
this.setCollapsed = store.setCollapsed;
this.forceVisible = function (id) {
annotationUI.setForceVisible(id, true);
store.setForceVisible(id, true);
};
Object.assign(this.search, {
......@@ -71,12 +71,12 @@ function StreamContentController(
},
});
annotationUI.subscribe(function () {
self.rootThread = rootThread.thread(annotationUI.getState());
store.subscribe(function () {
self.rootThread = rootThread.thread(store.getState());
});
// Sort the stream so that the newest annotations are at the top
annotationUI.setSortKey('Newest');
store.setSortKey('Newest');
this.loadMore = fetch;
}
......
......@@ -101,7 +101,7 @@ describe('annotation', function() {
};
var fakeAnalytics;
var fakeAnnotationMapper;
var fakeAnnotationUI;
var fakeStore;
var fakeDrafts;
var fakeFlash;
var fakeGroups;
......@@ -177,7 +177,7 @@ describe('annotation', function() {
flagAnnotation: sandbox.stub(),
};
fakeAnnotationUI = {
fakeStore = {
updateFlagStatus: sandbox.stub().returns(true),
};
......@@ -244,7 +244,7 @@ describe('annotation', function() {
$provide.value('analytics', fakeAnalytics);
$provide.value('annotationMapper', fakeAnnotationMapper);
$provide.value('annotationUI', fakeAnnotationUI);
$provide.value('store', fakeStore);
$provide.value('api', fakeApi);
$provide.value('drafts', fakeDrafts);
$provide.value('flash', fakeFlash);
......
......@@ -45,7 +45,7 @@ describe('annotationViewerContent', function () {
var locals = {
$location: {},
$routeParams: { id: 'test_annotation_id' },
annotationUI: {
store: {
setAppIsSidebar: sinon.stub(),
setCollapsed: sinon.stub(),
highlightAnnotations: sinon.stub(),
......@@ -105,7 +105,7 @@ describe('annotationViewerContent', function () {
]);
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.notCalled(controller.annotationUI.highlightAnnotations);
assert.notCalled(controller.store.highlightAnnotations);
});
});
});
......@@ -130,8 +130,8 @@ describe('annotationViewerContent', function () {
]);
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledWith(controller.annotationUI.setCollapsed, 'parent_id', false);
assert.calledWith(controller.annotationUI.setCollapsed, 'test_annotation_id', false);
assert.calledWith(controller.store.setCollapsed, 'parent_id', false);
assert.calledWith(controller.store.setCollapsed, 'test_annotation_id', false);
});
});
......@@ -142,7 +142,7 @@ describe('annotationViewerContent', function () {
]);
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledWith(controller.annotationUI.highlightAnnotations,
assert.calledWith(controller.store.highlightAnnotations,
sinon.match(['test_annotation_id']));
});
});
......
......@@ -3,12 +3,12 @@
var angular = require('angular');
describe('helpPanel', function () {
var fakeAnnotationUI;
var fakeStore;
var $componentController;
var $rootScope;
beforeEach(function () {
fakeAnnotationUI = {
fakeStore = {
frames: sinon.stub().returns([]),
};
......@@ -16,7 +16,7 @@ describe('helpPanel', function () {
.component('helpPanel', require('../help-panel'));
angular.mock.module('h', {
annotationUI: fakeAnnotationUI,
store: fakeStore,
serviceUrl: sinon.stub(),
});
......@@ -27,7 +27,7 @@ describe('helpPanel', function () {
});
it('displays the URL and fingerprint of the first connected frame', function () {
fakeAnnotationUI.frames.returns([{
fakeStore.frames.returns([{
uri: 'https://publisher.org/article.pdf',
metadata: {
documentFingerprint: '12345',
......
......@@ -12,7 +12,7 @@ describe('sidebar.components.hypothesis-app', function () {
var $scope = null;
var $rootScope = null;
var fakeAnnotationMetadata = null;
var fakeAnnotationUI = null;
var fakeStore = null;
var fakeAnalytics = null;
var fakeAuth = null;
var fakeBridge = null;
......@@ -64,7 +64,7 @@ describe('sidebar.components.hypothesis-app', function () {
beforeEach(angular.mock.module('h'));
beforeEach(angular.mock.module(function ($provide) {
fakeAnnotationUI = {
fakeStore = {
tool: 'comment',
clearSelectedAnnotations: sandbox.spy(),
};
......@@ -130,7 +130,7 @@ describe('sidebar.components.hypothesis-app', function () {
call: sandbox.stub(),
};
$provide.value('annotationUI', fakeAnnotationUI);
$provide.value('store', fakeStore);
$provide.value('auth', fakeAuth);
$provide.value('analytics', fakeAnalytics);
$provide.value('drafts', fakeDrafts);
......
......@@ -10,7 +10,7 @@ var moderatedAnnotation = fixtures.moderatedAnnotation;
describe('moderationBanner', function () {
var bannerEl;
var fakeAnnotationUI;
var fakeStore;
var fakeFlash;
var fakeApi;
......@@ -20,7 +20,7 @@ describe('moderationBanner', function () {
});
beforeEach(function () {
fakeAnnotationUI = {
fakeStore = {
hideAnnotation: sinon.stub(),
unhideAnnotation: sinon.stub(),
};
......@@ -37,7 +37,7 @@ describe('moderationBanner', function () {
};
angular.mock.module('app', {
annotationUI: fakeAnnotationUI,
store: fakeStore,
api: fakeApi,
flash: fakeFlash,
});
......
......@@ -8,7 +8,7 @@ var util = require('../../directive/test/util');
describe('newNoteBtn', function () {
var $rootScope;
var sandbox = sinon.sandbox.create();
var fakeAnnotationUI = {
var fakeStore = {
frames: sinon.stub().returns([{ id: null, uri: 'www.example.org'}, { id: '1', uri: 'www.example.org'}]),
};
......@@ -25,7 +25,7 @@ describe('newNoteBtn', function () {
var fakeSettings = { theme: 'clean' };
angular.mock.module('app', {
annotationUI: fakeAnnotationUI,
store: fakeStore,
features: fakeFeatures,
settings: fakeSettings,
});
......@@ -45,7 +45,7 @@ describe('newNoteBtn', function () {
uri: 'www.example.org',
};
var elem = util.createDirective(document, 'newNoteBtn', {
annotationUI: fakeAnnotationUI,
store: fakeStore,
});
sandbox.spy($rootScope, '$broadcast');
elem.ctrl.onNewNoteBtnClick();
......
......@@ -22,13 +22,13 @@ describe('selectionTabs', function () {
});
beforeEach(function () {
var fakeAnnotationUI = {};
var fakeStore = {};
var fakeFeatures = {
flagEnabled: sinon.stub().returns(true),
};
angular.mock.module('app', {
annotationUI: fakeAnnotationUI,
store: fakeStore,
features: fakeFeatures,
session: fakeSession,
settings: fakeSettings,
......@@ -84,7 +84,7 @@ describe('selectionTabs', function () {
it('should show the clean theme when settings contains the clean theme option', function () {
angular.mock.module('app', {
annotationUI: {},
store: {},
features: {
flagEnabled: sinon.stub().returns(true),
},
......
......@@ -6,33 +6,33 @@ var util = require('../../directive/test/util');
describe('shareDialog', function () {
var fakeAnalytics;
var fakeAnnotationUI;
var fakeStore;
beforeEach(function () {
fakeAnalytics = {
track: sinon.stub(),
events: {},
};
fakeAnnotationUI = { frames: sinon.stub().returns([]) };
fakeStore = { frames: sinon.stub().returns([]) };
angular.module('h', [])
.component('shareDialog', require('../share-dialog'))
.value('analytics', fakeAnalytics)
.value('annotationUI', fakeAnnotationUI)
.value('store', fakeStore)
.value('urlEncodeFilter', function (val) { return val; });
angular.mock.module('h');
});
it('generates new via link', function () {
var element = util.createDirective(document, 'shareDialog', {});
fakeAnnotationUI.frames.returns([{ uri: 'http://example.com' }]);
fakeStore.frames.returns([{ uri: 'http://example.com' }]);
element.scope.$digest();
assert.equal(element.ctrl.viaPageLink, 'https://via.hypothes.is/http://example.com');
});
it('does not generate new via link if already on via', function () {
var element = util.createDirective(document, 'shareDialog', {});
fakeAnnotationUI.frames.returns([{
fakeStore.frames.returns([{
uri: 'https://via.hypothes.is/http://example.com',
}]);
element.scope.$digest();
......
......@@ -39,7 +39,7 @@ inherits(FakeRootThread, EventEmitter);
describe('sidebar.components.sidebar-content', function () {
var $rootScope;
var $scope;
var annotationUI;
var store;
var ctrl;
var fakeAnalytics;
var fakeAnnotationMapper;
......@@ -56,7 +56,7 @@ describe('sidebar.components.sidebar-content', function () {
before(function () {
angular.module('h', [])
.service('annotationUI', require('../../store'))
.service('store', require('../../store'))
.component('sidebarContent', proxyquire('../sidebar-content',
noCallThru({
angular: angular,
......@@ -135,15 +135,15 @@ describe('sidebar.components.sidebar-content', function () {
function setFrames(frames) {
frames.forEach(function (frame) {
annotationUI.connectFrame(frame);
store.connectFrame(frame);
});
}
beforeEach(angular.mock.inject(function ($componentController, _annotationUI_, _$rootScope_) {
beforeEach(angular.mock.inject(function ($componentController, _store_, _$rootScope_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
annotationUI = _annotationUI_;
annotationUI.updateFrameAnnotationFetchStatus = sinon.stub();
store = _store_;
store.updateFrameAnnotationFetchStatus = sinon.stub();
ctrl = $componentController('sidebarContent', { $scope: $scope }, {
auth: { status: 'unknown' },
});
......@@ -157,7 +157,7 @@ describe('sidebar.components.sidebar-content', function () {
it('unloads any existing annotations', function () {
// When new clients connect, all existing annotations should be unloaded
// before reloading annotations for each currently-connected client
annotationUI.addAnnotations([{id: '123'}]);
store.addAnnotations([{id: '123'}]);
var uri1 = 'http://example.com/page-a';
var frames = [{uri: uri1}];
setFrames(frames);
......@@ -168,7 +168,7 @@ describe('sidebar.components.sidebar-content', function () {
setFrames(frames);
$scope.$digest();
assert.calledWith(fakeAnnotationMapper.unloadAnnotations,
annotationUI.getState().annotations);
store.getState().annotations);
});
it('loads all annotations for a frame', function () {
......@@ -222,7 +222,7 @@ describe('sidebar.components.sidebar-content', function () {
return {uri: frameUri};
}));
$scope.$digest();
var updateSpy = annotationUI.updateFrameAnnotationFetchStatus;
var updateSpy = store.updateFrameAnnotationFetchStatus;
assert.isTrue(updateSpy.calledWith(frameUris[0], true));
assert.isTrue(updateSpy.calledWith(frameUris[1], true));
});
......@@ -233,7 +233,7 @@ describe('sidebar.components.sidebar-content', function () {
beforeEach(function () {
setFrames([{uri: uri}]);
annotationUI.selectAnnotations([id]);
store.selectAnnotations([id]);
$scope.$digest();
});
......@@ -286,7 +286,7 @@ describe('sidebar.components.sidebar-content', function () {
beforeEach(function () {
setFrames([{uri: uri}]);
annotationUI.selectAnnotations([id]);
store.selectAnnotations([id]);
fakeGroups.focused.returns({ id: 'private-group' });
$scope.$digest();
});
......@@ -321,24 +321,24 @@ describe('sidebar.components.sidebar-content', function () {
beforeEach(connectFrameAndPerformInitialFetch);
it('reloads annotations if the user ID changed', () => {
var newProfile = Object.assign({}, annotationUI.profile(), {
var newProfile = Object.assign({}, store.profile(), {
userid: 'different-user@hypothes.is',
});
annotationUI.updateSession(newProfile);
store.updateSession(newProfile);
$scope.$digest();
assert.called(fakeAnnotationMapper.loadAnnotations);
});
it('does not reload annotations if the user ID is the same', () => {
var newProfile = Object.assign({}, annotationUI.profile(), {
var newProfile = Object.assign({}, store.profile(), {
user_info: {
display_name: 'New display name',
},
});
annotationUI.updateSession(newProfile);
store.updateSession(newProfile);
$scope.$digest();
assert.notCalled(fakeAnnotationMapper.loadAnnotations);
......@@ -348,13 +348,13 @@ describe('sidebar.components.sidebar-content', function () {
describe('when an annotation is anchored', function () {
it('focuses and scrolls to the annotation if already selected', function () {
var uri = 'http://example.com';
annotationUI.selectAnnotations(['123']);
store.selectAnnotations(['123']);
setFrames([{uri: uri}]);
var annot = {
$tag: 'atag',
id: '123',
};
annotationUI.addAnnotations([annot]);
store.addAnnotations([annot]);
$scope.$digest();
$rootScope.$broadcast(events.ANNOTATIONS_SYNCED, ['atag']);
assert.calledWith(fakeFrameSync.focusAnnotations, ['atag']);
......@@ -368,8 +368,8 @@ describe('sidebar.components.sidebar-content', function () {
beforeEach(() => {
// Setup an initial state with frames connected, a group focused and some
// annotations loaded.
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.addAnnotations = sinon.stub();
store.addAnnotations([{id: '123'}]);
store.addAnnotations = sinon.stub();
fakeDrafts.unsaved.returns([{id: uri + '123'}, {id: uri + '456'}]);
setFrames([{uri: uri}]);
$scope.$digest();
......@@ -393,11 +393,11 @@ describe('sidebar.components.sidebar-content', function () {
});
it('should clear the selection', () => {
annotationUI.selectAnnotations(['123']);
store.selectAnnotations(['123']);
changeGroup();
assert.isFalse(annotationUI.hasSelectedAnnotations());
assert.isFalse(store.hasSelectedAnnotations());
});
});
......@@ -424,22 +424,22 @@ describe('sidebar.components.sidebar-content', function () {
it('displays a message if the selection is unavailable', function () {
addFrame();
annotationUI.selectAnnotations(['missing']);
store.selectAnnotations(['missing']);
$scope.$digest();
assert.isTrue(ctrl.selectedAnnotationUnavailable());
});
it('does not show a message if the selection is available', function () {
addFrame();
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.selectAnnotations(['123']);
store.addAnnotations([{id: '123'}]);
store.selectAnnotations(['123']);
$scope.$digest();
assert.isFalse(ctrl.selectedAnnotationUnavailable());
});
it('does not a show a message if there is no selection', function () {
addFrame();
annotationUI.selectAnnotations([]);
store.selectAnnotations([]);
$scope.$digest();
assert.isFalse(ctrl.selectedAnnotationUnavailable());
});
......@@ -448,7 +448,7 @@ describe('sidebar.components.sidebar-content', function () {
// No search requests have been sent yet.
searchClients = [];
// There is a selection but the selected annotation isn't available.
annotationUI.selectAnnotations(['missing']);
store.selectAnnotations(['missing']);
$scope.$digest();
assert.isFalse(ctrl.selectedAnnotationUnavailable());
......@@ -459,8 +459,8 @@ describe('sidebar.components.sidebar-content', function () {
ctrl.auth = {
status: 'logged-out',
};
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.selectAnnotations(['123']);
store.addAnnotations([{id: '123'}]);
store.selectAnnotations(['123']);
$scope.$digest();
assert.isTrue(ctrl.shouldShowLoggedOutMessage());
});
......@@ -470,7 +470,7 @@ describe('sidebar.components.sidebar-content', function () {
ctrl.auth = {
status: 'logged-out',
};
annotationUI.selectAnnotations(['missing']);
store.selectAnnotations(['missing']);
$scope.$digest();
assert.isFalse(ctrl.shouldShowLoggedOutMessage());
});
......@@ -480,7 +480,7 @@ describe('sidebar.components.sidebar-content', function () {
ctrl.auth = {
status: 'logged-out',
};
annotationUI.selectAnnotations([]);
store.selectAnnotations([]);
$scope.$digest();
assert.isFalse(ctrl.shouldShowLoggedOutMessage());
});
......@@ -490,8 +490,8 @@ describe('sidebar.components.sidebar-content', function () {
ctrl.auth = {
status: 'logged-in',
};
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.selectAnnotations(['123']);
store.addAnnotations([{id: '123'}]);
store.selectAnnotations(['123']);
$scope.$digest();
assert.isFalse(ctrl.shouldShowLoggedOutMessage());
});
......@@ -502,8 +502,8 @@ describe('sidebar.components.sidebar-content', function () {
status: 'logged-out',
};
delete fakeSettings.annotations;
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.selectAnnotations(['123']);
store.addAnnotations([{id: '123'}]);
store.selectAnnotations(['123']);
$scope.$digest();
assert.isFalse(ctrl.shouldShowLoggedOutMessage());
});
......@@ -512,8 +512,8 @@ describe('sidebar.components.sidebar-content', function () {
fakeSettings.services = [{ authority: 'publisher.com' }];
addFrame();
ctrl.auth = { status: 'logged-out' };
annotationUI.addAnnotations([{id: '123'}]);
annotationUI.selectAnnotations(['123']);
store.addAnnotations([{id: '123'}]);
store.selectAnnotations(['123']);
$scope.$digest();
assert.isFalse(ctrl.shouldShowLoggedOutMessage());
......@@ -545,7 +545,7 @@ describe('sidebar.components.sidebar-content', function () {
it('shows the thread', function () {
var thread = {id: '1'};
ctrl.forceVisible(thread);
assert.deepEqual(annotationUI.getState().forceVisible, {1: true});
assert.deepEqual(store.getState().forceVisible, {1: true});
});
it('uncollapses the parent', function () {
......@@ -553,9 +553,9 @@ describe('sidebar.components.sidebar-content', function () {
id: '2',
parent: {id: '3'},
};
assert.equal(annotationUI.getState().expanded[thread.parent.id], undefined);
assert.equal(store.getState().expanded[thread.parent.id], undefined);
ctrl.forceVisible(thread);
assert.equal(annotationUI.getState().expanded[thread.parent.id], true);
assert.equal(store.getState().expanded[thread.parent.id], true);
});
});
......
......@@ -15,7 +15,7 @@ describe('StreamContentController', function () {
var fakeRoute;
var fakeRouteParams;
var fakeAnnotationMapper;
var fakeAnnotationUI;
var fakeStore;
var fakeQueryParser;
var fakeRootThread;
var fakeSearchFilter;
......@@ -35,7 +35,7 @@ describe('StreamContentController', function () {
loadAnnotations: sinon.spy(),
};
fakeAnnotationUI = {
fakeStore = {
clearAnnotations: sinon.spy(),
setAppIsSidebar: sinon.spy(),
setCollapsed: sinon.spy(),
......@@ -84,7 +84,7 @@ describe('StreamContentController', function () {
$route: fakeRoute,
$routeParams: fakeRouteParams,
annotationMapper: fakeAnnotationMapper,
annotationUI: fakeAnnotationUI,
store: fakeStore,
api: fakeApi,
queryParser: fakeQueryParser,
rootThread: fakeRootThread,
......@@ -136,7 +136,7 @@ describe('StreamContentController', function () {
createController();
fakeRouteParams.q = 'new query';
$rootScope.$broadcast('$routeUpdate');
assert.called(fakeAnnotationUI.clearAnnotations);
assert.called(fakeStore.clearAnnotations);
assert.calledOnce(fakeRoute.reload);
});
......@@ -144,7 +144,7 @@ describe('StreamContentController', function () {
fakeRouteParams.q = 'test query';
createController();
$rootScope.$broadcast('$routeUpdate');
assert.notCalled(fakeAnnotationUI.clearAnnotations);
assert.notCalled(fakeStore.clearAnnotations);
assert.notCalled(fakeRoute.reload);
});
});
......
......@@ -21,7 +21,7 @@
*
*/
// @ngInject
function start(annotationUI, settings, $window) {
function start(store, settings, $window) {
$window.addEventListener('message', function receiveMessage(event) {
let allowedOrigins = settings.rpcAllowedOrigins || [];
......@@ -40,7 +40,7 @@ function start(annotationUI, settings, $window) {
function jsonRpcResponse(request) {
// The set of methods that clients can call.
let methods = {
'searchUris': annotationUI.searchUris,
'searchUris': store.searchUris,
};
let method = methods[request.method];
......
......@@ -209,7 +209,7 @@ module.exports = angular.module('h', [
.service('viewFilter', require('./services/view-filter'))
// Redux store
.service('annotationUI', require('./store'))
.service('store', require('./store'))
// Utilities
.value('Discovery', require('../shared/discovery'))
......
......@@ -4,21 +4,21 @@ var angular = require('angular');
var events = require('../events');
function getExistingAnnotation(annotationUI, id) {
return annotationUI.getState().annotations.find(function (annot) {
function getExistingAnnotation(store, id) {
return store.getState().annotations.find(function (annot) {
return annot.id === id;
});
}
// Wraps the annotation store to trigger events for the CRUD actions
// @ngInject
function annotationMapper($rootScope, annotationUI, api) {
function annotationMapper($rootScope, store, api) {
function loadAnnotations(annotations, replies) {
annotations = annotations.concat(replies || []);
var loaded = [];
annotations.forEach(function (annotation) {
var existing = getExistingAnnotation(annotationUI, annotation.id);
var existing = getExistingAnnotation(store, annotation.id);
if (existing) {
$rootScope.$broadcast(events.ANNOTATION_UPDATED, annotation);
return;
......@@ -31,7 +31,7 @@ function annotationMapper($rootScope, annotationUI, api) {
function unloadAnnotations(annotations) {
var unloaded = annotations.map(function (annotation) {
var existing = getExistingAnnotation(annotationUI, annotation.id);
var existing = getExistingAnnotation(store, annotation.id);
if (existing && annotation !== existing) {
annotation = angular.copy(annotation, existing);
}
......
......@@ -41,7 +41,7 @@ function formatAnnot(ann) {
* sidebar.
*/
// @ngInject
function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
function FrameSync($rootScope, $window, Discovery, store, bridge) {
// Set of tags of annotations that are currently loaded into the frame
var inFrame = new Set();
......@@ -56,8 +56,8 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
var prevFrames = [];
var prevPublicAnns = 0;
annotationUI.subscribe(function () {
var state = annotationUI.getState();
store.subscribe(function () {
var state = store.getState();
if (state.annotations === prevAnnotations &&
state.frames === prevFrames) {
return;
......@@ -102,7 +102,7 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
inFrame.delete(annot.$tag);
});
var frames = annotationUI.frames();
var frames = store.frames();
if (frames.length > 0) {
if (frames.every(function (frame) { return frame.isAnnotationFetchComplete; })) {
if (publicAnns === 0 || publicAnns !== prevPublicAnns) {
......@@ -135,7 +135,7 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
// triggered by each `UPDATE_ANCHOR_STATUS` action that is dispatched.
var anchoringStatusUpdates = {};
var scheduleAnchoringStatusUpdate = debounce(() => {
annotationUI.updateAnchorStatus(anchoringStatusUpdates);
store.updateAnchorStatus(anchoringStatusUpdates);
$rootScope.$broadcast(events.ANNOTATIONS_SYNCED, Object.keys(anchoringStatusUpdates));
anchoringStatusUpdates = {};
}, 10);
......@@ -150,16 +150,16 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
});
bridge.on('showAnnotations', function (tags) {
annotationUI.selectAnnotations(annotationUI.findIDsForTags(tags));
annotationUI.selectTab(uiConstants.TAB_ANNOTATIONS);
store.selectAnnotations(store.findIDsForTags(tags));
store.selectTab(uiConstants.TAB_ANNOTATIONS);
});
bridge.on('focusAnnotations', function (tags) {
annotationUI.focusAnnotations(tags || []);
store.focusAnnotations(tags || []);
});
bridge.on('toggleAnnotationSelection', function (tags) {
annotationUI.toggleSelectedAnnotations(annotationUI.findIDsForTags(tags));
store.toggleSelectedAnnotations(store.findIDsForTags(tags));
});
bridge.on('sidebarOpened', function () {
......@@ -192,7 +192,7 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
}
$rootScope.$broadcast(events.FRAME_CONNECTED);
annotationUI.connectFrame({
store.connectFrame({
id: info.frameIdentifier,
metadata: info.metadata,
uri: info.uri,
......@@ -201,12 +201,12 @@ function FrameSync($rootScope, $window, Discovery, annotationUI, bridge) {
}
function destroyFrame(frameIdentifier) {
var frames = annotationUI.frames();
var frames = store.frames();
var frameToDestroy = frames.find(function (frame) {
return frame.id === frameIdentifier;
});
if (frameToDestroy) {
annotationUI.destroyFrame(frameToDestroy);
store.destroyFrame(frameToDestroy);
}
}
......
......@@ -18,7 +18,7 @@ var { awaitStateChange } = require('../util/state-util');
var serviceConfig = require('../service-config');
// @ngInject
function groups($rootScope, annotationUI, api, isSidebar, localStorage, serviceUrl, session,
function groups($rootScope, store, api, isSidebar, localStorage, serviceUrl, session,
settings) {
// The currently focused group. This is the group that's shown as selected in
// the groups dropdown, the annotations displayed are filtered to only ones
......@@ -33,7 +33,7 @@ function groups($rootScope, annotationUI, api, isSidebar, localStorage, serviceU
function getDocumentUriForGroupSearch() {
function mainUri() {
var uris = annotationUI.searchUris();
var uris = store.searchUris();
if (uris.length === 0) {
return null;
}
......@@ -43,7 +43,7 @@ function groups($rootScope, annotationUI, api, isSidebar, localStorage, serviceU
// HTTP URLs (so eg. we cannot use a "file:" URL or PDF fingerprint).
return uris.find(uri => uri.startsWith('http'));
}
return awaitStateChange(annotationUI, mainUri);
return awaitStateChange(store, mainUri);
}
/**
......
......@@ -33,14 +33,14 @@ var sortFns = {
* This performs two functions:
*
* 1. It listens for annotations being loaded, created and unloaded and
* dispatches annotationUI.{addAnnotations|removeAnnotations} actions.
* dispatches store.{addAnnotations|removeAnnotations} actions.
* 2. Listens for changes in the UI state and rebuilds the root conversation
* thread.
*
* The root thread is then displayed by viewer.html
*/
// @ngInject
function RootThread($rootScope, annotationUI, drafts, searchFilter, viewFilter) {
function RootThread($rootScope, store, drafts, searchFilter, viewFilter) {
/**
* Build the root conversation thread from the given UI state.
......@@ -84,7 +84,7 @@ function RootThread($rootScope, annotationUI, drafts, searchFilter, viewFilter)
}
function deleteNewAndEmptyAnnotations() {
annotationUI.getState().annotations.filter(function (ann) {
store.getState().annotations.filter(function (ann) {
return metadata.isNew(ann) && !drafts.getIfNotEmpty(ann);
}).forEach(function (ann) {
drafts.remove(ann);
......@@ -96,13 +96,13 @@ function RootThread($rootScope, annotationUI, drafts, searchFilter, viewFilter)
// and show them in the UI.
//
// Note: These events could all be converted into actions that are handled by
// the Redux store in annotationUI.
// the Redux store in store.
var loadEvents = [events.ANNOTATION_CREATED,
events.ANNOTATION_UPDATED,
events.ANNOTATIONS_LOADED];
loadEvents.forEach(function (event) {
$rootScope.$on(event, function (event, annotation) {
annotationUI.addAnnotations([].concat(annotation));
store.addAnnotations([].concat(annotation));
});
});
......@@ -111,37 +111,37 @@ function RootThread($rootScope, annotationUI, drafts, searchFilter, viewFilter)
// that are empty.
deleteNewAndEmptyAnnotations();
annotationUI.addAnnotations([ann]);
store.addAnnotations([ann]);
// If the annotation is of type note or annotation, make sure
// the appropriate tab is selected. If it is of type reply, user
// stays in the selected tab.
if (metadata.isPageNote(ann)) {
annotationUI.selectTab(uiConstants.TAB_NOTES);
store.selectTab(uiConstants.TAB_NOTES);
} else if (metadata.isAnnotation(ann)) {
annotationUI.selectTab(uiConstants.TAB_ANNOTATIONS);
store.selectTab(uiConstants.TAB_ANNOTATIONS);
}
(ann.references || []).forEach(function (parent) {
annotationUI.setCollapsed(parent, false);
store.setCollapsed(parent, false);
});
});
// Remove any annotations that are deleted or unloaded
$rootScope.$on(events.ANNOTATION_DELETED, function (event, annotation) {
annotationUI.removeAnnotations([annotation]);
store.removeAnnotations([annotation]);
if (annotation.id) {
annotationUI.removeSelectedAnnotation(annotation.id);
store.removeSelectedAnnotation(annotation.id);
}
});
$rootScope.$on(events.ANNOTATIONS_UNLOADED, function (event, annotations) {
annotationUI.removeAnnotations(annotations);
store.removeAnnotations(annotations);
});
// Once the focused group state is moved to the app state store, then the
// logic in this event handler can be moved to the annotations reducer.
$rootScope.$on(events.GROUP_FOCUSED, function (event, focusedGroupId) {
var updatedAnnots = annotationUI.getState().annotations.filter(function (ann) {
var updatedAnnots = store.getState().annotations.filter(function (ann) {
return metadata.isNew(ann) && !metadata.isReply(ann);
}).map(function (ann) {
return Object.assign(ann, {
......@@ -149,7 +149,7 @@ function RootThread($rootScope, annotationUI, drafts, searchFilter, viewFilter)
});
});
if (updatedAnnots.length > 0) {
annotationUI.addAnnotations(updatedAnnots);
store.addAnnotations(updatedAnnots);
}
});
......
......@@ -33,16 +33,16 @@ var urlUtil = require('../util/url-util');
*
* @ngInject
*/
function serviceUrl(annotationUI, apiRoutes) {
function serviceUrl(store, apiRoutes) {
apiRoutes.links()
.then(annotationUI.updateLinks)
.then(store.updateLinks)
.catch(function(error) {
console.warn('The links API request was rejected: ' + error.message);
});
return function(linkName, params) {
var links = annotationUI.getState().links;
var links = store.getState().links;
if (links === null) {
return '';
......
......@@ -20,7 +20,7 @@ var CACHE_TTL = 5 * 60 * 1000; // 5 minutes
*
* @ngInject
*/
function session($q, $rootScope, analytics, annotationUI, api, auth,
function session($q, $rootScope, analytics, store, api, auth,
flash, raven, settings, serviceConfig) {
// Cache the result of load()
var lastLoad;
......@@ -93,11 +93,11 @@ function session($q, $rootScope, analytics, annotationUI, api, auth,
* @return {Profile} The updated profile data
*/
function update(model) {
var prevSession = annotationUI.getState().session;
var prevSession = store.getState().session;
var userChanged = model.userid !== prevSession.userid;
// Update the session model used by the application
annotationUI.updateSession(model);
store.updateSession(model);
lastLoad = Promise.resolve(model);
lastLoadTime = Date.now();
......@@ -167,9 +167,9 @@ function session($q, $rootScope, analytics, annotationUI, api, auth,
// For the moment, we continue to expose the session state as a property on
// this service. In future, other services which access the session state
// will do so directly from annotationUI or via selector functions
// will do so directly from store or via selector functions
get state() {
return annotationUI.getState().session;
return store.getState().session;
},
update,
......
......@@ -20,7 +20,7 @@ var Socket = require('../websocket');
* @param settings - Application settings
*/
// @ngInject
function Streamer($rootScope, annotationMapper, annotationUI, auth,
function Streamer($rootScope, annotationMapper, store, auth,
groups, session, settings) {
// The randomly generated session UUID
var clientId = uuid.v4();
......@@ -37,7 +37,7 @@ function Streamer($rootScope, annotationMapper, annotationUI, auth,
// app.
//
// This state should be managed as part of the global app state in
// annotationUI, but that is currently difficult because applying updates
// store, but that is currently difficult because applying updates
// requires filtering annotations against the focused group (information not
// currently stored in the app state) and triggering events in order to update
// the annotations displayed in the page.
......@@ -62,7 +62,7 @@ function Streamer($rootScope, annotationMapper, annotationUI, auth,
// focused group, since we only display annotations from the focused
// group and reload all annotations and discard pending updates
// when switching groups.
if (ann.group === groups.focused().id || !annotationUI.isSidebar()) {
if (ann.group === groups.focused().id || !store.isSidebar()) {
pendingUpdates[ann.id] = ann;
}
});
......@@ -78,14 +78,14 @@ function Streamer($rootScope, annotationMapper, annotationUI, auth,
// even if the annotation is from the current group, it might be for a
// new annotation (saved in pendingUpdates and removed above), that has
// not yet been loaded.
if (annotationUI.annotationExists(ann.id)) {
if (store.annotationExists(ann.id)) {
pendingDeletions[ann.id] = true;
}
});
break;
}
if (!annotationUI.isSidebar()) {
if (!store.isSidebar()) {
applyPendingUpdates();
}
}
......@@ -125,7 +125,7 @@ function Streamer($rootScope, annotationMapper, annotationUI, auth,
} else if (message.type === 'session-change') {
handleSessionChangeNotification(message);
} else if (message.type === 'whoyouare') {
var userid = annotationUI.getState().session.userid;
var userid = store.getState().session.userid;
if (message.userid !== userid) {
console.warn('WebSocket user ID "%s" does not match logged-in ID "%s"', message.userid, userid);
}
......
......@@ -8,7 +8,7 @@ var events = require('../../events');
describe('annotationMapper', function() {
var sandbox = sinon.sandbox.create();
var $rootScope;
var annotationUI;
var store;
var fakeApi;
var annotationMapper;
......@@ -21,15 +21,15 @@ describe('annotationMapper', function() {
};
angular.module('app', [])
.service('annotationMapper', require('../annotation-mapper'))
.service('annotationUI', require('../../store'))
.service('store', require('../../store'))
.value('api', fakeApi)
.value('settings', {});
angular.mock.module('app');
angular.mock.inject(function (_$rootScope_, _annotationUI_, _annotationMapper_) {
angular.mock.inject(function (_$rootScope_, _store_, _annotationMapper_) {
$rootScope = _$rootScope_;
annotationMapper = _annotationMapper_;
annotationUI = _annotationUI_;
store = _store_;
});
});
......@@ -60,7 +60,7 @@ describe('annotationMapper', function() {
it('triggers the annotationUpdated event for each loaded annotation', function () {
sandbox.stub($rootScope, '$broadcast');
var annotations = immutable([{id: 1}, {id: 2}, {id: 3}]);
annotationUI.addAnnotations(angular.copy(annotations));
store.addAnnotations(angular.copy(annotations));
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$broadcast);
......@@ -72,7 +72,7 @@ describe('annotationMapper', function() {
sandbox.stub($rootScope, '$broadcast');
var annotations = [{id: 1}];
var replies = [{id: 2}, {id: 3}, {id: 4}];
annotationUI.addAnnotations([{id:3}]);
store.addAnnotations([{id:3}]);
annotationMapper.loadAnnotations(annotations, replies);
assert($rootScope.$broadcast.calledWith(events.ANNOTATION_UPDATED,
......@@ -82,7 +82,7 @@ describe('annotationMapper', function() {
it('replaces the properties on the cached annotation with those from the loaded one', function () {
sandbox.stub($rootScope, '$broadcast');
var annotations = [{id: 1, url: 'http://example.com'}];
annotationUI.addAnnotations([{id:1, $tag: 'tag1'}]);
store.addAnnotations([{id:1, $tag: 'tag1'}]);
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$broadcast);
......@@ -95,7 +95,7 @@ describe('annotationMapper', function() {
it('excludes cached annotations from the annotationLoaded event', function () {
sandbox.stub($rootScope, '$broadcast');
var annotations = [{id: 1, url: 'http://example.com'}];
annotationUI.addAnnotations([{id: 1, $tag: 'tag1'}]);
store.addAnnotations([{id: 1, $tag: 'tag1'}]);
annotationMapper.loadAnnotations(annotations);
assert.called($rootScope.$broadcast);
......@@ -115,7 +115,7 @@ describe('annotationMapper', function() {
it('replaces the properties on the cached annotation with those from the deleted one', function () {
sandbox.stub($rootScope, '$broadcast');
var annotations = [{id: 1, url: 'http://example.com'}];
annotationUI.addAnnotations([{id: 1, $tag: 'tag1'}]);
store.addAnnotations([{id: 1, $tag: 'tag1'}]);
annotationMapper.unloadAnnotations(annotations);
assert.calledWith($rootScope.$broadcast, events.ANNOTATIONS_UNLOADED, [{
......
......@@ -6,7 +6,7 @@ var EventEmitter = require('tiny-emitter');
var annotationFixtures = require('../../test/annotation-fixtures');
var events = require('../../events');
var FrameSync = require('../frame-sync').default;
var fakeStore = require('../../test/fake-redux-store');
var createFakeStore = require('../../test/fake-redux-store');
var formatAnnot = require('../frame-sync').formatAnnot;
var uiConstants = require('../../ui-constants');
......@@ -51,7 +51,7 @@ var fixtures = {
};
describe('sidebar.frame-sync', function () {
var fakeAnnotationUI;
var fakeStore;
var fakeBridge;
var frameSync;
var $rootScope;
......@@ -62,7 +62,7 @@ describe('sidebar.frame-sync', function () {
});
beforeEach(function () {
fakeAnnotationUI = fakeStore({annotations: []}, {
fakeStore = createFakeStore({annotations: []}, {
connectFrame: sinon.stub(),
destroyFrame: sinon.stub(),
findIDsForTags: sinon.stub(),
......@@ -92,7 +92,7 @@ describe('sidebar.frame-sync', function () {
angular.mock.module('app', {
Discovery: FakeDiscovery,
annotationUI: fakeAnnotationUI,
store: fakeStore,
bridge: fakeBridge,
});
......@@ -108,7 +108,7 @@ describe('sidebar.frame-sync', function () {
context('when annotations are loaded into the sidebar', function () {
it('sends a "loadAnnotations" message to the frame', function () {
fakeAnnotationUI.setState({annotations: [fixtures.ann]});
fakeStore.setState({annotations: [fixtures.ann]});
assert.calledWithMatch(fakeBridge.call, 'loadAnnotations', sinon.match([
formatAnnot(fixtures.ann),
]));
......@@ -116,10 +116,10 @@ describe('sidebar.frame-sync', function () {
it('sends a "loadAnnotations" message only for new annotations', function () {
var ann2 = Object.assign({}, fixtures.ann, {$tag: 't2', id: 'a2'});
fakeAnnotationUI.setState({annotations: [fixtures.ann]});
fakeStore.setState({annotations: [fixtures.ann]});
fakeBridge.call.reset();
fakeAnnotationUI.setState({annotations: [fixtures.ann, ann2]});
fakeStore.setState({annotations: [fixtures.ann, ann2]});
assert.calledWithMatch(fakeBridge.call, 'loadAnnotations', sinon.match([
formatAnnot(ann2),
......@@ -127,37 +127,37 @@ describe('sidebar.frame-sync', function () {
});
it('does not send a "loadAnnotations" message for replies', function () {
fakeAnnotationUI.setState({annotations: [annotationFixtures.newReply()]});
fakeStore.setState({annotations: [annotationFixtures.newReply()]});
assert.isFalse(fakeBridge.call.calledWith('loadAnnotations'));
});
});
context('when annotation count has changed', function () {
it('sends a "publicAnnotationCountChanged" message to the frame when there are public annotations', function () {
fakeAnnotationUI.setState({
fakeStore.setState({
annotations: [annotationFixtures.publicAnnotation()],
});
assert.calledWithMatch(fakeBridge.call, 'publicAnnotationCountChanged', sinon.match(1));
});
it('sends a "publicAnnotationCountChanged" message to the frame when there are only private annotations', function () {
fakeAnnotationUI.setState({
fakeStore.setState({
annotations: [annotationFixtures.defaultAnnotation()],
});
assert.calledWithMatch(fakeBridge.call, 'publicAnnotationCountChanged', sinon.match(0));
});
it('does not send a "publicAnnotationCountChanged" message to the frame if annotation fetch is not complete', function () {
fakeAnnotationUI.frames.returns([{uri: 'http://example.com'}]);
fakeAnnotationUI.setState({
fakeStore.frames.returns([{uri: 'http://example.com'}]);
fakeStore.setState({
annotations: [annotationFixtures.publicAnnotation()],
});
assert.isFalse(fakeBridge.call.calledWith('publicAnnotationCountChanged'));
});
it('does not send a "publicAnnotationCountChanged" message if there are no connected frames', function () {
fakeAnnotationUI.frames.returns([]);
fakeAnnotationUI.setState({
fakeStore.frames.returns([]);
fakeStore.setState({
annotations: [annotationFixtures.publicAnnotation()],
});
assert.isFalse(fakeBridge.call.calledWith('publicAnnotationCountChanged'));
......@@ -166,8 +166,8 @@ describe('sidebar.frame-sync', function () {
context('when annotations are removed from the sidebar', function () {
it('sends a "deleteAnnotation" message to the frame', function () {
fakeAnnotationUI.setState({annotations: [fixtures.ann]});
fakeAnnotationUI.setState({annotations: []});
fakeStore.setState({annotations: [fixtures.ann]});
fakeStore.setState({annotations: []});
assert.calledWithMatch(fakeBridge.call, 'deleteAnnotation',
sinon.match(formatAnnot(fixtures.ann)));
});
......@@ -210,7 +210,7 @@ describe('sidebar.frame-sync', function () {
expireDebounceTimeout();
assert.calledWith(fakeAnnotationUI.updateAnchorStatus, { t1: 'anchored' });
assert.calledWith(fakeStore.updateAnchorStatus, { t1: 'anchored' });
});
it('coalesces multiple "sync" messages', () => {
......@@ -219,7 +219,7 @@ describe('sidebar.frame-sync', function () {
expireDebounceTimeout();
assert.calledWith(fakeAnnotationUI.updateAnchorStatus, {
assert.calledWith(fakeStore.updateAnchorStatus, {
t1: 'anchored',
t2: 'orphan',
});
......@@ -249,7 +249,7 @@ describe('sidebar.frame-sync', function () {
fakeBridge.emit('connect', fakeChannel);
assert.calledWith(fakeAnnotationUI.connectFrame, {
assert.calledWith(fakeStore.connectFrame, {
id: frameInfo.frameIdentifier,
metadata: frameInfo.metadata,
uri: frameInfo.uri,
......@@ -263,32 +263,32 @@ describe('sidebar.frame-sync', function () {
it('removes the frame from the frames list', function () {
fakeBridge.emit('destroyFrame', frameId);
assert.calledWith(fakeAnnotationUI.destroyFrame, fixtures.framesListEntry);
assert.calledWith(fakeStore.destroyFrame, fixtures.framesListEntry);
});
});
describe('on "showAnnotations" message', function () {
it('selects annotations which have an ID', function () {
fakeAnnotationUI.findIDsForTags.returns(['id1','id2','id3']);
fakeStore.findIDsForTags.returns(['id1','id2','id3']);
fakeBridge.emit('showAnnotations', ['tag1', 'tag2', 'tag3']);
assert.calledWith(fakeAnnotationUI.selectAnnotations, ['id1', 'id2', 'id3']);
assert.calledWith(fakeAnnotationUI.selectTab, uiConstants.TAB_ANNOTATIONS);
assert.calledWith(fakeStore.selectAnnotations, ['id1', 'id2', 'id3']);
assert.calledWith(fakeStore.selectTab, uiConstants.TAB_ANNOTATIONS);
});
});
describe('on "focusAnnotations" message', function () {
it('focuses the annotations', function () {
fakeBridge.emit('focusAnnotations', ['tag1', 'tag2', 'tag3']);
assert.calledWith(fakeAnnotationUI.focusAnnotations, ['tag1', 'tag2', 'tag3']);
assert.calledWith(fakeStore.focusAnnotations, ['tag1', 'tag2', 'tag3']);
});
});
describe('on "toggleAnnotationSelection" message', function () {
it('toggles the selected state of the annotations', function () {
fakeAnnotationUI.findIDsForTags.returns(['id1','id2','id3']);
fakeStore.findIDsForTags.returns(['id1','id2','id3']);
fakeBridge.emit('toggleAnnotationSelection', ['tag1', 'tag2', 'tag3']);
assert.calledWith(fakeAnnotationUI.toggleSelectedAnnotations, ['id1', 'id2', 'id3']);
assert.calledWith(fakeStore.toggleSelectedAnnotations, ['id1', 'id2', 'id3']);
});
});
......
......@@ -13,7 +13,7 @@ var sessionWithThreeGroups = function() {
};
describe('groups', function() {
var fakeAnnotationUI;
var fakeStore;
var fakeIsSidebar;
var fakeSession;
var fakeSettings;
......@@ -26,7 +26,7 @@ describe('groups', function() {
beforeEach(function() {
sandbox = sinon.sandbox.create();
fakeAnnotationUI = fakeReduxStore({
fakeStore = fakeReduxStore({
searchUris: ['http://example.org'],
},{
searchUris() {
......@@ -77,7 +77,7 @@ describe('groups', function() {
});
function service() {
return groups(fakeRootScope, fakeAnnotationUI, fakeApi, fakeIsSidebar, fakeLocalStorage, fakeServiceUrl,
return groups(fakeRootScope, fakeStore, fakeApi, fakeIsSidebar, fakeLocalStorage, fakeServiceUrl,
fakeSession, fakeSettings);
}
......@@ -134,9 +134,9 @@ describe('groups', function() {
it('waits for the document URL to be determined', () => {
var svc = service();
fakeAnnotationUI.setState({ searchUris: [] });
fakeStore.setState({ searchUris: [] });
var loaded = svc.load();
fakeAnnotationUI.setState({ searchUris: ['https://asite.com'] });
fakeStore.setState({ searchUris: ['https://asite.com'] });
return loaded.then(() => {
assert.calledWith(fakeApi.groups.list, { document_uri: 'https://asite.com' });
......@@ -150,7 +150,7 @@ describe('groups', function() {
});
it('does not wait for the document URL', () => {
fakeAnnotationUI.setState({ searchUris: [] });
fakeStore.setState({ searchUris: [] });
var svc = service();
return svc.load().then(() => {
assert.calledWith(fakeApi.groups.list, {});
......
......@@ -24,7 +24,7 @@ var fixtures = immutable({
});
describe('rootThread', function () {
var fakeAnnotationUI;
var fakeStore;
var fakeBuildThread;
var fakeDrafts;
var fakeSearchFilter;
......@@ -35,7 +35,7 @@ describe('rootThread', function () {
var rootThread;
beforeEach(function () {
fakeAnnotationUI = {
fakeStore = {
state: {
annotations: [],
expanded: {},
......@@ -79,7 +79,7 @@ describe('rootThread', function () {
};
angular.module('app', [])
.value('annotationUI', fakeAnnotationUI)
.value('store', fakeStore)
.value('drafts', fakeDrafts)
.value('searchFilter', fakeSearchFilter)
.value('viewFilter', fakeViewFilter)
......@@ -97,53 +97,53 @@ describe('rootThread', function () {
describe('#thread', function () {
it('returns the result of buildThread()', function() {
assert.equal(rootThread.thread(fakeAnnotationUI.state), fixtures.emptyThread);
assert.equal(rootThread.thread(fakeStore.state), fixtures.emptyThread);
});
it('passes loaded annotations to buildThread()', function () {
var annotation = annotationFixtures.defaultAnnotation();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
annotations: [annotation],
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
assert.calledWith(fakeBuildThread, sinon.match([annotation]));
});
it('passes the current selection to buildThread()', function () {
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
selectedAnnotationMap: {id1: true, id2: true},
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
assert.calledWith(fakeBuildThread, [], sinon.match({
selected: ['id1', 'id2'],
}));
});
it('passes the current expanded set to buildThread()', function () {
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
expanded: {id1: true, id2: true},
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
assert.calledWith(fakeBuildThread, [], sinon.match({
expanded: {id1: true, id2: true},
}));
});
it('passes the current force-visible set to buildThread()', function () {
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
forceVisible: {id1: true, id2: true},
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
assert.calledWith(fakeBuildThread, [], sinon.match({
forceVisible: ['id1', 'id2'],
}));
});
it('passes the highlighted set to buildThread()', function () {
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
highlighted: ['id1', 'id2'],
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
assert.calledWith(fakeBuildThread, [], sinon.match({
highlighted: ['id1', 'id2'],
}));
......@@ -179,11 +179,11 @@ describe('rootThread', function () {
}];
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state, {
fakeStore.state = Object.assign({}, fakeStore.state, {
sortKey: testCase.order,
sortKeysAvailable: [testCase.order],
});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var sortCompareFn = fakeBuildThread.args[0][1].sortCompareFn;
var actualOrder = sortBy(annotations, sortCompareFn).map(function (annot) {
return annotations.indexOf(annot);
......@@ -200,10 +200,10 @@ describe('rootThread', function () {
it('filter matches only annotations when Annotations tab is selected', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{selectedTab: uiConstants.TAB_ANNOTATIONS});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
var annotation = {target: [{ selector: {} }]};
......@@ -213,10 +213,10 @@ describe('rootThread', function () {
it('filter matches only notes when Notes tab is selected', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{selectedTab: uiConstants.TAB_NOTES});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
assert.isTrue(threadFilterFn({annotation: {target: [{}]}}));
......@@ -225,10 +225,10 @@ describe('rootThread', function () {
it('filter matches only orphans when Orphans tab is selected', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{selectedTab: uiConstants.TAB_ORPHANS});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
var orphan = Object.assign(annotationFixtures.defaultAnnotation(),
......@@ -240,10 +240,10 @@ describe('rootThread', function () {
it('filter does not match notes when Annotations tab is selected', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{selectedTab: uiConstants.TAB_ANNOTATIONS});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
assert.isFalse(threadFilterFn({annotation: {target: [{}]}}));
......@@ -252,10 +252,10 @@ describe('rootThread', function () {
it('filter does not match orphans when Annotations tab is selected', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{selectedTab: uiConstants.TAB_ANNOTATIONS});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
assert.isFalse(threadFilterFn({annotation: {$orphan: true}}));
......@@ -263,10 +263,10 @@ describe('rootThread', function () {
it('does not filter annotations when not in the sidebar', function () {
fakeBuildThread.reset();
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{isSidebar: false});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var threadFilterFn = fakeBuildThread.args[0][1].threadFilterFn;
// There should be no thread filter function on the stream and standalone
......@@ -281,9 +281,9 @@ describe('rootThread', function () {
var filters = [{any: {terms: ['queryterm']}}];
var annotation = annotationFixtures.defaultAnnotation();
fakeSearchFilter.generateFacetedFilter.returns(filters);
fakeAnnotationUI.state = Object.assign({}, fakeAnnotationUI.state,
fakeStore.state = Object.assign({}, fakeStore.state,
{filterQuery: 'queryterm'});
rootThread.thread(fakeAnnotationUI.state);
rootThread.thread(fakeStore.state);
var filterFn = fakeBuildThread.args[0][1].filterFn;
fakeViewFilter.filter.returns([annotation]);
......@@ -299,8 +299,8 @@ describe('rootThread', function () {
unroll('adds or updates annotations when #event event occurs', function (testCase) {
$rootScope.$broadcast(testCase.event, testCase.annotations);
var annotations = [].concat(testCase.annotations);
assert.notCalled(fakeAnnotationUI.removeAnnotations);
assert.calledWith(fakeAnnotationUI.addAnnotations, sinon.match(annotations));
assert.notCalled(fakeStore.removeAnnotations);
assert.calledWith(fakeStore.addAnnotations, sinon.match(annotations));
}, [
{event: events.BEFORE_ANNOTATION_CREATED, annotations: annot},
{event: events.ANNOTATION_CREATED, annotations: annot},
......@@ -311,13 +311,13 @@ describe('rootThread', function () {
it('expands the parents of new annotations', function () {
var reply = annotationFixtures.oldReply();
$rootScope.$broadcast(events.BEFORE_ANNOTATION_CREATED, reply);
assert.calledWith(fakeAnnotationUI.setCollapsed, reply.references[0], false);
assert.calledWith(fakeStore.setCollapsed, reply.references[0], false);
});
unroll('removes annotations when #event event occurs', function (testCase) {
$rootScope.$broadcast(testCase.event, testCase.annotations);
var annotations = [].concat(testCase.annotations);
assert.calledWith(fakeAnnotationUI.removeAnnotations, sinon.match(annotations));
assert.calledWith(fakeStore.removeAnnotations, sinon.match(annotations));
}, [
{event: events.ANNOTATION_DELETED, annotations: annot},
{event: events.ANNOTATIONS_UNLOADED, annotations: [annot]},
......@@ -325,7 +325,7 @@ describe('rootThread', function () {
it('deselects deleted annotations', function () {
$rootScope.$broadcast(events.ANNOTATION_DELETED, annot);
assert.calledWith(fakeAnnotationUI.removeSelectedAnnotation, annot.id);
assert.calledWith(fakeStore.removeSelectedAnnotation, annot.id);
});
describe('when a new annotation is created', function () {
......@@ -336,7 +336,7 @@ describe('rootThread', function () {
$rootScope.$on(events.ANNOTATION_DELETED, onDelete);
existingNewAnnot = {$tag: 'a-new-tag'};
fakeAnnotationUI.state.annotations.push(existingNewAnnot);
fakeStore.state.annotations.push(existingNewAnnot);
});
it('removes drafts for new and empty annotations', function () {
......@@ -371,7 +371,7 @@ describe('rootThread', function () {
it('does not remove saved annotations', function () {
var ann = annotationFixtures.defaultAnnotation();
fakeAnnotationUI.state.annotations = [ann];
fakeStore.state.annotations = [ann];
$rootScope.$broadcast(events.BEFORE_ANNOTATION_CREATED,
annotationFixtures.newAnnotation());
......@@ -384,30 +384,30 @@ describe('rootThread', function () {
describe('when the focused group changes', function () {
it('moves new annotations to the focused group', function () {
fakeAnnotationUI.state.annotations = [{$tag: 'a-tag'}];
fakeStore.state.annotations = [{$tag: 'a-tag'}];
$rootScope.$broadcast(events.GROUP_FOCUSED, 'private-group');
assert.calledWith(fakeAnnotationUI.addAnnotations, sinon.match([{
assert.calledWith(fakeStore.addAnnotations, sinon.match([{
$tag: 'a-tag',
group: 'private-group',
}]));
});
it('does not move replies to the new group', function () {
fakeAnnotationUI.state.annotations = [annotationFixtures.newReply()];
fakeStore.state.annotations = [annotationFixtures.newReply()];
$rootScope.$broadcast(events.GROUP_FOCUSED, 'private-group');
assert.notCalled(fakeAnnotationUI.addAnnotations);
assert.notCalled(fakeStore.addAnnotations);
});
it('does not move saved annotations to the new group', function () {
fakeAnnotationUI.state.annotations = [annotationFixtures.defaultAnnotation()];
fakeStore.state.annotations = [annotationFixtures.defaultAnnotation()];
$rootScope.$broadcast(events.GROUP_FOCUSED, 'private-group');
assert.notCalled(fakeAnnotationUI.addAnnotations);
assert.notCalled(fakeStore.addAnnotations);
});
});
});
......@@ -2,8 +2,8 @@
var proxyquire = require('proxyquire');
/** Return a fake annotationUI object. */
function fakeAnnotationUI() {
/** Return a fake store object. */
function fakeStore() {
var links = null;
return {
updateLinks: function(newLinks) {
......@@ -24,16 +24,16 @@ function createServiceUrl(linksPromise) {
'../util/url-util': { replaceURLParams: replaceURLParams },
});
var annotationUI = fakeAnnotationUI();
var store = fakeStore();
var apiRoutes = {
links: sinon.stub().returns(linksPromise),
};
return {
annotationUI: annotationUI,
store: store,
apiRoutes,
serviceUrl: serviceUrlFactory(annotationUI, apiRoutes),
serviceUrl: serviceUrlFactory(store, apiRoutes),
replaceURLParams: replaceURLParams,
};
}
......@@ -76,7 +76,7 @@ describe('sidebar.service-url', function () {
});
context('after the API response has been received', function() {
var annotationUI;
var store;
var linksPromise;
var replaceURLParams;
var serviceUrl;
......@@ -90,14 +90,14 @@ describe('sidebar.service-url', function () {
var parts = createServiceUrl(linksPromise);
annotationUI = parts.annotationUI;
store = parts.store;
serviceUrl = parts.serviceUrl;
replaceURLParams = parts.replaceURLParams;
});
it('updates annotationUI with the real links', function() {
it('updates store with the real links', function() {
return linksPromise.then(function(links) {
assert.deepEqual(annotationUI.getState(), {links: links});
assert.deepEqual(store.getState(), {links: links});
});
});
......
......@@ -32,7 +32,7 @@ describe('sidebar.session', function () {
track: sinon.stub(),
events: require('../analytics')().events,
};
var fakeAnnotationUI = {
var fakeStore = {
getState: function () {
return {session: state};
},
......@@ -60,7 +60,7 @@ describe('sidebar.session', function () {
mock.module('h', {
analytics: fakeAnalytics,
annotationUI: fakeAnnotationUI,
store: fakeStore,
api: fakeApi,
auth: fakeAuth,
flash: fakeFlash,
......
......@@ -67,7 +67,7 @@ inherits(FakeSocket, EventEmitter);
describe('Streamer', function () {
var fakeAnnotationMapper;
var fakeAnnotationUI;
var fakeStore;
var fakeAuth;
var fakeGroups;
var fakeRootScope;
......@@ -80,7 +80,7 @@ describe('Streamer', function () {
activeStreamer = new Streamer(
fakeRootScope,
fakeAnnotationMapper,
fakeAnnotationUI,
fakeStore,
fakeAuth,
fakeGroups,
fakeSession,
......@@ -112,7 +112,7 @@ describe('Streamer', function () {
unloadAnnotations: sinon.stub(),
};
fakeAnnotationUI = {
fakeStore = {
annotationExists: sinon.stub().returns(false),
isSidebar: sinon.stub().returns(true),
getState: sinon.stub().returns({
......@@ -254,7 +254,7 @@ describe('Streamer', function () {
context('when the app is the stream', function () {
beforeEach(function () {
fakeAnnotationUI.isSidebar.returns(false);
fakeStore.isSidebar.returns(false);
});
it('does not defer updates', function () {
......@@ -288,7 +288,7 @@ describe('Streamer', function () {
it('saves pending deletions if the annotation is loaded', function () {
var id = fixtures.deleteNotification.payload[0].id;
fakeAnnotationUI.annotationExists.returns(true);
fakeStore.annotationExists.returns(true);
fakeWebSocket.notify(fixtures.deleteNotification);
......@@ -298,7 +298,7 @@ describe('Streamer', function () {
it('discards pending deletions if the annotation is not loaded', function () {
var id = fixtures.deleteNotification.payload[0].id;
fakeAnnotationUI.annotationExists.returns(false);
fakeStore.annotationExists.returns(false);
fakeWebSocket.notify(fixtures.deleteNotification);
......@@ -312,7 +312,7 @@ describe('Streamer', function () {
});
it('discards pending updates if an unloaded annotation is deleted', function () {
fakeAnnotationUI.annotationExists.returns(false);
fakeStore.annotationExists.returns(false);
fakeWebSocket.notify(fixtures.createNotification);
fakeWebSocket.notify(fixtures.deleteNotification);
......@@ -346,7 +346,7 @@ describe('Streamer', function () {
});
it('applies pending deletions', function () {
fakeAnnotationUI.annotationExists.returns(true);
fakeStore.annotationExists.returns(true);
fakeWebSocket.notify(fixtures.deleteNotification);
activeStreamer.applyPendingUpdates();
......@@ -382,7 +382,7 @@ describe('Streamer', function () {
}, changeEvents);
unroll('discards pending deletions when #event occurs', function (testCase) {
fakeAnnotationUI.annotationExists.returns(true);
fakeStore.annotationExists.returns(true);
fakeWebSocket.notify(fixtures.deleteNotification);
fakeRootScope.$broadcast(testCase.event, {id: 'an-id'});
......@@ -432,7 +432,7 @@ describe('Streamer', function () {
});
unroll('does nothing if the userid matches the logged-in userid', function (testCase) {
fakeAnnotationUI.getState.returns({
fakeStore.getState.returns({
session: {
userid: testCase.userid,
},
......@@ -454,7 +454,7 @@ describe('Streamer', function () {
}]);
unroll('logs a warning if the userid does not match the logged-in userid', function (testCase) {
fakeAnnotationUI.getState.returns({
fakeStore.getState.returns({
session: {
userid: testCase.userid,
},
......
......@@ -89,12 +89,12 @@ function store($rootScope, settings) {
enhancer);
// Expose helper functions that create actions as methods of the
// `annotationUI` service to make using them easier from app code. eg.
// `store` service to make using them easier from app code. eg.
//
// Instead of:
// annotationUI.dispatch(annotations.actions.addAnnotations(annotations))
// store.dispatch(annotations.actions.addAnnotations(annotations))
// You can use:
// annotationUI.addAnnotations(annotations)
// store.addAnnotations(annotations)
//
var actionCreators = redux.bindActionCreators(Object.assign({},
annotationsModule.actions,
......@@ -105,13 +105,13 @@ function store($rootScope, settings) {
viewerModule.actions
), store.dispatch);
// Expose selectors as methods of the `annotationUI` to make using them easier
// Expose selectors as methods of the `store` to make using them easier
// from app code.
//
// eg. Instead of:
// selection.isAnnotationSelected(annotationUI.getState(), id)
// selection.isAnnotationSelected(store.getState(), id)
// You can use:
// annotationUI.isAnnotationSelected(id)
// store.isAnnotationSelected(id)
var selectors = util.bindSelectors(Object.assign({},
annotationsModule.selectors,
framesModule.selectors,
......
......@@ -2,7 +2,7 @@
var immutable = require('seamless-immutable');
var annotationUIFactory = require('../index');
var storeFactory = require('../index');
var annotationFixtures = require('../../test/annotation-fixtures');
var metadata = require('../../annotation-metadata');
var unroll = require('../../../shared/test/util').unroll;
......@@ -23,12 +23,12 @@ var fixtures = immutable({
],
});
describe('annotationUI', function () {
var annotationUI;
describe('store', function () {
var store;
var fakeRootScope;
function tagForID(id) {
var storeAnn = annotationUI.findAnnotationByID(id);
var storeAnn = store.findAnnotationByID(id);
if (!storeAnn) {
throw new Error(`No annotation with ID ${id}`);
}
......@@ -37,25 +37,25 @@ describe('annotationUI', function () {
beforeEach(function () {
fakeRootScope = {$applyAsync: sinon.stub()};
annotationUI = annotationUIFactory(fakeRootScope, {});
store = storeFactory(fakeRootScope, {});
});
describe('initialization', function () {
it('does not set a selection when settings.annotations is null', function () {
assert.isFalse(annotationUI.hasSelectedAnnotations());
assert.equal(Object.keys(annotationUI.getState().expanded).length, 0);
assert.isFalse(store.hasSelectedAnnotations());
assert.equal(Object.keys(store.getState().expanded).length, 0);
});
it('sets the selection when settings.annotations is set', function () {
annotationUI = annotationUIFactory(fakeRootScope, {annotations: 'testid'});
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, {
store = storeFactory(fakeRootScope, {annotations: 'testid'});
assert.deepEqual(store.getState().selectedAnnotationMap, {
testid: true,
});
});
it('expands the selected annotations when settings.annotations is set', function () {
annotationUI = annotationUIFactory(fakeRootScope, {annotations: 'testid'});
assert.deepEqual(annotationUI.getState().expanded, {
store = storeFactory(fakeRootScope, {annotations: 'testid'});
assert.deepEqual(store.getState().expanded, {
testid: true,
});
});
......@@ -75,39 +75,39 @@ describe('annotationUI', function () {
it('adds annotations not in the store', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
assert.match(annotationUI.getState().annotations,
store.addAnnotations([annot]);
assert.match(store.getState().annotations,
[sinon.match(annot)]);
});
it('does not change `selectedTab` state if annotations are already loaded', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
store.addAnnotations([annot]);
var page = oldPageNote();
annotationUI.addAnnotations([page]);
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
store.addAnnotations([page]);
assert.equal(store.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
});
it('sets `selectedTab` to "note" if only page notes are present', function () {
var page = oldPageNote();
annotationUI.addAnnotations([page]);
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_NOTES);
store.addAnnotations([page]);
assert.equal(store.getState().selectedTab, uiConstants.TAB_NOTES);
});
it('leaves `selectedTab` as "annotation" if annotations and/or page notes are present', function () {
var page = oldPageNote();
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot, page]);
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
store.addAnnotations([annot, page]);
assert.equal(store.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
});
it('assigns a local tag to annotations', function () {
var annotA = Object.assign(defaultAnnotation(), {id: 'a1'});
var annotB = Object.assign(defaultAnnotation(), {id: 'a2'});
annotationUI.addAnnotations([annotA, annotB]);
store.addAnnotations([annotA, annotB]);
var tags = annotationUI.getState().annotations.map(function (a) {
var tags = store.getState().annotations.map(function (a) {
return a.$tag;
});
......@@ -116,23 +116,23 @@ describe('annotationUI', function () {
it('updates annotations with matching IDs in the store', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
store.addAnnotations([annot]);
var update = Object.assign({}, defaultAnnotation(), {text: 'update'});
annotationUI.addAnnotations([update]);
store.addAnnotations([update]);
var updatedAnnot = annotationUI.getState().annotations[0];
var updatedAnnot = store.getState().annotations[0];
assert.equal(updatedAnnot.text, 'update');
});
it('updates annotations with matching tags in the store', function () {
var annot = newAnnotation();
annot.$tag = 'local-tag';
annotationUI.addAnnotations([annot]);
store.addAnnotations([annot]);
var saved = Object.assign({}, annot, {id: 'server-id'});
annotationUI.addAnnotations([saved]);
store.addAnnotations([saved]);
var annots = annotationUI.getState().annotations;
var annots = store.getState().annotations;
assert.equal(annots.length, 1);
assert.equal(annots[0].id, 'server-id');
});
......@@ -144,8 +144,8 @@ describe('annotationUI', function () {
var now = new Date();
var nowStr = now.toISOString();
annotationUI.addAnnotations([newAnnotation()], now);
var annot = annotationUI.getState().annotations[0];
store.addAnnotations([newAnnotation()], now);
var annot = store.getState().annotations[0];
assert.equal(annot.created, nowStr);
assert.equal(annot.updated, nowStr);
......@@ -157,8 +157,8 @@ describe('annotationUI', function () {
annot.created = '2000-01-01T01:02:03Z';
annot.updated = '2000-01-01T04:05:06Z';
annotationUI.addAnnotations([annot], now);
var result = annotationUI.getState().annotations[0];
store.addAnnotations([annot], now);
var result = store.getState().annotations[0];
assert.equal(result.created, annot.created);
assert.equal(result.updated, annot.updated);
......@@ -166,40 +166,40 @@ describe('annotationUI', function () {
it('preserves anchoring status of updated annotations', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
store.addAnnotations([annot]);
store.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
var update = Object.assign({}, defaultAnnotation(), {text: 'update'});
annotationUI.addAnnotations([update]);
store.addAnnotations([update]);
var updatedAnnot = annotationUI.getState().annotations[0];
var updatedAnnot = store.getState().annotations[0];
assert.isFalse(updatedAnnot.$orphan);
});
it('sets the timeout flag on annotations that fail to anchor within a time limit', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
store.addAnnotations([annot]);
clock.tick(ANCHOR_TIME_LIMIT);
assert.isTrue(annotationUI.getState().annotations[0].$anchorTimeout);
assert.isTrue(store.getState().annotations[0].$anchorTimeout);
});
it('does not set the timeout flag on annotations that do anchor within a time limit', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
store.addAnnotations([annot]);
store.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
clock.tick(ANCHOR_TIME_LIMIT);
assert.isFalse(annotationUI.getState().annotations[0].$anchorTimeout);
assert.isFalse(store.getState().annotations[0].$anchorTimeout);
});
it('does not attempt to modify orphan status if annotations are removed before anchoring timeout expires', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
annotationUI.removeAnnotations([annot]);
store.addAnnotations([annot]);
store.updateAnchorStatus({ [tagForID(annot.id)]: 'anchored' });
store.removeAnnotations([annot]);
assert.doesNotThrow(function () {
clock.tick(ANCHOR_TIME_LIMIT);
......@@ -208,12 +208,12 @@ describe('annotationUI', function () {
it('does not expect annotations to anchor on the stream', function () {
var isOrphan = function () {
return !!metadata.isOrphan(annotationUI.getState().annotations[0]);
return !!metadata.isOrphan(store.getState().annotations[0]);
};
var annot = defaultAnnotation();
annotationUI.setAppIsSidebar(false);
annotationUI.addAnnotations([annot]);
store.setAppIsSidebar(false);
store.addAnnotations([annot]);
clock.tick(ANCHOR_TIME_LIMIT);
......@@ -221,41 +221,41 @@ describe('annotationUI', function () {
});
it('initializes the $orphan field for new annotations', function () {
annotationUI.addAnnotations([newAnnotation()]);
assert.isFalse(annotationUI.getState().annotations[0].$orphan);
store.addAnnotations([newAnnotation()]);
assert.isFalse(store.getState().annotations[0].$orphan);
});
it('adds multiple new annotations', function () {
annotationUI.addAnnotations([fixtures.newPair[0]]);
annotationUI.addAnnotations([fixtures.newPair[1]]);
store.addAnnotations([fixtures.newPair[0]]);
store.addAnnotations([fixtures.newPair[1]]);
assert.equal(annotationUI.getState().annotations.length, 2);
assert.equal(store.getState().annotations.length, 2);
});
});
describe('#removeAnnotations()', function () {
it('removes annotations from the current state', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.removeAnnotations([annot]);
assert.deepEqual(annotationUI.getState().annotations, []);
store.addAnnotations([annot]);
store.removeAnnotations([annot]);
assert.deepEqual(store.getState().annotations, []);
});
it('matches annotations to remove by ID', function () {
annotationUI.addAnnotations(fixtures.pair);
annotationUI.removeAnnotations([{id: fixtures.pair[0].id}]);
store.addAnnotations(fixtures.pair);
store.removeAnnotations([{id: fixtures.pair[0].id}]);
var ids = annotationUI.getState().annotations.map(function (a) {
var ids = store.getState().annotations.map(function (a) {
return a.id;
});
assert.deepEqual(ids, [fixtures.pair[1].id]);
});
it('matches annotations to remove by tag', function () {
annotationUI.addAnnotations(fixtures.pair);
annotationUI.removeAnnotations([{$tag: fixtures.pair[0].$tag}]);
store.addAnnotations(fixtures.pair);
store.removeAnnotations([{$tag: fixtures.pair[0].$tag}]);
var tags = annotationUI.getState().annotations.map(function (a) {
var tags = store.getState().annotations.map(function (a) {
return a.$tag;
});
assert.deepEqual(tags, [fixtures.pair[1].$tag]);
......@@ -263,26 +263,26 @@ describe('annotationUI', function () {
it('switches back to the Annotations tab when the last orphan is removed', function () {
var orphan = Object.assign(defaultAnnotation(), {$orphan: true});
annotationUI.addAnnotations([orphan]);
annotationUI.selectTab(uiConstants.TAB_ORPHANS);
annotationUI.removeAnnotations([orphan]);
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
store.addAnnotations([orphan]);
store.selectTab(uiConstants.TAB_ORPHANS);
store.removeAnnotations([orphan]);
assert.equal(store.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
});
});
describe('#clearAnnotations()', function () {
it('removes all annotations', function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.clearAnnotations();
assert.deepEqual(annotationUI.getState().annotations, []);
store.addAnnotations([annot]);
store.clearAnnotations();
assert.deepEqual(store.getState().annotations, []);
});
});
describe('#setShowHighlights()', function () {
unroll('sets the visibleHighlights state flag to #state', function (testCase) {
annotationUI.setShowHighlights(testCase.state);
assert.equal(annotationUI.getState().visibleHighlights, testCase.state);
store.setShowHighlights(testCase.state);
assert.equal(store.getState().visibleHighlights, testCase.state);
}, [
{state: true},
{state: false},
......@@ -292,239 +292,239 @@ describe('annotationUI', function () {
describe('#subscribe()', function () {
it('notifies subscribers when the UI state changes', function () {
var listener = sinon.stub();
annotationUI.subscribe(listener);
annotationUI.addAnnotations([annotationFixtures.defaultAnnotation()]);
store.subscribe(listener);
store.addAnnotations([annotationFixtures.defaultAnnotation()]);
assert.called(listener);
});
});
describe('#setForceVisible()', function () {
it('sets the visibility of the annotation', function () {
annotationUI.setForceVisible('id1', true);
assert.deepEqual(annotationUI.getState().forceVisible, {id1:true});
store.setForceVisible('id1', true);
assert.deepEqual(store.getState().forceVisible, {id1:true});
});
});
describe('#setCollapsed()', function () {
it('sets the expanded state of the annotation', function () {
annotationUI.setCollapsed('parent_id', false);
assert.deepEqual(annotationUI.getState().expanded, {'parent_id': true});
store.setCollapsed('parent_id', false);
assert.deepEqual(store.getState().expanded, {'parent_id': true});
});
});
describe('#focusAnnotations()', function () {
it('adds the passed annotations to the focusedAnnotationMap', function () {
annotationUI.focusAnnotations([1, 2, 3]);
assert.deepEqual(annotationUI.getState().focusedAnnotationMap, {
store.focusAnnotations([1, 2, 3]);
assert.deepEqual(store.getState().focusedAnnotationMap, {
1: true, 2: true, 3: true,
});
});
it('replaces any annotations originally in the map', function () {
annotationUI.focusAnnotations([1]);
annotationUI.focusAnnotations([2, 3]);
assert.deepEqual(annotationUI.getState().focusedAnnotationMap, {
store.focusAnnotations([1]);
store.focusAnnotations([2, 3]);
assert.deepEqual(store.getState().focusedAnnotationMap, {
2: true, 3: true,
});
});
it('nulls the map if no annotations are focused', function () {
annotationUI.focusAnnotations([1]);
annotationUI.focusAnnotations([]);
assert.isNull(annotationUI.getState().focusedAnnotationMap);
store.focusAnnotations([1]);
store.focusAnnotations([]);
assert.isNull(store.getState().focusedAnnotationMap);
});
});
describe('#hasSelectedAnnotations', function () {
it('returns true if there are any selected annotations', function () {
annotationUI.selectAnnotations([1]);
assert.isTrue(annotationUI.hasSelectedAnnotations());
store.selectAnnotations([1]);
assert.isTrue(store.hasSelectedAnnotations());
});
it('returns false if there are no selected annotations', function () {
assert.isFalse(annotationUI.hasSelectedAnnotations());
assert.isFalse(store.hasSelectedAnnotations());
});
});
describe('#isAnnotationSelected', function () {
it('returns true if the id provided is selected', function () {
annotationUI.selectAnnotations([1]);
assert.isTrue(annotationUI.isAnnotationSelected(1));
store.selectAnnotations([1]);
assert.isTrue(store.isAnnotationSelected(1));
});
it('returns false if the id provided is not selected', function () {
annotationUI.selectAnnotations([1]);
assert.isFalse(annotationUI.isAnnotationSelected(2));
store.selectAnnotations([1]);
assert.isFalse(store.isAnnotationSelected(2));
});
it('returns false if there are no selected annotations', function () {
assert.isFalse(annotationUI.isAnnotationSelected(1));
assert.isFalse(store.isAnnotationSelected(1));
});
});
describe('#selectAnnotations()', function () {
it('adds the passed annotations to the selectedAnnotationMap', function () {
annotationUI.selectAnnotations([1, 2, 3]);
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, {
store.selectAnnotations([1, 2, 3]);
assert.deepEqual(store.getState().selectedAnnotationMap, {
1: true, 2: true, 3: true,
});
});
it('replaces any annotations originally in the map', function () {
annotationUI.selectAnnotations([1]);
annotationUI.selectAnnotations([2, 3]);
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, {
store.selectAnnotations([1]);
store.selectAnnotations([2, 3]);
assert.deepEqual(store.getState().selectedAnnotationMap, {
2: true, 3: true,
});
});
it('nulls the map if no annotations are selected', function () {
annotationUI.selectAnnotations([1]);
annotationUI.selectAnnotations([]);
assert.isNull(annotationUI.getState().selectedAnnotationMap);
store.selectAnnotations([1]);
store.selectAnnotations([]);
assert.isNull(store.getState().selectedAnnotationMap);
});
});
describe('#toggleSelectedAnnotations()', function () {
it('adds annotations missing from the selectedAnnotationMap', function () {
annotationUI.selectAnnotations([1, 2]);
annotationUI.toggleSelectedAnnotations([3, 4]);
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, {
store.selectAnnotations([1, 2]);
store.toggleSelectedAnnotations([3, 4]);
assert.deepEqual(store.getState().selectedAnnotationMap, {
1: true, 2: true, 3: true, 4: true,
});
});
it('removes annotations already in the selectedAnnotationMap', function () {
annotationUI.selectAnnotations([1, 3]);
annotationUI.toggleSelectedAnnotations([1, 2]);
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, { 2: true, 3: true });
store.selectAnnotations([1, 3]);
store.toggleSelectedAnnotations([1, 2]);
assert.deepEqual(store.getState().selectedAnnotationMap, { 2: true, 3: true });
});
it('nulls the map if no annotations are selected', function () {
annotationUI.selectAnnotations([1]);
annotationUI.toggleSelectedAnnotations([1]);
assert.isNull(annotationUI.getState().selectedAnnotationMap);
store.selectAnnotations([1]);
store.toggleSelectedAnnotations([1]);
assert.isNull(store.getState().selectedAnnotationMap);
});
});
describe('#removeSelectedAnnotation()', function () {
it('removes an annotation from the selectedAnnotationMap', function () {
annotationUI.selectAnnotations([1, 2, 3]);
annotationUI.removeSelectedAnnotation(2);
assert.deepEqual(annotationUI.getState().selectedAnnotationMap, {
store.selectAnnotations([1, 2, 3]);
store.removeSelectedAnnotation(2);
assert.deepEqual(store.getState().selectedAnnotationMap, {
1: true, 3: true,
});
});
it('nulls the map if no annotations are selected', function () {
annotationUI.selectAnnotations([1]);
annotationUI.removeSelectedAnnotation(1);
assert.isNull(annotationUI.getState().selectedAnnotationMap);
store.selectAnnotations([1]);
store.removeSelectedAnnotation(1);
assert.isNull(store.getState().selectedAnnotationMap);
});
});
describe('#clearSelectedAnnotations()', function () {
it('removes all annotations from the selection', function () {
annotationUI.selectAnnotations([1]);
annotationUI.clearSelectedAnnotations();
assert.isNull(annotationUI.getState().selectedAnnotationMap);
store.selectAnnotations([1]);
store.clearSelectedAnnotations();
assert.isNull(store.getState().selectedAnnotationMap);
});
it('clears the current search query', function () {
annotationUI.setFilterQuery('foo');
annotationUI.clearSelectedAnnotations();
assert.isNull(annotationUI.getState().filterQuery);
store.setFilterQuery('foo');
store.clearSelectedAnnotations();
assert.isNull(store.getState().filterQuery);
});
});
describe('#setFilterQuery()', function () {
it('sets the filter query', function () {
annotationUI.setFilterQuery('a-query');
assert.equal(annotationUI.getState().filterQuery, 'a-query');
store.setFilterQuery('a-query');
assert.equal(store.getState().filterQuery, 'a-query');
});
it('resets the force-visible and expanded sets', function () {
annotationUI.setForceVisible('123', true);
annotationUI.setCollapsed('456', false);
annotationUI.setFilterQuery('some-query');
assert.deepEqual(annotationUI.getState().forceVisible, {});
assert.deepEqual(annotationUI.getState().expanded, {});
store.setForceVisible('123', true);
store.setCollapsed('456', false);
store.setFilterQuery('some-query');
assert.deepEqual(store.getState().forceVisible, {});
assert.deepEqual(store.getState().expanded, {});
});
});
describe('#highlightAnnotations()', function () {
it('sets the highlighted annotations', function () {
annotationUI.highlightAnnotations(['id1', 'id2']);
assert.deepEqual(annotationUI.getState().highlighted, ['id1', 'id2']);
store.highlightAnnotations(['id1', 'id2']);
assert.deepEqual(store.getState().highlighted, ['id1', 'id2']);
});
});
describe('#selectTab()', function () {
it('sets the selected tab', function () {
annotationUI.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
store.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.equal(store.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
});
it('ignores junk tag names', function () {
annotationUI.selectTab('flibbertigibbert');
assert.equal(annotationUI.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
store.selectTab('flibbertigibbert');
assert.equal(store.getState().selectedTab, uiConstants.TAB_ANNOTATIONS);
});
it('allows sorting annotations by time and document location', function () {
annotationUI.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.deepEqual(annotationUI.getState().sortKeysAvailable, ['Newest', 'Oldest', 'Location']);
store.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.deepEqual(store.getState().sortKeysAvailable, ['Newest', 'Oldest', 'Location']);
});
it('allows sorting page notes by time', function () {
annotationUI.selectTab(uiConstants.TAB_NOTES);
assert.deepEqual(annotationUI.getState().sortKeysAvailable, ['Newest', 'Oldest']);
store.selectTab(uiConstants.TAB_NOTES);
assert.deepEqual(store.getState().sortKeysAvailable, ['Newest', 'Oldest']);
});
it('allows sorting orphans by time and document location', function () {
annotationUI.selectTab(uiConstants.TAB_ORPHANS);
assert.deepEqual(annotationUI.getState().sortKeysAvailable, ['Newest', 'Oldest', 'Location']);
store.selectTab(uiConstants.TAB_ORPHANS);
assert.deepEqual(store.getState().sortKeysAvailable, ['Newest', 'Oldest', 'Location']);
});
it('sorts annotations by document location by default', function () {
annotationUI.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.deepEqual(annotationUI.getState().sortKey, 'Location');
store.selectTab(uiConstants.TAB_ANNOTATIONS);
assert.deepEqual(store.getState().sortKey, 'Location');
});
it('sorts page notes from oldest to newest by default', function () {
annotationUI.selectTab(uiConstants.TAB_NOTES);
assert.deepEqual(annotationUI.getState().sortKey, 'Oldest');
store.selectTab(uiConstants.TAB_NOTES);
assert.deepEqual(store.getState().sortKey, 'Oldest');
});
it('sorts orphans by document location by default', function () {
annotationUI.selectTab(uiConstants.TAB_ORPHANS);
assert.deepEqual(annotationUI.getState().sortKey, 'Location');
store.selectTab(uiConstants.TAB_ORPHANS);
assert.deepEqual(store.getState().sortKey, 'Location');
});
it('does not reset the sort key unless necessary', function () {
// Select the tab, setting sort key to 'Oldest', and then manually
// override the sort key.
annotationUI.selectTab(uiConstants.TAB_NOTES);
annotationUI.setSortKey('Newest');
store.selectTab(uiConstants.TAB_NOTES);
store.setSortKey('Newest');
annotationUI.selectTab(uiConstants.TAB_NOTES);
store.selectTab(uiConstants.TAB_NOTES);
assert.equal(annotationUI.getState().sortKey, 'Newest');
assert.equal(store.getState().sortKey, 'Newest');
});
});
describe('#updatingAnchorStatus', function () {
it("updates the annotation's orphan flag", function () {
var annot = defaultAnnotation();
annotationUI.addAnnotations([annot]);
annotationUI.updateAnchorStatus({ [tagForID(annot.id)]: 'orphan' });
assert.equal(annotationUI.getState().annotations[0].$orphan, true);
store.addAnnotations([annot]);
store.updateAnchorStatus({ [tagForID(annot.id)]: 'orphan' });
assert.equal(store.getState().annotations[0].$orphan, true);
});
});
describe('selector functions', function () {
// The individual state management modules in reducers/*.js define various
// 'selector' functions for extracting data from the app state. These are
// then re-exported on the annotationUI module.
// then re-exported on the store module.
it('re-exports selectors from reducers', function () {
var selectors = [
// Selection
......@@ -541,7 +541,7 @@ describe('annotationUI', function () {
];
selectors.forEach(function (fnName) {
assert.equal(typeof annotationUI[fnName], 'function', fnName + ' was exported');
assert.equal(typeof store[fnName], 'function', fnName + ' was exported');
});
});
});
......
......@@ -5,13 +5,13 @@ var crossOriginRPC = require('../cross-origin-rpc');
describe('crossOriginRPC', function() {
describe('server', function() {
let addedListener; // The postMessage() listener that the server adds.
let fakeAnnotationUI;
let fakeStore;
let fakeWindow;
let settings;
let source;
beforeEach(function() {
fakeAnnotationUI = {
fakeStore = {
searchUris: sinon.stub().returns('THE_SEARCH_URIS'),
};
......@@ -40,14 +40,14 @@ describe('crossOriginRPC', function() {
}
it('adds a postMessage() event listener function', function() {
crossOriginRPC.server.start(fakeAnnotationUI, {}, fakeWindow);
crossOriginRPC.server.start(fakeStore, {}, fakeWindow);
assert.isTrue(fakeWindow.addEventListener.calledOnce);
assert.isTrue(fakeWindow.addEventListener.calledWith('message'));
});
it('sends a response with the result from the called method', function() {
crossOriginRPC.server.start(fakeAnnotationUI, settings, fakeWindow);
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
data: { method: 'searchUris', id: 42 },
......@@ -72,7 +72,7 @@ describe('crossOriginRPC', function() {
{ rpcAllowedOrigins: ['https://allowed1.com', 'https://allowed2.com'] },
].forEach(function(settings) {
it("doesn't respond if the origin isn't allowed", function() {
crossOriginRPC.server.start(fakeAnnotationUI, settings, fakeWindow);
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
origin: 'https://notallowed.com',
......@@ -85,7 +85,7 @@ describe('crossOriginRPC', function() {
});
it("responds with an error if there's no method", function() {
crossOriginRPC.server.start(fakeAnnotationUI, settings, fakeWindow);
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
let jsonRpcRequest = { id: 42 }; // No "method" member.
postMessage({
......@@ -113,7 +113,7 @@ describe('crossOriginRPC', function() {
null,
].forEach(function(method) {
it('responds with an error if the method is unknown', function() {
crossOriginRPC.server.start(fakeAnnotationUI, settings, fakeWindow);
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
origin: 'https://allowed1.com',
......
......@@ -30,7 +30,7 @@ var fixtures = immutable({
});
describe('annotation threading', function () {
var annotationUI;
var store;
var rootThread;
beforeEach(function () {
......@@ -44,7 +44,7 @@ describe('annotation threading', function () {
};
angular.module('app', [])
.service('annotationUI', require('../../store'))
.service('store', require('../../store'))
.service('drafts', require('../../services/drafts'))
.service('rootThread', require('../../services/root-thread'))
.service('searchFilter', require('../../services/search-filter'))
......@@ -55,34 +55,34 @@ describe('annotation threading', function () {
angular.mock.module('app');
angular.mock.inject(function (_annotationUI_, _rootThread_) {
annotationUI = _annotationUI_;
angular.mock.inject(function (_store_, _rootThread_) {
store = _store_;
rootThread = _rootThread_;
});
});
it('should display newly loaded annotations', function () {
annotationUI.addAnnotations(fixtures.annotations);
assert.equal(rootThread.thread(annotationUI.getState()).children.length, 2);
store.addAnnotations(fixtures.annotations);
assert.equal(rootThread.thread(store.getState()).children.length, 2);
});
it('should not display unloaded annotations', function () {
annotationUI.addAnnotations(fixtures.annotations);
annotationUI.removeAnnotations(fixtures.annotations);
assert.equal(rootThread.thread(annotationUI.getState()).children.length, 0);
store.addAnnotations(fixtures.annotations);
store.removeAnnotations(fixtures.annotations);
assert.equal(rootThread.thread(store.getState()).children.length, 0);
});
it('should filter annotations when a search is set', function () {
annotationUI.addAnnotations(fixtures.annotations);
annotationUI.setFilterQuery('second');
assert.equal(rootThread.thread(annotationUI.getState()).children.length, 1);
assert.equal(rootThread.thread(annotationUI.getState()).children[0].id, '2');
store.addAnnotations(fixtures.annotations);
store.setFilterQuery('second');
assert.equal(rootThread.thread(store.getState()).children.length, 1);
assert.equal(rootThread.thread(store.getState()).children[0].id, '2');
});
unroll('should sort annotations by #mode', function (testCase) {
annotationUI.addAnnotations(fixtures.annotations);
annotationUI.setSortKey(testCase.sortKey);
var actualOrder = rootThread.thread(annotationUI.getState()).children.map(function (thread) {
store.addAnnotations(fixtures.annotations);
store.setSortKey(testCase.sortKey);
var actualOrder = rootThread.thread(store.getState()).children.map(function (thread) {
return thread.annotation.id;
});
assert.deepEqual(actualOrder, testCase.expectedOrder);
......
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