4chan-x/src/Quotelinks/QuoteThreading.coffee
2019-04-04 18:00:30 -07:00

161 lines
4.7 KiB
CoffeeScript

###
<3 aeosynth
###
QuoteThreading =
init: ->
return unless Conf['Quote Threading'] and g.VIEW is 'thread'
@controls = $.el 'label',
<%= html('<input id="threadingControl" name="Thread Quotes" type="checkbox"> Threading') %>
@threadNewLink = $.el 'span',
className: 'brackets-wrap threadnewlink'
hidden: true
$.extend @threadNewLink, <%= html('<a href="javascript:;">Thread New Posts</a>') %>
@input = $('input', @controls)
@input.checked = Conf['Thread Quotes']
$.on @input, 'change', @setEnabled
$.on @input, 'change', @rethread
$.on @threadNewLink.firstElementChild, 'click', @rethread
$.on d, '4chanXInitFinished', => @ready = true
Header.menu.addEntry @entry =
el: @controls
order: 99
Callbacks.Thread.push
name: 'Quote Threading'
cb: @setThread
Callbacks.Post.push
name: 'Quote Threading'
cb: @node
parent: {}
children: {}
inserted: {}
toggleThreading: ->
@setThreadingState !Conf['Thread Quotes']
setThreadingState: (enabled) ->
@input.checked = enabled
@setEnabled.call @input
@rethread.call @input
setEnabled: ->
if @checked
$.set 'Prune All Threads', false
other = ReplyPruning.inputs?.enabled
if other?.checked
other.checked = false
$.event 'change', null, other
$.cb.checked.call @
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 if not (
Conf['Thread Quotes'] 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: ->
return unless QuoteThreading.ready
{thread} = QuoteThreading
{posts} = thread
QuoteThreading.threadNewLink.hidden = true
if Conf['Thread Quotes']
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.nodes.root, nodes
Unread.position = Unread.order.first
Unread.updatePosition()
Unread.setLine true
Unread.read()
Unread.update()