From 1771713d6f2d784833df7fd7dad6eaf00ba28b4a Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 16 Feb 2013 18:15:27 +0100 Subject: [PATCH] Add Unread Count. Remove the "read thread" keybind. Fix #714. --- 4chan_x.user.js | 78 +++++++++++++++++++++++++++++++++++++++++++-- changelog | 1 + src/config.coffee | 1 - src/features.coffee | 52 ++++++++++++++++++++++++++++++ src/main.coffee | 1 + 5 files changed, 130 insertions(+), 3 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index b3253a578..a64f453af 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -43,7 +43,7 @@ */ (function() { - var $, $$, Anonymize, ArchiveLink, AutoGIF, Board, Build, Clone, Conf, Config, DeleteLink, DownloadLink, FileInfo, Filter, Get, Header, ImageExpand, ImageHover, Main, Menu, Notification, Polyfill, Post, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Recursive, Redirect, RelativeDates, ReplyHiding, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, Time, UI, d, doc, g, + var $, $$, Anonymize, ArchiveLink, AutoGIF, Board, Build, Clone, Conf, Config, DeleteLink, DownloadLink, FileInfo, Filter, Get, Header, ImageExpand, ImageHover, Main, Menu, Notification, Polyfill, Post, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Recursive, Redirect, RelativeDates, ReplyHiding, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, Time, UI, Unread, d, doc, g, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; @@ -151,7 +151,6 @@ 'submit QR': ['alt+s', 'Submit post.'], 'watch': ['w', 'Watch thread.'], 'update': ['u', 'Update the thread now.'], - 'read thread': ['r', 'Mark thread as read.'], 'expand image': ['E', 'Expand selected image.'], 'expand images': ['e', 'Expand all images.'], 'front page': ['0', 'Jump to page 0.'], @@ -3907,6 +3906,80 @@ } }; + Unread = { + init: function() { + if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) { + return; + } + $.on(d, 'ThreadUpdate', this.onUpdate); + $.on(d, 'QRPostSuccessful', this.post); + $.on(d, 'scroll visibilitychange', this.read); + return Thread.prototype.callbacks.push({ + name: 'Unread', + cb: this.node + }); + }, + node: function() { + var ID, post, posts, _ref; + Unread.yourPosts = []; + Unread.posts = []; + Unread.title = d.title; + posts = []; + _ref = this.posts; + for (ID in _ref) { + post = _ref[ID]; + if (post.isReply) { + posts.push(post); + } + } + Unread.addPosts(posts); + return Unread.update(); + }, + addPosts: function(newPosts) { + var height, index, post, _i, _len; + if (!d.hidden) { + height = doc.clientHeight; + } + for (_i = 0, _len = newPosts.length; _i < _len; _i++) { + post = newPosts[_i]; + if ((index = Unread.yourPosts.indexOf(post.ID)) !== -1) { + Unread.yourPosts.splice(index, 1); + } else if (!post.isHidden && (d.hidden || post.nodes.root.getBoundingClientRect().bottom > height)) { + Unread.posts.push(post); + } + } + }, + onUpdate: function(e) { + if (!e.detail[404]) { + Unread.addPosts(e.detail.newPosts); + } + return Unread.update(); + }, + post: function(e) { + return Unread.yourPosts.push(+e.detail.postID); + }, + read: function() { + var bottom, height, i, post, _i, _len, _ref; + height = doc.clientHeight; + _ref = Unread.posts; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + post = _ref[i]; + bottom = post.nodes.root.getBoundingClientRect().bottom; + if (bottom > height) { + break; + } + } + if (!i) { + return; + } + Unread.posts = Unread.posts.slice(i); + return Unread.update(); + }, + update: function() { + return d.title = "(" + Unread.posts.length + ") " + Unread.title; + } + }; + ThreadStats = { init: function() { if (g.VIEW !== 'thread' || !Conf['Thread Stats']) { @@ -5618,6 +5691,7 @@ initFeature('Auto-GIF', AutoGIF); initFeature('Image Hover', ImageHover); initFeature('Thread Excerpt', ThreadExcerpt); + initFeature('Unread', Unread); initFeature('Thread Stats', ThreadStats); initFeature('Thread Updater', ThreadUpdater); console.timeEnd('All initializations'); diff --git a/changelog b/changelog index 4b53ac25a..8ed639190 100644 --- a/changelog +++ b/changelog @@ -21,6 +21,7 @@ alpha Added Thread & Post Hiding in the Menu, with individual settings. Thread & Post Hiding Buttons can now be disabled in the settings. Recursive Hiding will be automatically applied when manually hiding a post. + Visible posts will not be taken into account towards the unread count. Fix Chrome's install warning saying that 4chan X would execute on all domains. Fix Quote Backlinks not affecting inlined quotes. Fix Quote Highlighting not affecting inlined quotes. diff --git a/src/config.coffee b/src/config.coffee index 56ea5e27b..97b67aae5 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -141,7 +141,6 @@ Config = # Thread related 'watch': ['w', 'Watch thread.'] 'update': ['u', 'Update the thread now.'] - 'read thread': ['r', 'Mark thread as read.'] # Images 'expand image': ['E', 'Expand selected image.'] 'expand images': ['e', 'Expand all images.'] diff --git a/src/features.coffee b/src/features.coffee index 3dd3f6d61..55e9904e9 100644 --- a/src/features.coffee +++ b/src/features.coffee @@ -2430,6 +2430,58 @@ ThreadExcerpt = node: -> d.title = Get.threadExcerpt @ +Unread = + init: -> + return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Favicon'] + $.on d, 'ThreadUpdate', @onUpdate + $.on d, 'QRPostSuccessful', @post + $.on d, 'scroll visibilitychange', @read + + Thread::callbacks.push + name: 'Unread' + cb: @node + + node: -> + Unread.yourPosts = [] + Unread.posts = [] + Unread.title = d.title + posts = [] + for ID, post of @posts + posts.push post if post.isReply + Unread.addPosts posts + Unread.update() + + addPosts: (newPosts) -> + unless d.hidden + height = doc.clientHeight + for post in newPosts + if (index = Unread.yourPosts.indexOf post.ID) isnt -1 + Unread.yourPosts.splice index, 1 + else if !post.isHidden and (d.hidden or post.nodes.root.getBoundingClientRect().bottom > height) + Unread.posts.push post + return + + onUpdate: (e) -> + unless e.detail[404] + Unread.addPosts e.detail.newPosts + Unread.update() + + post: (e) -> + Unread.yourPosts.push +e.detail.postID + + read: -> + height = doc.clientHeight + for post, i in Unread.posts + {bottom} = post.nodes.root.getBoundingClientRect() + break if bottom > height # post is not completely read + return unless i + + Unread.posts = Unread.posts[i..] + Unread.update() + + update: -> + d.title = "(#{Unread.posts.length}) #{Unread.title}" + ThreadStats = init: -> return if g.VIEW isnt 'thread' or !Conf['Thread Stats'] diff --git a/src/main.coffee b/src/main.coffee index 59bd8cefe..dd39a1665 100644 --- a/src/main.coffee +++ b/src/main.coffee @@ -334,6 +334,7 @@ Main = initFeature 'Auto-GIF', AutoGIF initFeature 'Image Hover', ImageHover initFeature 'Thread Excerpt', ThreadExcerpt + initFeature 'Unread', Unread initFeature 'Thread Stats', ThreadStats initFeature 'Thread Updater', ThreadUpdater console.timeEnd 'All initializations'