Commit e9b4045e authored by Nick Stenning's avatar Nick Stenning

Merge pull request #2693 from robertknight/avoid-group-reload-on-change

Avoid route reload on change
parents be1ba7d4 22ae23a8
...@@ -46,9 +46,8 @@ module.exports = class AppController ...@@ -46,9 +46,8 @@ module.exports = class AppController
options: ['Newest', 'Oldest', 'Location'] options: ['Newest', 'Oldest', 'Location']
} }
# Reload the view when the focused group changes or the # Reload the view when the user switches accounts
# list of groups that the user is a member of changes reloadEvents = [events.USER_CHANGED];
reloadEvents = [events.USER_CHANGED, events.GROUP_FOCUSED];
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())
angular = require('angular') angular = require('angular')
mail = require('./vendor/jwz') mail = require('./vendor/jwz')
# The threading service provides the model for the currently loaded
# set of annotations, structured as a tree of annotations and replies.
#
# The service listens for events when annotations are loaded, unloaded,
# created or deleted and updates the tree model in response.
#
# The conversion of a flat list of incoming messages into a tree structure
# with replies nested under their parents
# uses an implementation of the `jwz` message threading algorithm
# (see https://www.jwz.org/doc/threading.html and the JS port
# at https://github.com/maxogden/conversationThreading-js).
#
# The 'Threading' service "inherits" from 'mail.messageThread'
#
module.exports = class Threading module.exports = class Threading
root: null root: null
...@@ -61,6 +74,11 @@ module.exports = class Threading ...@@ -61,6 +74,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