I kinda-sorta into quote threading.
Unread count is completely broken with this, so I'm keeping it in its own branch until I fix it. Also code is a mess.
This commit is contained in:
parent
5d446e53be
commit
643e20a2d8
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -277,6 +277,10 @@ Config =
|
||||
true
|
||||
'Highlight the previewed post.'
|
||||
]
|
||||
'Quote Threading': [
|
||||
true
|
||||
''
|
||||
]
|
||||
'Resurrect Quotes': [
|
||||
true
|
||||
'Link dead quotes to the archives.'
|
||||
|
||||
@ -107,6 +107,7 @@ Main =
|
||||
'Thread Excerpt': ThreadExcerpt
|
||||
'Favicon': Favicon
|
||||
'Unread': Unread
|
||||
'Quote Threading': QuoteThreading
|
||||
'Thread Stats': ThreadStats
|
||||
'Thread Updater': ThreadUpdater
|
||||
'Thread Watcher': ThreadWatcher
|
||||
|
||||
@ -218,7 +218,6 @@ ThreadUpdater =
|
||||
ThreadUpdater.thread.postLimit = !!OP.bumplimit
|
||||
ThreadUpdater.thread.fileLimit = !!OP.imagelimit
|
||||
|
||||
nodes = [] # post container elements
|
||||
posts = [] # post objects
|
||||
index = [] # existing posts
|
||||
files = [] # existing files
|
||||
@ -232,7 +231,6 @@ ThreadUpdater =
|
||||
# Insert new posts, not older ones.
|
||||
count++
|
||||
node = Build.postFromObject postObject, ThreadUpdater.thread.board
|
||||
nodes.push node
|
||||
posts.push new Post node, ThreadUpdater.thread, ThreadUpdater.thread.board
|
||||
|
||||
deletedPosts = []
|
||||
@ -258,6 +256,7 @@ ThreadUpdater =
|
||||
unless count
|
||||
ThreadUpdater.set 'status', null, null
|
||||
ThreadUpdater.outdateCount++
|
||||
|
||||
else
|
||||
ThreadUpdater.set 'status', "+#{count}", 'new'
|
||||
ThreadUpdater.outdateCount = 0
|
||||
@ -271,7 +270,14 @@ ThreadUpdater =
|
||||
|
||||
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and
|
||||
ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25
|
||||
$.add ThreadUpdater.root, nodes
|
||||
|
||||
for key, post of posts
|
||||
continue unless posts.hasOwnProperty key
|
||||
if post.cb
|
||||
post.cb.call post
|
||||
else
|
||||
$.add ThreadUpdater.root, post.nodes.root
|
||||
|
||||
if scroll
|
||||
if Conf['Bottom Scroll']
|
||||
<% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop = d.body.clientHeight
|
||||
|
||||
@ -5,7 +5,7 @@ Unread =
|
||||
@db = new DataBoard 'lastReadPosts', @sync
|
||||
@hr = $.el 'hr',
|
||||
id: 'unread-line'
|
||||
@posts = []
|
||||
@posts = new RandomAccessList
|
||||
@postsQuotingYou = []
|
||||
|
||||
Thread::callbacks.push
|
||||
@ -19,7 +19,7 @@ Unread =
|
||||
for ID, post of @posts
|
||||
posts.push post if post.isReply
|
||||
Unread.lastReadPost = Unread.db.get
|
||||
boardID: @board.ID
|
||||
boardID: @board.ID
|
||||
threadID: @ID
|
||||
defaultValue: 0
|
||||
Unread.addPosts posts
|
||||
@ -62,13 +62,14 @@ Unread =
|
||||
threadID: post.thread.ID
|
||||
postID: post.ID
|
||||
continue if QR.db.get data
|
||||
Unread.posts.push post
|
||||
Unread.posts.push ID, post
|
||||
Unread.addPostQuotingYou post
|
||||
if Conf['Unread Line']
|
||||
# Force line on visible threads if there were no unread posts previously.
|
||||
Unread.setLine newPosts.contains Unread.posts[0]
|
||||
Unread.read()
|
||||
Unread.update()
|
||||
Unread.setLine newPosts.contains Unread.posts.first
|
||||
unless Conf['Quote Threading']
|
||||
Unread.read()
|
||||
Unread.update()
|
||||
|
||||
addPostQuotingYou: (post) ->
|
||||
return unless QR.db
|
||||
@ -84,14 +85,22 @@ Unread =
|
||||
Unread.addPosts e.detail.newPosts
|
||||
|
||||
readSinglePost: (post) ->
|
||||
return if (i = Unread.posts.indexOf post) is -1
|
||||
Unread.posts.splice i, 1
|
||||
if i is 0
|
||||
Unread.lastReadPost = post.ID
|
||||
{ID} = post
|
||||
return unless Unread.posts[ID]
|
||||
Unread.posts.rm ID
|
||||
unless Unread.posts.first
|
||||
Unread.lastReadPost = ID
|
||||
Unread.saveLastReadPost()
|
||||
if (i = Unread.postsQuotingYou.indexOf post) isnt -1
|
||||
Unread.postsQuotingYou.splice i, 1
|
||||
Unread.update()
|
||||
|
||||
readRAL: (ral) ->
|
||||
items = []
|
||||
for post of ral
|
||||
items.push post.ID > Unread.lastReadPost
|
||||
for item in items
|
||||
ral.rm item
|
||||
|
||||
readArray: (arr) ->
|
||||
for post, i in arr
|
||||
@ -100,15 +109,17 @@ Unread =
|
||||
|
||||
read: (e) ->
|
||||
return if d.hidden or !Unread.posts.length
|
||||
{posts} = Unread
|
||||
height = doc.clientHeight
|
||||
for post, i in Unread.posts
|
||||
for key, post of posts
|
||||
continue unless posts.hasOwnProperty key
|
||||
{bottom} = post.nodes.root.getBoundingClientRect()
|
||||
break if bottom > height # post is not completely read
|
||||
return unless i
|
||||
Unread.posts.rm post
|
||||
return unless post
|
||||
|
||||
Unread.lastReadPost = Unread.posts[i - 1].ID
|
||||
Unread.lastReadPost = post.ID
|
||||
Unread.saveLastReadPost()
|
||||
Unread.posts.splice 0, i
|
||||
Unread.readArray Unread.postsQuotingYou
|
||||
Unread.update() if e
|
||||
|
||||
|
||||
139
src/code/quoting/quotethreading.coffee
Normal file
139
src/code/quoting/quotethreading.coffee
Normal file
@ -0,0 +1,139 @@
|
||||
###
|
||||
<3 aeosynth
|
||||
###
|
||||
|
||||
QuoteThreading =
|
||||
init: ->
|
||||
return unless Conf['Quote Threading'] and g.VIEW is 'thread'
|
||||
|
||||
@enabled = true
|
||||
@controls = $.el 'span',
|
||||
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
||||
|
||||
input = $ 'input', @controls
|
||||
$.on input, 'change', QuoteThreading.toggle
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'header'
|
||||
el: @controls
|
||||
order: 115
|
||||
|
||||
$.on d, '4chanXInitFinished', @setup
|
||||
|
||||
Post::callbacks.push
|
||||
name: 'Quote Threading'
|
||||
cb: @node
|
||||
|
||||
setup: ->
|
||||
$.off d, '4chanXInitFinished', QuoteThreading.setup
|
||||
{posts} = g
|
||||
|
||||
Unread.read()
|
||||
Unread.update()
|
||||
|
||||
for ID, post of posts
|
||||
if post.cb
|
||||
try
|
||||
post.cb.call post
|
||||
catch err
|
||||
console.log err
|
||||
return
|
||||
|
||||
QuoteThreading.hasRun = true
|
||||
|
||||
node: ->
|
||||
# Random access list
|
||||
#
|
||||
# 'Array' implementation is very awkward - mid-object inserts, loop to find
|
||||
# quoted post, loop to find inserted post(!), loop to find distance from
|
||||
# threaded post to thread root
|
||||
#
|
||||
# Of course, implementing your own data structure can be awkward.
|
||||
return if @isClone or not QuoteThreading.enabled or @thread.OP is @
|
||||
|
||||
{quotes, ID} = @
|
||||
if QuoteThreading.hasRun
|
||||
{posts} = Unread
|
||||
return if !(post = posts[ID]) or post.isHidden # Filtered
|
||||
|
||||
else
|
||||
{posts} = g
|
||||
return if !(post = posts["#{g.BOARD}.#{ID}"]) or post.isHidden # Filtered
|
||||
|
||||
uniq = {}
|
||||
if QuoteThreading.hasRun
|
||||
for quote in quotes
|
||||
qid = quote[2..]
|
||||
continue unless qid < ID
|
||||
if qid of posts
|
||||
uniq[qid] = true
|
||||
else
|
||||
for quote in quotes
|
||||
qid = quote
|
||||
continue unless qid[2..] < ID
|
||||
if qid of posts
|
||||
uniq[qid[2..]] = true
|
||||
|
||||
keys = Object.keys uniq
|
||||
return unless keys.length is 1
|
||||
|
||||
@threaded = keys[0]
|
||||
@cb = QuoteThreading.nodeinsert
|
||||
|
||||
nodeinsert: ->
|
||||
qid = @threaded
|
||||
|
||||
if QuoteThreading.hasRun
|
||||
{posts} = Unread
|
||||
qpost = posts[qid]
|
||||
else
|
||||
{posts} = g
|
||||
unread = Unread.posts
|
||||
qpost = posts["#{g.BOARD}.#{qid}"]
|
||||
|
||||
return if @thread.OP is qpost
|
||||
|
||||
qroot = qpost.nodes.root
|
||||
threadContainer = qroot.nextSibling
|
||||
if threadContainer?.className isnt 'threadContainer'
|
||||
threadContainer = $.el 'div',
|
||||
className: 'threadContainer'
|
||||
$.after qroot, threadContainer
|
||||
|
||||
$.add threadContainer, @nodes.root
|
||||
|
||||
pEl = $.x 'preceding::div[contains(@class,"post reply")][1]/parent::div', @nodes.root
|
||||
pid = pEl.id[2..]
|
||||
|
||||
if QuoteThreading.hasRun
|
||||
ppost = posts[pid]
|
||||
else
|
||||
ppost = posts[pid]
|
||||
return unless (post = unread["#{g.BOARD}.#{@id}"]) and (ppost = unread["#{g.BOARD}.#{pid}"])
|
||||
|
||||
posts.after ppost, @
|
||||
|
||||
toggle: ->
|
||||
thread = $ '.thread'
|
||||
replies = $$ '.thread > .replyContainer, .threadContainer > .replyContainer', thread
|
||||
QuoteThreading.enabled = @checked
|
||||
if @checked
|
||||
nodes = (Get.postFromNode reply for reply in replies)
|
||||
Unread.node.call node for node in nodes
|
||||
QuoteThreading.node node for node in nodes
|
||||
else
|
||||
replies.sort (a, b) ->
|
||||
aID = Number a.id[2..]
|
||||
bID = Number b.id[2..]
|
||||
aID - bID
|
||||
$.add thread, replies
|
||||
containers = $$ '.threadContainer', thread
|
||||
$.rm container for container in containers
|
||||
Unread.update true
|
||||
|
||||
# Keybind comes later.
|
||||
# public:
|
||||
# toggle: ->
|
||||
# control = $.id 'threadingControl'
|
||||
# control.checked = not control.checked
|
||||
# QuoteThreading.toggle.call control
|
||||
@ -481,6 +481,12 @@ a.hide-announcement {
|
||||
outline: 2px solid rgba(216, 94, 49, .7);
|
||||
}
|
||||
|
||||
/* Quote Threading */
|
||||
.threadContainer {
|
||||
margin-left: 20px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
|
||||
/* File */
|
||||
.fileText:hover .fntrunc,
|
||||
.fileText:not(:hover) .fnfull,
|
||||
|
||||
@ -11,6 +11,7 @@ $$ = (selector, root=d.body) ->
|
||||
|
||||
$.extend = (object, properties) ->
|
||||
for key, val of properties
|
||||
continue unless properties.hasOwnProperty key
|
||||
object[key] = val
|
||||
return
|
||||
|
||||
@ -35,7 +36,7 @@ $.extend Array::,
|
||||
args = arguments
|
||||
for arg in args
|
||||
@push.apply @, arg
|
||||
return @
|
||||
return
|
||||
|
||||
remove: (object) ->
|
||||
if (index = @indexOf object) > -1
|
||||
@ -116,8 +117,9 @@ $.extend $,
|
||||
cb()
|
||||
else
|
||||
setTimeout $.asap, 25, test, cb
|
||||
addStyle: (css) ->
|
||||
addStyle: (css, id) ->
|
||||
style = $.el 'style',
|
||||
id: id
|
||||
textContent: css
|
||||
$.asap (-> d.head), ->
|
||||
$.add d.head, style
|
||||
@ -247,6 +249,16 @@ $.extend $,
|
||||
# Round to an integer otherwise.
|
||||
Math.round size
|
||||
"#{size} #{['B', 'KB', 'MB', 'GB'][unit]}"
|
||||
minmax: (value, min, max) ->
|
||||
return (
|
||||
if value < min
|
||||
min
|
||||
else
|
||||
if value > max
|
||||
max
|
||||
else
|
||||
value
|
||||
)
|
||||
syncing: {}
|
||||
sync: do ->
|
||||
<% if (type === 'crx') { %>
|
||||
|
||||
@ -3,4 +3,5 @@
|
||||
<%= grunt.file.read('src/lib/post.class') %>
|
||||
<%= grunt.file.read('src/lib/clone.class') %>
|
||||
<%= grunt.file.read('src/lib/databoard.class') %>
|
||||
<%= grunt.file.read('src/lib/notification.class') %>
|
||||
<%= grunt.file.read('src/lib/notification.class') %>
|
||||
<%= grunt.file.read('src/lib/randomaccesslist.class') %>
|
||||
50
src/lib/randomaccesslist.class
Normal file
50
src/lib/randomaccesslist.class
Normal file
@ -0,0 +1,50 @@
|
||||
class RandomAccessList
|
||||
constructor: ->
|
||||
@first = null
|
||||
@last = null
|
||||
@length = 0
|
||||
|
||||
push: (id, post) ->
|
||||
{last} = @
|
||||
@[id] = item = post
|
||||
item.prev = last
|
||||
item.next = null
|
||||
@last = item
|
||||
if last
|
||||
last.next = item
|
||||
else
|
||||
@first = item
|
||||
@length++
|
||||
|
||||
shift: ->
|
||||
@rm @first.ID
|
||||
|
||||
after: (root, item) ->
|
||||
return if item.prev is root
|
||||
|
||||
@rmi item
|
||||
|
||||
{next} = root
|
||||
|
||||
root.next = item
|
||||
item.prev = root
|
||||
item.next = next
|
||||
next.prev = item
|
||||
|
||||
rm: (id) ->
|
||||
item = @[id]
|
||||
return unless item
|
||||
delete @[id]
|
||||
@length--
|
||||
@rmi item
|
||||
|
||||
rmi: (item) ->
|
||||
{prev, next} = item
|
||||
if prev
|
||||
prev.next = next
|
||||
else
|
||||
@first = next
|
||||
if next
|
||||
next.prev = prev
|
||||
else
|
||||
@last = prev
|
||||
Loading…
x
Reference in New Issue
Block a user