Commit 9e6d4760 authored by Aron Carroll's avatar Aron Carroll

Remove the Threading plugin

This has now moved to the threading service.
parent 3f27741f
class Annotator.Plugin.Threading extends Annotator.Plugin
# Mix in message thread properties into the prototype. The body of the
# class will overwrite any methods applied here. If you need inheritance
# assign the message thread to a local varible.
$.extend(this.prototype, mail.messageThread())
events:
'beforeAnnotationCreated': 'beforeAnnotationCreated'
'annotationCreated': 'annotationCreated'
'annotationDeleted': 'annotationDeleted'
'annotationsLoaded': 'annotationsLoaded'
root: null
pluginInit: ->
# Create a root container.
@root = mail.messageContainer()
# TODO: Refactor the jwz API for progressive updates.
# Right now the idTable is wiped when `messageThread.thread()` is called and
# empty containers are pruned. We want to show empties so that replies attach
# to missing parents and threads can be updates as new data arrives.
thread: (messages) ->
for message in messages
# Get or create a thread to contain the annotation
if message.id
thread = (this.getContainer message.id)
thread.message = message
else
# XXX: relies on outside code to update the idTable if the message
# later acquires an id.
thread = mail.messageContainer(message)
prev = @root
references = message.references or []
if typeof(message.references) == 'string'
references = [references]
# Build out an ancestry from the root
for reference in references
container = this.getContainer(reference)
unless container.parent? or container.hasDescendant(prev) # no cycles
prev.addChild(container)
prev = container
# Attach the thread at its leaf location
unless thread.hasDescendant(prev) # no cycles
do ->
for child in prev.children when child.message is message
return # no dupes
prev.addChild(thread)
this.pruneEmpties(@root)
@root
pruneEmpties: (parent) ->
for container in parent.children
this.pruneEmpties(container)
if !container.message && container.children.length == 0
parent.removeChild(container)
delete this.idTable[container.message?.id]
beforeAnnotationCreated: (annotation) =>
this.thread([annotation])
annotationCreated: (annotation) =>
references = annotation.references or []
if typeof(annotation.references) == 'string' then references = []
ref = references[references.length-1]
parent = if ref then @idTable[ref] else @root
for child in (parent.children or []) when child.message is annotation
@idTable[annotation.id] = child
break
annotationDeleted: (annotation) =>
if this.idTable[annotation.id]
container = this.idTable[annotation.id]
container.message = null
delete this.idTable[annotation.id]
this.pruneEmpties(@root)
else
if annotation.references
refs = annotation.references
unless angular.isArray(refs) then refs = [refs]
parentRef = refs[refs.length-1]
parent = this.idTable[parentRef]
else
parent = @root
for child in parent.children when child.message is annotation
child.message = null
this.pruneEmpties(@root)
break
annotationsLoaded: (annotations) =>
messages = (@root.flattenChildren() or []).concat(annotations)
this.thread(messages)
assert = chai.assert
sinon.assert.expose(assert, prefix: null)
sandbox = sinon.sandbox.create()
describe 'Annotator.Threading', ->
createThreadingInstance = (options) ->
element = document.createElement('div')
return new Annotator.Plugin.Threading(element, options || {})
describe 'pruneEmpties', ->
it 'keeps public messages with no children', ->
threadA = mail.messageContainer(mail.message('subject a', 'a', []))
threadB = mail.messageContainer(mail.message('subject b', 'b', []))
threadC = mail.messageContainer(mail.message('subject c', 'c', []))
root = mail.messageContainer()
root.addChild(threadA)
root.addChild(threadB)
root.addChild(threadC)
instance = createThreadingInstance()
instance.pruneEmpties(root)
assert.equal(root.children.length, 3)
it 'keeps public messages with public children', ->
threadA = mail.messageContainer(mail.message('subject a', 'a', []))
threadA1 = mail.messageContainer(mail.message('subject a1', 'a1', ['a']))
threadA2 = mail.messageContainer(mail.message('subject a2', 'a2', ['a']))
root = mail.messageContainer()
root.addChild(threadA)
threadA.addChild(threadA1)
threadA.addChild(threadA2)
instance = createThreadingInstance()
instance.pruneEmpties(root)
assert.equal(root.children.length, 1)
it 'prunes private messages with no children', ->
threadA = mail.messageContainer()
threadB = mail.messageContainer()
threadC = mail.messageContainer()
root = mail.messageContainer()
root.addChild(threadA)
root.addChild(threadB)
root.addChild(threadC)
instance = createThreadingInstance()
instance.pruneEmpties(root)
assert.equal(root.children.length, 0)
it 'keeps private messages with public children', ->
threadA = mail.messageContainer()
threadA1 = mail.messageContainer(mail.message('subject a1', 'a1', ['a']))
threadA2 = mail.messageContainer(mail.message('subject a2', 'a2', ['a']))
root = mail.messageContainer()
root.addChild(threadA)
threadA.addChild(threadA1)
threadA.addChild(threadA2)
instance = createThreadingInstance()
instance.pruneEmpties(root)
assert.equal(root.children.length, 1)
it 'prunes private messages with private children', ->
threadA = mail.messageContainer()
threadA1 = mail.messageContainer()
threadA2 = mail.messageContainer()
root = mail.messageContainer()
root.addChild(threadA)
threadA.addChild(threadA1)
threadA.addChild(threadA2)
instance = createThreadingInstance()
instance.pruneEmpties(root)
assert.equal(root.children.length, 0)
describe 'handles events', ->
annotator = null
instance = null
beforeEach ->
instance = createThreadingInstance()
instance.pluginInit()
annotator =
publish: (event, args) ->
unless angular.isArray(args) then args = [args]
meth = instance.events[event]
instance[meth].apply(instance, args)
afterEach ->
sandbox.restore()
it 'calls the thread method on beforeAnnotationCreated', ->
annotation = {id: 'foo'}
sandbox.spy(instance, 'thread')
annotator.publish 'beforeAnnotationCreated', annotation
assert.calledWithMatch instance.thread, [annotation]
it 'calls the thread method on annotationsLoaded', ->
annotation = {id: 'foo'}
sandbox.spy(instance, 'thread')
annotator.publish 'annotationsLoaded', [annotation]
assert.calledWithMatch instance.thread, [annotation]
it 'removes matching top level threads when annotationDeleted is called', ->
annotation = {id: 'foo'}
instance.thread([annotation])
assert.equal(instance.root.children.length, 1)
assert.equal(instance.idTable['foo'].message, annotation)
sandbox.spy(instance, 'pruneEmpties')
annotator.publish 'annotationDeleted', annotation
assert.called(instance.pruneEmpties)
assert.equal(instance.root.children.length, 0)
assert.isUndefined(instance.idTable['foo'])
it 'removes matching reply threads when annotationDeleted is called', ->
parent = {id: 'foo'}
reply = {id: 'bar', references: ['foo']}
instance.thread([parent, reply])
assert.equal(instance.idTable['foo'].children.length, 1)
assert.equal(instance.idTable['bar'].message, reply)
sandbox.spy(instance, 'pruneEmpties')
annotator.publish 'annotationDeleted', reply
assert.called(instance.pruneEmpties)
assert.equal(instance.idTable['foo'].children.length, 0)
assert.isUndefined(instance.idTable['bar'])
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