diff --git a/4chan_x.user.js b/4chan_x.user.js
index 40348d1a1..2830868c5 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, ExpandComment, ExpandThread, Favicon, 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,
+ var $, $$, Anonymize, ArchiveLink, AutoGIF, Board, Build, Clone, Conf, Config, DeleteLink, DownloadLink, ExpandComment, ExpandThread, Favicon, 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, ThreadWatcher, 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; };
@@ -93,8 +93,8 @@
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
'Thread Stats': [true, 'Display reply and image count.'],
'Thread Watcher': [true, 'Bookmark threads.'],
- 'Auto Watch': [true, 'Automatically watch threads that you start.'],
- 'Auto Watch Reply': [false, 'Automatically watch threads that you reply to.']
+ 'Auto Watch': [true, 'Automatically watch threads you start.'],
+ 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
},
Posting: {
'Quick Reply': [true, 'WMD.'],
@@ -1112,7 +1112,7 @@
var link, settings;
link = $.el('a', {
className: 'settings-link',
- textContent: '4chan X Settings',
+ textContent: '4chan X Alpha Settings',
href: 'javascript:;'
});
$.on(link, 'click', Settings.open);
@@ -4231,7 +4231,7 @@
this.postCountEl = $('#post-count', this.dialog);
this.fileCountEl = $('#file-count', this.dialog);
this.fileLimit = (function() {
- switch (g.BOARD) {
+ switch (g.BOARD.ID) {
case 'a':
case 'b':
case 'v':
@@ -4563,6 +4563,118 @@
}
};
+ ThreadWatcher = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Thread Watcher']) {
+ return;
+ }
+ this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '
Thread Watcher
');
+ $.on(d, 'QRPostSuccessful', this.cb.post);
+ $.on(d, '4chanXInitFinished', this.ready);
+ $.sync('WatchedThreads', this.refresh);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Watcher',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var favicon, op;
+ op = this.posts[this];
+ favicon = $.el('img', {
+ className: 'favicon'
+ });
+ $.on(favicon, 'click', ThreadWatcher.cb.toggle);
+ $.before($('input', op.nodes.post), favicon);
+ if (g.VIEW === 'thread' && this.ID === $.get('AutoWatch', 0)) {
+ ThreadWatcher.watch(this);
+ return $["delete"]('AutoWatch');
+ }
+ },
+ ready: function() {
+ ThreadWatcher.refresh();
+ return $.add(d.body, ThreadWatcher.dialog);
+ },
+ refresh: function(watched) {
+ var ID, board, div, favicon, id, link, nodes, op, props, thread, x, _ref, _ref1;
+ watched || (watched = $.get('WatchedThreads', {}));
+ nodes = [$('.move', ThreadWatcher.dialog)];
+ for (board in watched) {
+ _ref = watched[board];
+ for (id in _ref) {
+ props = _ref[id];
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.x);
+ link = $.el('a', props);
+ link.title = link.textContent;
+ div = $.el('div');
+ $.add(div, [x, $.tn(' '), link]);
+ nodes.push(div);
+ }
+ }
+ ThreadWatcher.dialog.innerHTML = '';
+ $.add(ThreadWatcher.dialog, nodes);
+ watched = watched[g.BOARD] || {};
+ _ref1 = g.BOARD.threads;
+ for (ID in _ref1) {
+ thread = _ref1[ID];
+ op = thread.posts[thread];
+ favicon = $('.favicon', op.nodes.post);
+ favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
+ }
+ },
+ cb: {
+ toggle: function() {
+ return ThreadWatcher.toggle(Get.postFromNode(this).thread);
+ },
+ x: function() {
+ var thread;
+ thread = this.nextElementSibling.pathname.split('/');
+ return ThreadWatcher.unwatch(thread[1], thread[3]);
+ },
+ post: function(e) {
+ var postID, threadID, _ref;
+ _ref = e.detail, postID = _ref.postID, threadID = _ref.threadID;
+ if (threadID === '0') {
+ if (Conf['Auto Watch']) {
+ return $.set('AutoWatch', +postID);
+ }
+ } else if (Conf['Auto Watch Reply']) {
+ return ThreadWatcher.watch(g.BOARD.threads[threadID]);
+ }
+ }
+ },
+ toggle: function(thread) {
+ var op;
+ op = thread.posts[thread];
+ if ($('.favicon', op.nodes.post).src === Favicon.empty) {
+ return ThreadWatcher.watch(thread);
+ } else {
+ return ThreadWatcher.unwatch(thread.board, thread.ID);
+ }
+ },
+ unwatch: function(board, threadID) {
+ var watched;
+ watched = $.get('WatchedThreads', {});
+ delete watched[board][threadID];
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ },
+ watch: function(thread) {
+ var watched, _name;
+ watched = $.get('WatchedThreads', {});
+ watched[_name = thread.board] || (watched[_name] = {});
+ watched[thread.board][thread] = {
+ href: "/" + thread.board + "/res/" + thread,
+ textContent: Get.threadExcerpt(thread)
+ };
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ }
+ };
+
QR = {
init: function() {
var link;
@@ -5945,6 +6057,7 @@
initFeature('Unread', Unread);
initFeature('Thread Stats', ThreadStats);
initFeature('Thread Updater', ThreadUpdater);
+ initFeature('Thread Watcher', ThreadWatcher);
console.timeEnd('All initializations');
$.on(d, '4chanMainInit', Main.initStyle);
return $.ready(Main.initReady);
diff --git a/src/config.coffee b/src/config.coffee
index ce99e0512..46973074d 100644
--- a/src/config.coffee
+++ b/src/config.coffee
@@ -39,8 +39,8 @@ Config =
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.']
'Thread Stats': [true, 'Display reply and image count.']
'Thread Watcher': [true, 'Bookmark threads.']
- 'Auto Watch': [true, 'Automatically watch threads that you start.']
- 'Auto Watch Reply': [false, 'Automatically watch threads that you reply to.']
+ 'Auto Watch': [true, 'Automatically watch threads you start.']
+ 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
Posting:
'Quick Reply': [true, 'WMD.']
'Persistent QR': [false, 'The Quick reply won\'t disappear after posting.']
diff --git a/src/features.coffee b/src/features.coffee
index e4f51e2d3..6ddf28429 100644
--- a/src/features.coffee
+++ b/src/features.coffee
@@ -119,7 +119,7 @@ Settings =
# 4chan X settings link
link = $.el 'a',
className: 'settings-link'
- textContent: '4chan X Settings'
+ textContent: '<%= meta.name %> Settings'
href: 'javascript:;'
$.on link, 'click', Settings.open
$.event 'AddMenuEntry',
@@ -2686,7 +2686,7 @@ ThreadStats =
@postCountEl = $ '#post-count', @dialog
@fileCountEl = $ '#file-count', @dialog
@fileLimit = # XXX boards config, need up to date data on this, check browser
- switch g.BOARD
+ switch g.BOARD.ID
when 'a', 'b', 'v', 'co', 'mlp'
251
when 'vg'
@@ -2950,3 +2950,96 @@ ThreadUpdater =
newPosts: posts
deletedPosts: deletedPosts
deletedFiles: deletedFiles
+
+ThreadWatcher =
+ init: ->
+ return if g.VIEW is 'catalog' or !Conf['Thread Watcher']
+ @dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;',
+ 'Thread Watcher
'
+
+ $.on d, 'QRPostSuccessful', @cb.post
+ $.on d, '4chanXInitFinished', @ready
+ $.sync 'WatchedThreads', @refresh
+
+ Thread::callbacks.push
+ name: 'Thread Watcher'
+ cb: @node
+
+ node: ->
+ op = @posts[@]
+ favicon = $.el 'img',
+ className: 'favicon'
+ $.on favicon, 'click', ThreadWatcher.cb.toggle
+ $.before $('input', op.nodes.post), favicon
+ if g.VIEW is 'thread' and @ID is $.get 'AutoWatch', 0
+ ThreadWatcher.watch @
+ $.delete 'AutoWatch'
+
+ ready: ->
+ ThreadWatcher.refresh()
+ $.add d.body, ThreadWatcher.dialog
+
+ refresh: (watched) ->
+ watched or= $.get 'WatchedThreads', {}
+ nodes = [$('.move', ThreadWatcher.dialog)]
+ for board of watched
+ for id, props of watched[board]
+ x = $.el 'a',
+ textContent: '×'
+ href: 'javascript:;'
+ $.on x, 'click', ThreadWatcher.cb.x
+ link = $.el 'a', props
+ link.title = link.textContent
+
+ div = $.el 'div'
+ $.add div, [x, $.tn(' '), link]
+ nodes.push div
+
+ ThreadWatcher.dialog.innerHTML = ''
+ $.add ThreadWatcher.dialog, nodes
+
+ watched = watched[g.BOARD] or {}
+ for ID, thread of g.BOARD.threads
+ op = thread.posts[thread]
+ favicon = $ '.favicon', op.nodes.post
+ favicon.src = if ID of watched
+ Favicon.default
+ else
+ Favicon.empty
+ return
+
+ cb:
+ toggle: ->
+ ThreadWatcher.toggle Get.postFromNode(@).thread
+ x: ->
+ thread = @nextElementSibling.pathname.split '/'
+ ThreadWatcher.unwatch thread[1], thread[3]
+ post: (e) ->
+ {postID, threadID} = e.detail
+ if threadID is '0'
+ if Conf['Auto Watch']
+ $.set 'AutoWatch', +postID
+ else if Conf['Auto Watch Reply']
+ ThreadWatcher.watch g.BOARD.threads[threadID]
+
+ toggle: (thread) ->
+ op = thread.posts[thread]
+ if $('.favicon', op.nodes.post).src is Favicon.empty
+ ThreadWatcher.watch thread
+ else
+ ThreadWatcher.unwatch thread.board, thread.ID
+
+ unwatch: (board, threadID) ->
+ watched = $.get 'WatchedThreads', {}
+ delete watched[board][threadID]
+ ThreadWatcher.refresh watched
+ $.set 'WatchedThreads', watched
+
+ watch: (thread) ->
+ watched = $.get 'WatchedThreads', {}
+ watched[thread.board] or= {}
+ watched[thread.board][thread] =
+ href: "/#{thread.board}/res/#{thread}"
+ textContent: Get.threadExcerpt thread
+ ThreadWatcher.refresh watched
+ $.set 'WatchedThreads', watched
diff --git a/src/main.coffee b/src/main.coffee
index 2bbdbc2e2..a6fe0a1fc 100644
--- a/src/main.coffee
+++ b/src/main.coffee
@@ -343,6 +343,7 @@ Main =
initFeature 'Unread', Unread
initFeature 'Thread Stats', ThreadStats
initFeature 'Thread Updater', ThreadUpdater
+ initFeature 'Thread Watcher', ThreadWatcher
console.timeEnd 'All initializations'
$.on d, '4chanMainInit', Main.initStyle