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() {
|
||||
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;', '<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 = {
|
||||
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);
|
||||
|
||||
@ -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.']
|
||||
|
||||
@ -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;',
|
||||
'<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 'Thread Stats', ThreadStats
|
||||
initFeature 'Thread Updater', ThreadUpdater
|
||||
initFeature 'Thread Watcher', ThreadWatcher
|
||||
console.timeEnd 'All initializations'
|
||||
|
||||
$.on d, '4chanMainInit', Main.initStyle
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user