###
<3 aeosynth
###
QuoteThreading =
init: ->
return unless Conf['Quote Threading'] and g.VIEW is 'thread'
@enabled = true
@controls = $.el 'span',
<%= html('') %>
@threadNewLink = $.el 'span',
className: 'brackets-wrap threadnewlink'
hidden: true
$.extend @threadNewLink, <%= html('Thread New Posts') %>
@input = $('input', @controls)
$.on @input, 'change', @rethread
$.on @threadNewLink.firstElementChild, 'click', @rethread
Header.menu.addEntry @entry =
el: @controls
order: 99
Thread.callbacks.push
name: 'Quote Threading'
cb: @setThread
Post.callbacks.push
name: 'Quote Threading'
cb: @node
parent: {}
children: {}
inserted: {}
setThread: ->
QuoteThreading.thread = @
$.asap (-> !Conf['Thread Updater'] or $ '.navLinksBot > .updatelink'), ->
$.add navLinksBot, [$.tn(' '), QuoteThreading.threadNewLink] if (navLinksBot = $ '.navLinksBot')
node: ->
return if @isFetchedQuote or @isClone or !@isReply
parents = new Set()
lastParent = null
for quote in @quotes when parent = g.posts[quote]
if not parent.isFetchedQuote and parent.isReply and parent.ID < @ID
parents.add parent.ID
lastParent = parent if not lastParent or parent.ID > lastParent.ID
return unless lastParent
ancestor = lastParent
while ancestor = QuoteThreading.parent[ancestor.fullID]
parents.delete ancestor.ID
if parents.size is 1
QuoteThreading.parent[@fullID] = lastParent
descendants: (post) ->
posts = [post]
if children = QuoteThreading.children[post.fullID]
for child in children
posts = posts.concat QuoteThreading.descendants child
posts
insert: (post) ->
return false unless QuoteThreading.enabled and
(parent = QuoteThreading.parent[post.fullID]) and
!QuoteThreading.inserted[post.fullID]
descendants = QuoteThreading.descendants post
if !Unread.posts.has(parent.ID)
if (do -> return true for x in descendants when Unread.posts.has x.ID)
QuoteThreading.threadNewLink.hidden = false
return false
{order} = Unread
children = (QuoteThreading.children[parent.fullID] or= [])
threadContainer = parent.nodes.threadContainer or $.el 'div', className: 'threadContainer'
nodes = [post.nodes.root]
nodes.push post.nodes.threadContainer if post.nodes.threadContainer
i = children.length
i-- for child in children by -1 when child.ID >= post.ID
if i isnt children.length
next = children[i]
order.before order[next.ID], order[x.ID] for x in descendants
children.splice i, 0, post
$.before next.nodes.root, nodes
else
prev = parent
while (prev2 = QuoteThreading.children[prev.fullID]) and prev2.length
prev = prev2[prev2.length-1]
order.after order[prev.ID], order[x.ID] for x in descendants by -1
children.push post
$.add threadContainer, nodes
QuoteThreading.inserted[post.fullID] = true
unless parent.nodes.threadContainer
parent.nodes.threadContainer = threadContainer
$.addClass parent.nodes.root, 'threadOP'
$.after parent.nodes.root, threadContainer
return true
rethread: ->
{thread} = QuoteThreading
{posts} = thread
QuoteThreading.threadNewLink.hidden = true
if QuoteThreading.enabled = QuoteThreading.input.checked
posts.forEach QuoteThreading.insert
else
nodes = []
Unread.order = new RandomAccessList()
QuoteThreading.inserted = {}
posts.forEach (post) ->
return if post.isFetchedQuote
Unread.order.push post
nodes.push post.nodes.root if post.isReply
if QuoteThreading.children[post.fullID]
delete QuoteThreading.children[post.fullID]
$.rmClass post.nodes.root, 'threadOP'
$.rm post.nodes.threadContainer
delete post.nodes.threadContainer
$.add thread.OP.nodes.root.parentNode, nodes
Unread.position = Unread.order.first
Unread.updatePosition()
Unread.setLine true
Unread.read()
Unread.update()