Commit d0099f12 authored by Robert Knight's avatar Robert Knight

Avoid reloading whole view when focused group changes

When the focused group changes, instead of reloading the whole
view just unload the currently displayed annotations and then
reload the annotations for the newly selected group(s) and
any drafts of unsaved annotations.

The only immediately 'visible' effect of the change is
that switching groups now only results in a call to /search
rather than network requests to fetch session state and features.

In future this should make it easier to preserve state
for the area below the top bar when switching groups.
parent fc913bb3
...@@ -48,7 +48,7 @@ module.exports = class AppController ...@@ -48,7 +48,7 @@ module.exports = class AppController
# Reload the view when the focused group changes or the # Reload the view when the focused group changes or the
# list of groups that the user is a member of changes # list of groups that the user is a member of changes
reloadEvents = [events.USER_CHANGED, events.GROUP_FOCUSED]; reloadEvents = [events.USER_CHANGED];
reloadEvents.forEach((eventName) -> reloadEvents.forEach((eventName) ->
$scope.$on(eventName, (event, data) -> $scope.$on(eventName, (event, data) ->
if !data || !data.initialLoad if !data || !data.initialLoad
......
...@@ -19,15 +19,13 @@ resolve = ...@@ -19,15 +19,13 @@ resolve =
'annotationMapper', 'drafts', 'threading' 'annotationMapper', 'drafts', 'threading'
(annotationMapper, drafts, threading) -> (annotationMapper, drafts, threading) ->
# Unload all the annotations # Unload all the annotations
idTable = threading.idTable annotationMapper.unloadAnnotations(threading.annotationList())
annotations = (message for id, {message} of idTable when message)
annotationMapper.unloadAnnotations(annotations)
# Reset the threading root # Reset the threading root
threading.createIdTable([]) threading.createIdTable([])
threading.root = mail.messageContainer() threading.root = mail.messageContainer()
# Thread all the drafts # Reload all unsaved annotations
threading.thread(drafts.all()) threading.thread(drafts.all())
return threading return threading
......
...@@ -145,12 +145,6 @@ describe 'AppController', -> ...@@ -145,12 +145,6 @@ describe 'AppController', ->
createController() createController()
assert.isFalse($scope.shareDialog.visible) assert.isFalse($scope.shareDialog.visible)
it 'reloads the view when the focused group changes', ->
createController()
fakeRoute.reload = sinon.spy()
$scope.$broadcast(events.GROUP_FOCUSED)
assert.calledOnce(fakeRoute.reload)
it 'does not reload the view when the logged-in user changes on first load', -> it 'does not reload the view when the logged-in user changes on first load', ->
createController() createController()
fakeRoute.reload = sinon.spy() fakeRoute.reload = sinon.spy()
......
{module, inject} = angular.mock {module, inject} = angular.mock
events = require('../events')
describe 'WidgetController', -> describe 'WidgetController', ->
$scope = null $scope = null
fakeAnnotationMapper = null fakeAnnotationMapper = null
fakeAnnotationUI = null fakeAnnotationUI = null
fakeAuth = null fakeAuth = null
fakeCrossFrame = null fakeCrossFrame = null
fakeDrafts = null
fakeStore = null fakeStore = null
fakeStreamer = null fakeStreamer = null
fakeStreamFilter = null fakeStreamFilter = null
fakeThreading = null fakeThreading = null
fakeGroups = null fakeGroups = null
lastSearchResult = null
sandbox = null sandbox = null
viewer = null viewer = null
...@@ -23,13 +27,22 @@ describe 'WidgetController', -> ...@@ -23,13 +27,22 @@ describe 'WidgetController', ->
beforeEach module ($provide) -> beforeEach module ($provide) ->
sandbox = sinon.sandbox.create() sandbox = sinon.sandbox.create()
fakeAnnotationMapper = {loadAnnotations: sandbox.spy()} fakeAnnotationMapper = {
loadAnnotations: sandbox.spy()
unloadAnnotations: sandbox.spy()
}
fakeAnnotationUI = { fakeAnnotationUI = {
tool: 'comment' tool: 'comment'
clearSelectedAnnotations: sandbox.spy() clearSelectedAnnotations: sandbox.spy()
} }
fakeAuth = {user: null} fakeAuth = {user: null}
fakeCrossFrame = {frames: []} fakeCrossFrame = {frames: []}
fakeDrafts = {
all: sandbox.stub()
}
lastSearchResult = null
fakeStore = { fakeStore = {
SearchResource: SearchResource:
...@@ -39,7 +52,7 @@ describe 'WidgetController', -> ...@@ -39,7 +52,7 @@ describe 'WidgetController', ->
result = result =
total: 100 total: 100
rows: [offset..offset+limit-1] rows: [offset..offset+limit-1]
lastSearchResult = result
callback result callback result
} }
...@@ -56,7 +69,8 @@ describe 'WidgetController', -> ...@@ -56,7 +69,8 @@ describe 'WidgetController', ->
} }
fakeThreading = { fakeThreading = {
root: {} root: {},
thread: sandbox.stub()
} }
fakeGroups = { fakeGroups = {
...@@ -66,6 +80,7 @@ describe 'WidgetController', -> ...@@ -66,6 +80,7 @@ describe 'WidgetController', ->
$provide.value 'annotationMapper', fakeAnnotationMapper $provide.value 'annotationMapper', fakeAnnotationMapper
$provide.value 'annotationUI', fakeAnnotationUI $provide.value 'annotationUI', fakeAnnotationUI
$provide.value 'crossframe', fakeCrossFrame $provide.value 'crossframe', fakeCrossFrame
$provide.value 'drafts', fakeDrafts
$provide.value 'store', fakeStore $provide.value 'store', fakeStore
$provide.value 'streamer', fakeStreamer $provide.value 'streamer', fakeStreamer
$provide.value 'streamFilter', fakeStreamFilter $provide.value 'streamFilter', fakeStreamFilter
...@@ -92,3 +107,16 @@ describe 'WidgetController', -> ...@@ -92,3 +107,16 @@ describe 'WidgetController', ->
assert.calledWith(loadSpy, [40..59]) assert.calledWith(loadSpy, [40..59])
assert.calledWith(loadSpy, [60..79]) assert.calledWith(loadSpy, [60..79])
assert.calledWith(loadSpy, [80..99]) assert.calledWith(loadSpy, [80..99])
describe 'when the focused group changes', ->
it 'should load annotations for the new group', ->
fakeThreading.annotationList = sandbox.stub().returns([{id: '1'}])
fakeCrossFrame.frames.push({uri: 'http://example.com'})
$scope.$broadcast(events.GROUP_FOCUSED)
assert.calledWith(fakeAnnotationMapper.unloadAnnotations,
[{id: '1'}])
$scope.$digest();
assert.calledWith(fakeAnnotationMapper.loadAnnotations,
lastSearchResult.rows)
assert.calledWith(fakeThreading.thread, fakeDrafts.all())
...@@ -61,6 +61,11 @@ module.exports = class Threading ...@@ -61,6 +61,11 @@ module.exports = class Threading
this.pruneEmpties(@root) this.pruneEmpties(@root)
@root @root
# Returns a flat list of every annotation that is currently loaded
# in the thread
annotationList: ->
(message for id, {message} of @idTable when message)
pruneEmpties: (parent) -> pruneEmpties: (parent) ->
for container in parent.children for container in parent.children
this.pruneEmpties(container) this.pruneEmpties(container)
......
angular = require('angular') angular = require('angular')
events = require('./events')
module.exports = class WidgetController module.exports = class WidgetController
this.$inject = [ this.$inject = [
'$scope', 'annotationUI', 'crossframe', 'annotationMapper', 'groups', '$scope', 'annotationUI', 'crossframe', 'annotationMapper', 'drafts', 'groups',
'streamer', 'streamFilter', 'store', 'threading' 'streamer', 'streamFilter', 'store', 'threading'
] ]
constructor: ( constructor: (
$scope, annotationUI, crossframe, annotationMapper, groups, $scope, annotationUI, crossframe, annotationMapper, drafts, groups,
streamer, streamFilter, store, threading streamer, streamFilter, store, threading
) -> ) ->
$scope.isStream = true $scope.isStream = true
...@@ -17,6 +18,12 @@ module.exports = class WidgetController ...@@ -17,6 +18,12 @@ module.exports = class WidgetController
@chunkSize = 200 @chunkSize = 200
loaded = [] loaded = []
_resetAnnotations = ->
# Unload all the annotations
annotationMapper.unloadAnnotations(threading.annotationList())
# Reload all the drafts
threading.thread(drafts.all())
_loadAnnotationsFrom = (query, offset) => _loadAnnotationsFrom = (query, offset) =>
queryCore = queryCore =
limit: @chunkSize limit: @chunkSize
...@@ -45,6 +52,11 @@ module.exports = class WidgetController ...@@ -45,6 +52,11 @@ module.exports = class WidgetController
streamFilter.resetFilter().addClause('/uri', 'one_of', loaded) streamFilter.resetFilter().addClause('/uri', 'one_of', loaded)
streamer.send({filter: streamFilter.getFilter()}) streamer.send({filter: streamFilter.getFilter()})
$scope.$on events.GROUP_FOCUSED, ->
_resetAnnotations(annotationMapper, drafts, threading)
loaded = []
loadAnnotations crossframe.frames
$scope.$watchCollection (-> crossframe.frames), loadAnnotations $scope.$watchCollection (-> crossframe.frames), loadAnnotations
$scope.focus = (annotation) -> $scope.focus = (annotation) ->
......
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