From 481a775a80d81258c6d2a01e307de37450eb3634 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Sat, 20 Oct 2018 22:43:34 -0700 Subject: [PATCH] Add `Unread Line in Index` option, combined with previous work on `Mark Read` button. #625 Also fix various bugs with the old implementation. --- src/General/Index.coffee | 7 +- src/Miscellaneous/ExpandThread.coffee | 2 + src/Monitoring/Unread.coffee | 1 + src/Monitoring/UnreadIndex.coffee | 118 +++++++++++++++++--------- src/classes/Post.coffee | 1 - src/classes/Thread.coffee | 4 +- src/config/Config.coffee | 4 +- src/css/spooky.css | 2 +- src/css/style.css | 2 +- src/css/tomorrow.css | 2 +- src/main/Main.coffee | 2 +- src/site/SW.tinyboard.coffee | 1 + src/site/SW.yotsuba.coffee | 1 + 13 files changed, 96 insertions(+), 51 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index b2a505dee..08418028d 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -691,6 +691,10 @@ Index = isHiddenReply: (threadID, replyData) -> PostHiding.isHidden(g.BOARD.ID, threadID, replyData.no) or Filter.isHidden(Build.parseJSON replyData, g.BOARD.ID) + lastPost: (threadID) -> + threadData = Index.liveThreadDict[threadID] + if threadData?.last_replies then threadData.last_replies[threadData.last_replies.length - 1].no else threadID + buildThreads: (threadIDs, isCatalog, withReplies) -> threads = [] newThreads = [] @@ -713,7 +717,6 @@ Index = thread = new Thread ID, g.BOARD newThreads.push thread thread.json = threadData - thread.lastPost = if threadData.last_replies then threadData.last_replies[threadData.last_replies.length - 1].no else ID threads.push thread if ((OP = thread.OP) and not OP.isFetchedQuote) @@ -741,7 +744,7 @@ Index = Main.callbackNodes 'Thread', newThreads Main.callbackNodes 'Post', newPosts Index.updateHideLabel() - $.event 'IndexRefreshInternal' + $.event 'IndexRefreshInternal', {threadIDs: (t.fullID for t in threads), isCatalog} threads diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index 3a2580fff..f4dc79fbe 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -68,6 +68,8 @@ ExpandThread = postsCount = 0 filesCount = 0 for reply in replies + # rm elements above post such as unread line + $.rm node while (node = a.nextSibling) and node isnt reply # rm clones inlined.click() while inlined = $ '.inlined', reply if Conf['Quote Inlining'] postsCount++ diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index bce6cd10e..5671826c3 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -15,6 +15,7 @@ Unread = @hr = $.el 'hr', id: 'unread-line' + className: 'unread-line' @posts = new Set() @postsQuotingYou = new Set() @order = new RandomAccessList() diff --git a/src/Monitoring/UnreadIndex.coffee b/src/Monitoring/UnreadIndex.coffee index 2f77921b3..35c766d09 100644 --- a/src/Monitoring/UnreadIndex.coffee +++ b/src/Monitoring/UnreadIndex.coffee @@ -1,69 +1,109 @@ UnreadIndex = - hasUnread: {} + lastReadPost: {} + hr: {} markReadLink: {} init: -> - return unless g.VIEW is 'index' and Conf['Remember Last Read Post'] and Conf['Mark Read from Index'] + return unless g.VIEW is 'index' and Conf['Remember Last Read Post'] and Conf['Unread Line in Index'] @db = new DataBoard 'lastReadPosts', @sync - if Index.enabled - $.on d, 'IndexRefreshInternal', - @onIndexRefresh - else - Callbacks.Thread.push - name: 'Mark Read from Index' - cb: @node + Callbacks.Thread.push + name: 'Unread Line in Index' + cb: @node - Callbacks.Post.push - name: 'Mark Read from Index' - cb: @addPost - - onIndexRefresh: -> - g.threads.forEach (thread) -> - UnreadIndex.addMarkReadLink thread - UnreadIndex.update thread + $.on d, 'IndexRefreshInternal', @onIndexRefresh + $.on d, 'PostsInserted', @onPostsInserted node: -> - UnreadIndex.addMarkReadLink @ - UnreadIndex.update @ + UnreadIndex.lastReadPost[@fullID] = UnreadIndex.db.get( + boardID: @board.ID + threadID: @ID + ) or 0 + if !Index.enabled # let onIndexRefresh handle JSON Index + UnreadIndex.update @ - addPost: -> - if @ID is @thread.lastPost - UnreadIndex.update @thread + onIndexRefresh: (e) -> + return if e.detail.isCatalog + for threadID in e.detail.threadIDs + thread = g.threads[threadID] + UnreadIndex.update thread + + onPostsInserted: (e) -> + return if e.target is Index.root # onIndexRefresh handles this case + thread = Get.threadFromNode e.target + return if !thread or thread.nodes.root isnt e.target + UnreadIndex.update thread sync: -> - g.threads.forEach UnreadIndex.update + g.threads.forEach (thread) -> + lastReadPost = UnreadIndex.db.get( + boardID: thread.board.ID + threadID: thread.ID + ) or 0 + if lastReadPost isnt UnreadIndex.lastReadPost[thread.fullID] + UnreadIndex.lastReadPost[thread.fullID] = lastReadPost + if thread.nodes.root?.parentNode + UnreadIndex.update thread + + update: (thread) -> + lastReadPost = UnreadIndex.lastReadPost[thread.fullID] + repliesShown = 0 + repliesRead = 0 + firstUnread = null + thread.posts.forEach (post) -> + if post.isReply and post.nodes.root.parentNode is thread.nodes.root + repliesShown++ + if post.ID <= lastReadPost + repliesRead++ + else if (!firstUnread or post.ID < firstUnread.ID) and !post.isHidden and !QuoteYou.isYou(post) + firstUnread = post + + hr = UnreadIndex.hr[thread.fullID] + if firstUnread and (repliesRead or lastReadPost is thread.OP.ID) + if !hr + hr = UnreadIndex.hr[thread.fullID] = $.el 'hr', + className: 'unread-line' + $.before firstUnread.nodes.root, hr + else + $.rm hr + + hasUnread = if repliesShown + firstUnread or !repliesRead + else if Index.enabled + Index.lastPost(thread.ID) > lastReadPost + else + thread.OP.ID > lastReadPost + thread.nodes.root.classList.toggle 'unread-thread', hasUnread - addMarkReadLink: (thread) -> - return unless thread.nodes.root link = UnreadIndex.markReadLink[thread.fullID] - unless link + if !link link = UnreadIndex.markReadLink[thread.fullID] = $.el 'a', className: 'unread-mark-read brackets-wrap' href: 'javascript:;' textContent: 'Mark Read' $.on link, 'click', UnreadIndex.markRead - if link.parentNode isnt thread.nodes.root + if (divider = $ Site.selectors.threadDivider, thread.nodes.root) # divider inside thread as in Tinyboard + $.before divider, link + else $.add thread.nodes.root, link - update: (thread) -> - return unless thread.nodes.root - lastReadPost = UnreadIndex.db.get( - boardID: thread.board.ID - threadID: thread.ID - ) or 0 - hasUnread = (lastReadPost < thread.lastPost) - if hasUnread isnt UnreadIndex.hasUnread[thread.fullID] - thread.nodes.root.classList.toggle 'unread-thread', hasUnread - markRead: -> thread = Get.threadFromNode @ + if Index.enabled + lastPost = Index.lastPost(thread.ID) + else + lastPost = 0 + thread.posts.forEach (post) -> + if post.ID > lastPost and !post.isFetchedQuote + lastPost = post.ID + UnreadIndex.lastReadPost[thread.fullID] = lastPost UnreadIndex.db.set boardID: thread.board.ID threadID: thread.ID - val: thread.lastPost - UnreadIndex.update thread + val: lastPost + $.rm UnreadIndex.hr[thread.fullID] + $.rm UnreadIndex.markReadLink[thread.fullID] ThreadWatcher.update thread.board.ID, thread.ID, unread: 0 quotingYou: false diff --git a/src/classes/Post.coffee b/src/classes/Post.coffee index 3bfa57212..74fbe703f 100644 --- a/src/classes/Post.coffee +++ b/src/classes/Post.coffee @@ -61,7 +61,6 @@ class Post @board.posts.push @ID, @ @thread.posts.push @ID, @ - @thread.lastPost = @ID if @ID > @thread.lastPost g.posts.push @fullID, @ parseNodes: (root) -> diff --git a/src/classes/Thread.coffee b/src/classes/Thread.coffee index 941dce8ae..d5e05d691 100644 --- a/src/classes/Thread.coffee +++ b/src/classes/Thread.coffee @@ -13,14 +13,12 @@ class Thread @fileLimit = false @ipCount = undefined @json = null - @lastPost = 0 @OP = null @catalogView = null @nodes = - root: null - summary: null + root: null @board.threads.push @ID, @ g.threads.push @fullID, @ diff --git a/src/config/Config.coffee b/src/config/Config.coffee index 0178367fa..497849c7f 100644 --- a/src/config/Config.coffee +++ b/src/config/Config.coffee @@ -383,9 +383,9 @@ Config = 'Scroll back to the last read post when reopening a thread.' 1 ] - 'Mark Read from Index': [ + 'Unread Line in Index': [ false - 'Add links in the index for marking threads read.' + 'Show a line between read and unread posts in threads in the index.' 1 ] 'Remove Thread Excerpt': [ diff --git a/src/css/spooky.css b/src/css/spooky.css index a7db8fcf5..096331ad3 100644 --- a/src/css/spooky.css +++ b/src/css/spooky.css @@ -147,7 +147,7 @@ } /* Unread */ -:root.spooky #unread-line { +:root.spooky .unread-line { border-color: rgb(197, 200, 198); } diff --git a/src/css/style.css b/src/css/style.css index cfef612fd..3997030fe 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1059,7 +1059,7 @@ span.hide-announcement { } /* Unread */ -#unread-line { +.unread-line { margin: 0; border-color: rgb(255,0,0); } diff --git a/src/css/tomorrow.css b/src/css/tomorrow.css index fbbc95617..365f29fc0 100644 --- a/src/css/tomorrow.css +++ b/src/css/tomorrow.css @@ -154,7 +154,7 @@ } /* Unread */ -:root.tomorrow #unread-line { +:root.tomorrow .unread-line { border-color: rgb(197, 200, 198); } diff --git a/src/main/Main.coffee b/src/main/Main.coffee index 4d1a61e25..a0cf5aa70 100644 --- a/src/main/Main.coffee +++ b/src/main/Main.coffee @@ -510,7 +510,7 @@ Main = ['Thread Expansion', ExpandThread] ['Favicon', Favicon] ['Unread', Unread] - ['Mark Read from Index', UnreadIndex] + ['Unread Line in Index', UnreadIndex] ['Quote Threading', QuoteThreading] ['Thread Stats', ThreadStats] ['Thread Updater', ThreadUpdater] diff --git a/src/site/SW.tinyboard.coffee b/src/site/SW.tinyboard.coffee index d42cac420..dd1c4cd57 100644 --- a/src/site/SW.tinyboard.coffee +++ b/src/site/SW.tinyboard.coffee @@ -53,6 +53,7 @@ SW.tinyboard = selectors: board: 'form[name="postcontrols"]' thread: 'div[id^="thread_"]' + threadDivider: 'div[id^="thread_"] > hr:last-of-type' postContainer: '.reply' # postContainer is thread for OP infoRoot: '.intro' info: diff --git a/src/site/SW.yotsuba.coffee b/src/site/SW.yotsuba.coffee index 8ad7dda4e..6dc574b84 100644 --- a/src/site/SW.yotsuba.coffee +++ b/src/site/SW.yotsuba.coffee @@ -7,6 +7,7 @@ SW.yotsuba = selectors: board: '.board' thread: '.thread' + threadDivider: '.board > hr' postContainer: '.postContainer' sideArrows: '.sideArrows' post: '.post'