Add Thread Watcher.
This commit is contained in:
parent
6eac5ca3b2
commit
abb8128afd
123
4chan_x.user.js
123
4chan_x.user.js
@ -43,7 +43,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(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; },
|
__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,
|
__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; };
|
__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 Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
|
||||||
'Thread Stats': [true, 'Display reply and image count.'],
|
'Thread Stats': [true, 'Display reply and image count.'],
|
||||||
'Thread Watcher': [true, 'Bookmark threads.'],
|
'Thread Watcher': [true, 'Bookmark threads.'],
|
||||||
'Auto Watch': [true, 'Automatically watch threads that you start.'],
|
'Auto Watch': [true, 'Automatically watch threads you start.'],
|
||||||
'Auto Watch Reply': [false, 'Automatically watch threads that you reply to.']
|
'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
|
||||||
},
|
},
|
||||||
Posting: {
|
Posting: {
|
||||||
'Quick Reply': [true, 'WMD.'],
|
'Quick Reply': [true, 'WMD.'],
|
||||||
@ -1112,7 +1112,7 @@
|
|||||||
var link, settings;
|
var link, settings;
|
||||||
link = $.el('a', {
|
link = $.el('a', {
|
||||||
className: 'settings-link',
|
className: 'settings-link',
|
||||||
textContent: '4chan X Settings',
|
textContent: '4chan X Alpha Settings',
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
});
|
});
|
||||||
$.on(link, 'click', Settings.open);
|
$.on(link, 'click', Settings.open);
|
||||||
@ -4231,7 +4231,7 @@
|
|||||||
this.postCountEl = $('#post-count', this.dialog);
|
this.postCountEl = $('#post-count', this.dialog);
|
||||||
this.fileCountEl = $('#file-count', this.dialog);
|
this.fileCountEl = $('#file-count', this.dialog);
|
||||||
this.fileLimit = (function() {
|
this.fileLimit = (function() {
|
||||||
switch (g.BOARD) {
|
switch (g.BOARD.ID) {
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'v':
|
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;', '<div class=move>Thread Watcher</div>');
|
||||||
|
$.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 = {
|
QR = {
|
||||||
init: function() {
|
init: function() {
|
||||||
var link;
|
var link;
|
||||||
@ -5945,6 +6057,7 @@
|
|||||||
initFeature('Unread', Unread);
|
initFeature('Unread', Unread);
|
||||||
initFeature('Thread Stats', ThreadStats);
|
initFeature('Thread Stats', ThreadStats);
|
||||||
initFeature('Thread Updater', ThreadUpdater);
|
initFeature('Thread Updater', ThreadUpdater);
|
||||||
|
initFeature('Thread Watcher', ThreadWatcher);
|
||||||
console.timeEnd('All initializations');
|
console.timeEnd('All initializations');
|
||||||
$.on(d, '4chanMainInit', Main.initStyle);
|
$.on(d, '4chanMainInit', Main.initStyle);
|
||||||
return $.ready(Main.initReady);
|
return $.ready(Main.initReady);
|
||||||
|
|||||||
@ -39,8 +39,8 @@ Config =
|
|||||||
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.']
|
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.']
|
||||||
'Thread Stats': [true, 'Display reply and image count.']
|
'Thread Stats': [true, 'Display reply and image count.']
|
||||||
'Thread Watcher': [true, 'Bookmark threads.']
|
'Thread Watcher': [true, 'Bookmark threads.']
|
||||||
'Auto Watch': [true, 'Automatically watch threads that you start.']
|
'Auto Watch': [true, 'Automatically watch threads you start.']
|
||||||
'Auto Watch Reply': [false, 'Automatically watch threads that you reply to.']
|
'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
|
||||||
Posting:
|
Posting:
|
||||||
'Quick Reply': [true, 'WMD.']
|
'Quick Reply': [true, 'WMD.']
|
||||||
'Persistent QR': [false, 'The Quick reply won\'t disappear after posting.']
|
'Persistent QR': [false, 'The Quick reply won\'t disappear after posting.']
|
||||||
|
|||||||
@ -119,7 +119,7 @@ Settings =
|
|||||||
# 4chan X settings link
|
# 4chan X settings link
|
||||||
link = $.el 'a',
|
link = $.el 'a',
|
||||||
className: 'settings-link'
|
className: 'settings-link'
|
||||||
textContent: '4chan X Settings'
|
textContent: '<%= meta.name %> Settings'
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
$.on link, 'click', Settings.open
|
$.on link, 'click', Settings.open
|
||||||
$.event 'AddMenuEntry',
|
$.event 'AddMenuEntry',
|
||||||
@ -2686,7 +2686,7 @@ ThreadStats =
|
|||||||
@postCountEl = $ '#post-count', @dialog
|
@postCountEl = $ '#post-count', @dialog
|
||||||
@fileCountEl = $ '#file-count', @dialog
|
@fileCountEl = $ '#file-count', @dialog
|
||||||
@fileLimit = # XXX boards config, need up to date data on this, check browser
|
@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'
|
when 'a', 'b', 'v', 'co', 'mlp'
|
||||||
251
|
251
|
||||||
when 'vg'
|
when 'vg'
|
||||||
@ -2950,3 +2950,96 @@ ThreadUpdater =
|
|||||||
newPosts: posts
|
newPosts: posts
|
||||||
deletedPosts: deletedPosts
|
deletedPosts: deletedPosts
|
||||||
deletedFiles: deletedFiles
|
deletedFiles: deletedFiles
|
||||||
|
|
||||||
|
ThreadWatcher =
|
||||||
|
init: ->
|
||||||
|
return if g.VIEW is 'catalog' or !Conf['Thread Watcher']
|
||||||
|
@dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;',
|
||||||
|
'<div class=move>Thread Watcher</div>'
|
||||||
|
|
||||||
|
$.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
|
||||||
|
|||||||
@ -343,6 +343,7 @@ Main =
|
|||||||
initFeature 'Unread', Unread
|
initFeature 'Unread', Unread
|
||||||
initFeature 'Thread Stats', ThreadStats
|
initFeature 'Thread Stats', ThreadStats
|
||||||
initFeature 'Thread Updater', ThreadUpdater
|
initFeature 'Thread Updater', ThreadUpdater
|
||||||
|
initFeature 'Thread Watcher', ThreadWatcher
|
||||||
console.timeEnd 'All initializations'
|
console.timeEnd 'All initializations'
|
||||||
|
|
||||||
$.on d, '4chanMainInit', Main.initStyle
|
$.on d, '4chanMainInit', Main.initStyle
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user