### <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()