Add Recursive Hiding.

Close #665.
Add Thread.fullID and Post.fullID.
Smarter quote un-inlining.
This commit is contained in:
Nicolas Stepien 2013-01-24 11:45:05 +01:00
parent 8a587f515c
commit 81dd0fe9af
5 changed files with 270 additions and 171 deletions

View File

@ -20,7 +20,7 @@
// @icon https://github.com/MayhemYDG/4chan-x/raw/stable/img/icon.gif // @icon https://github.com/MayhemYDG/4chan-x/raw/stable/img/icon.gif
// ==/UserScript== // ==/UserScript==
/* 4chan X Alpha - Version 3.0.0 - 2013-01-22 /* 4chan X Alpha - Version 3.0.0 - 2013-01-24
* http://mayhemydg.github.com/4chan-x/ * http://mayhemydg.github.com/4chan-x/
* *
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com> * Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
@ -43,7 +43,7 @@
*/ */
(function() { (function() {
var $, $$, Anonymize, AutoGIF, Board, Build, Clone, Conf, Config, FileInfo, Get, ImageHover, Main, Post, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, RevealSpoilers, Sauce, Thread, ThreadHiding, ThreadUpdater, Time, UI, d, g, _base, var $, $$, Anonymize, AutoGIF, Board, Build, Clone, Conf, Config, FileInfo, Get, ImageHover, Main, Post, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Recursive, Redirect, ReplyHiding, RevealSpoilers, Sauce, Thread, ThreadHiding, ThreadUpdater, Time, UI, d, g, _base,
__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; };
@ -65,7 +65,7 @@
Filtering: { Filtering: {
'Anonymize': [false, 'Turn everyone Anonymous.'], 'Anonymize': [false, 'Turn everyone Anonymous.'],
'Filter': [true, 'Self-moderation placebo.'], 'Filter': [true, 'Self-moderation placebo.'],
'Recursive Filtering': [true, 'Filter replies of filtered posts, recursively.'], 'Recursive Hiding': [true, 'Filter replies of filtered posts, recursively.'],
'Reply Hiding': [true, 'Hide single replies.'], 'Reply Hiding': [true, 'Hide single replies.'],
'Thread Hiding': [true, 'Hide entire threads.'], 'Thread Hiding': [true, 'Hide entire threads.'],
'Stubs': [true, 'Make stubs of hidden threads / replies.'] 'Stubs': [true, 'Make stubs of hidden threads / replies.']
@ -696,7 +696,7 @@
if (_ref = this.ID, __indexOf.call(ThreadHiding.hiddenThreads.threads, _ref) >= 0) { if (_ref = this.ID, __indexOf.call(ThreadHiding.hiddenThreads.threads, _ref) >= 0) {
ThreadHiding.hide(this); ThreadHiding.hide(this);
} }
return $.prepend(this.posts[this].nodes.root, ThreadHiding.makeButton(this, '-')); return $.prepend(this.posts[this].nodes.root, ThreadHiding.makeButton(this, 'hide'));
}, },
getHiddenThreads: function() { getHiddenThreads: function() {
var hiddenThreads; var hiddenThreads;
@ -748,11 +748,11 @@
} }
}); });
}, },
makeButton: function(thread, sign) { makeButton: function(thread, type) {
var a; var a;
a = $.el('a', { a = $.el('a', {
className: 'hide-thread-button', className: "" + type + "-thread-button",
innerHTML: "<span>[&nbsp;" + sign + "&nbsp;]</span>&nbsp;", innerHTML: "<span>[&nbsp;" + (type === 'hide' ? '-' : '+') + "&nbsp;]</span>",
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(a, 'click', function() { $.on(a, 'click', function() {
@ -798,9 +798,11 @@
numReplies += $$('.opContainer ~ .replyContainer', threadRoot).length; numReplies += $$('.opContainer ~ .replyContainer', threadRoot).length;
numReplies = numReplies === 1 ? '1 reply' : "" + numReplies + " replies"; numReplies = numReplies === 1 ? '1 reply' : "" + numReplies + " replies";
opInfo = Conf['Anonymize'] ? 'Anonymous' : $('.nameBlock', op.nodes.info).textContent; opInfo = Conf['Anonymize'] ? 'Anonymous' : $('.nameBlock', op.nodes.info).textContent;
a = ThreadHiding.makeButton(thread, '+'); a = ThreadHiding.makeButton(thread, 'show');
$.add(a, $.tn("" + opInfo + " (" + numReplies + ")")); $.add(a, $.tn(" " + opInfo + " (" + numReplies + ")"));
thread.stub = $.el('div'); thread.stub = $.el('div', {
className: 'stub'
});
$.add(thread.stub, a); $.add(thread.stub, a);
return $.before(threadRoot, thread.stub); return $.before(threadRoot, thread.stub);
}, },
@ -834,7 +836,7 @@
ReplyHiding.hide(this); ReplyHiding.hide(this);
} }
} }
return $.replace($('.sideArrows', this.nodes.root), ReplyHiding.makeButton(this, '-')); return $.replace($('.sideArrows', this.nodes.root), ReplyHiding.makeButton(this, 'hide'));
}, },
getHiddenPosts: function() { getHiddenPosts: function() {
var hiddenPosts; var hiddenPosts;
@ -880,11 +882,11 @@
} }
}); });
}, },
makeButton: function(post, sign) { makeButton: function(post, type) {
var a; var a;
a = $.el('a', { a = $.el('a', {
className: 'hide-reply-button', className: "" + type + "-reply-button",
innerHTML: "<span>[&nbsp;" + sign + "&nbsp;]</span>", innerHTML: "<span>[&nbsp;" + (type === 'hide' ? '-' : '+') + "&nbsp;]</span>",
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(a, 'click', function() { $.on(a, 'click', function() {
@ -893,27 +895,20 @@
return a; return a;
}, },
toggle: function(post) { toggle: function(post) {
var hiddenPosts, quotelink, quotelinks, thread, _i, _j, _len, _len1; var hiddenPosts, index, thread;
hiddenPosts = ReplyHiding.getHiddenPosts(); hiddenPosts = ReplyHiding.getHiddenPosts();
quotelinks = Get.allQuotelinksLinkingTo(post);
if (post.isHidden) { if (post.isHidden) {
ReplyHiding.show(post); ReplyHiding.show(post);
for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
quotelink = quotelinks[_i];
$.rmClass(quotelink, 'filtered');
}
thread = hiddenPosts.threads[post.thread]; thread = hiddenPosts.threads[post.thread];
if (thread.length === 1) { if ((index = thread.indexOf(post.ID)) > -1) {
delete hiddenPosts.threads[post.thread]; if (thread.length === 1) {
} else { delete hiddenPosts.threads[post.thread];
thread.splice(thread.indexOf(post.ID), 1); } else {
thread.splice(index, 1);
}
} }
} else { } else {
ReplyHiding.hide(post); ReplyHiding.hide(post);
for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
quotelink = quotelinks[_j];
$.addClass(quotelink, 'filtered');
}
if (!(thread = hiddenPosts.threads[post.thread])) { if (!(thread = hiddenPosts.threads[post.thread])) {
thread = hiddenPosts.threads[post.thread] = []; thread = hiddenPosts.threads[post.thread] = [];
} }
@ -921,31 +916,101 @@
} }
return $.set("hiddenPosts." + g.BOARD, hiddenPosts); return $.set("hiddenPosts." + g.BOARD, hiddenPosts);
}, },
hide: function(post, makeStub) { hide: function(post, makeStub, hideRecursively) {
var a, postInfo; var a, postInfo, quotelink, _i, _len, _ref;
if (makeStub == null) { if (makeStub == null) {
makeStub = Conf['Stubs']; makeStub = Conf['Stubs'];
} }
if (hideRecursively == null) {
hideRecursively = Conf['Recursive Hiding'];
}
if (post.isHidden) { if (post.isHidden) {
return; return;
} }
post.nodes.root.hidden = post.isHidden = true; post.isHidden = true;
if (hideRecursively) {
Recursive.hide(post, makeStub, true);
}
_ref = Get.allQuotelinksLinkingTo(post);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quotelink = _ref[_i];
$.addClass(quotelink, 'filtered');
}
if (!makeStub) { if (!makeStub) {
return; return;
} }
a = ReplyHiding.makeButton(post, '+'); a = ReplyHiding.makeButton(post, 'show');
postInfo = Conf['Anonymize'] ? 'Anonymous' : $('.nameBlock', post.nodes.info).textContent; postInfo = Conf['Anonymize'] ? 'Anonymous' : $('.nameBlock', post.nodes.info).textContent;
$.add(a, $.tn(" " + postInfo)); $.add(a, $.tn(" " + postInfo));
post.stub = $.el('div'); post.nodes.stub = $.el('div', {
$.add(post.stub, a); className: 'stub'
return $.before(post.nodes.root, post.stub); });
$.add(post.nodes.stub, a);
return $.prepend(post.nodes.root, post.nodes.stub);
}, },
show: function(post) { show: function(post) {
if (post.stub) { var quotelink, _i, _len, _ref;
$.rm(post.stub); if (post.nodes.stub) {
delete post.stub; $.rm(post.nodes.stub);
delete post.nodes.stub;
}
post.isHidden = false;
_ref = Get.allQuotelinksLinkingTo(post);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quotelink = _ref[_i];
$.rmClass(quotelink, 'filtered');
}
}
};
Recursive = {
toHide: [],
init: function() {
return Post.prototype.callbacks.push({
name: 'Recursive',
cb: this.node
});
},
node: function() {
var board, postID, quote, quotelink, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
if (this.isClone) {
return;
}
_ref = this.quotes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i];
if (__indexOf.call(Recursive.toHide, quote) >= 0) {
ReplyHiding.hide(this, !!g.posts[quote].nodes.stub, true);
}
}
_ref1 = this.nodes.quotelinks;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
quotelink = _ref1[_j];
_ref2 = Get.postDataFromLink(quotelink), board = _ref2.board, postID = _ref2.postID;
if ((_ref3 = g.posts["" + board + "." + postID]) != null ? _ref3.isHidden : void 0) {
$.addClass(quotelink, 'filtered');
}
}
},
hide: function(post, makeStub) {
var ID, fullID, quote, _i, _len, _ref, _ref1;
fullID = post.fullID;
Recursive.toHide.push(fullID);
_ref = g.posts;
for (ID in _ref) {
post = _ref[ID];
if (!post.isReply || post.isHidden) {
continue;
}
_ref1 = post.quotes;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
quote = _ref1[_i];
if (quote === fullID) {
ReplyHiding.hide(post, makeStub, true);
break;
}
}
} }
return post.nodes.root.hidden = post.isHidden = false;
} }
}; };
@ -1017,7 +1082,7 @@
to: function(data) { to: function(data) {
var board, url; var board, url;
board = data.board; board = data.board;
switch ("" + board) { switch (board) {
case 'a': case 'a':
case 'co': case 'co':
case 'jp': case 'jp':
@ -1283,13 +1348,12 @@
}; };
}, },
allQuotelinksLinkingTo: function(post) { allQuotelinksLinkingTo: function(post) {
var ID, fullID, quote, quotedPost, quotelinks, quoterPost, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; var ID, quote, quotedPost, quotelinks, quoterPost, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
quotelinks = []; quotelinks = [];
fullID = "" + post.board + "." + post;
_ref = g.posts; _ref = g.posts;
for (ID in _ref) { for (ID in _ref) {
quoterPost = _ref[ID]; quoterPost = _ref[ID];
if (-1 !== quoterPost.quotes.indexOf(fullID)) { if (-1 !== quoterPost.quotes.indexOf(post.fullID)) {
_ref1 = [quoterPost].concat(quoterPost.clones); _ref1 = [quoterPost].concat(quoterPost.clones);
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
quoterPost = _ref1[_i]; quoterPost = _ref1[_i];
@ -1301,7 +1365,9 @@
_ref2 = post.quotes; _ref2 = post.quotes;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
quote = _ref2[_j]; quote = _ref2[_j];
quotedPost = g.posts[quote]; if (!(quotedPost = g.posts[quote])) {
continue;
}
_ref3 = [quotedPost].concat(quotedPost.clones); _ref3 = [quotedPost].concat(quotedPost.clones);
for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) { for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) {
quotedPost = _ref3[_k]; quotedPost = _ref3[_k];
@ -1584,19 +1650,20 @@
} }
}, },
toggle: function(e) { toggle: function(e) {
var board, postID, threadID, _ref; var board, context, postID, threadID, _ref;
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) { if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
return; return;
} }
e.preventDefault(); e.preventDefault();
_ref = Get.postDataFromLink(this), board = _ref.board, threadID = _ref.threadID, postID = _ref.postID; _ref = Get.postDataFromLink(this), board = _ref.board, threadID = _ref.threadID, postID = _ref.postID;
context = Get.contextFromLink(this);
if ($.hasClass(this, 'inlined')) { if ($.hasClass(this, 'inlined')) {
QuoteInline.rm(this, board, threadID, postID); QuoteInline.rm(this, board, threadID, postID, context);
} else { } else {
if ($.x("ancestor::div[@id='p" + postID + "']", this)) { if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
return; return;
} }
QuoteInline.add(this, board, threadID, postID); QuoteInline.add(this, board, threadID, postID, context);
} }
return this.classList.toggle('inlined'); return this.classList.toggle('inlined');
}, },
@ -1607,28 +1674,27 @@
return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink); return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
} }
}, },
add: function(quotelink, board, threadID, postID) { add: function(quotelink, board, threadID, postID, context) {
var context, inline, isBacklink, post; var inline, isBacklink, post;
isBacklink = $.hasClass(quotelink, 'backlink'); isBacklink = $.hasClass(quotelink, 'backlink');
inline = $.el('div', { inline = $.el('div', {
id: "i" + postID, id: "i" + postID,
className: 'inline' className: 'inline'
}); });
context = Get.contextFromLink(quotelink);
$.after(QuoteInline.findRoot(quotelink, isBacklink), inline); $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
Get.postClone(board, threadID, postID, inline, context); Get.postClone(board, threadID, postID, inline, context);
if (context.thread !== g.threads["" + board + "." + threadID]) { if (!((post = g.posts["" + board + "." + postID]) && context.thread === post.thread)) {
return; return;
} }
post = g.posts["" + board + "." + postID];
if (isBacklink && Conf['Forward Hiding']) { if (isBacklink && Conf['Forward Hiding']) {
$.addClass(post.nodes.root, 'forwarded'); $.addClass(post.nodes.root, 'forwarded');
return post.forwarded++ || (post.forwarded = 1); return post.forwarded++ || (post.forwarded = 1);
} }
}, },
rm: function(quotelink, board, threadID, postID) { rm: function(quotelink, board, threadID, postID, context) {
var context, el, inline, post, root, _i, _len, _ref, _ref1; var el, inlined, isBacklink, post, root, _ref;
root = QuoteInline.findRoot(quotelink, $.hasClass(quotelink, 'backlink')); isBacklink = $.hasClass(quotelink, 'backlink');
root = QuoteInline.findRoot(quotelink, isBacklink);
root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root); root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
$.rm(root); $.rm(root);
if (!(el = root.firstElementChild)) { if (!(el = root.firstElementChild)) {
@ -1636,26 +1702,14 @@
} }
post = g.posts["" + board + "." + postID]; post = g.posts["" + board + "." + postID];
post.rmClone(el.dataset.clone); post.rmClone(el.dataset.clone);
context = Get.contextFromLink(quotelink); if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + board + "." + threadID] && !--post.forwarded) {
if (Conf['Forward Hiding'] && context.thread === g.threads["" + board + "." + threadID] && $.hasClass(quotelink, 'backlink') && !--post.forwarded) {
delete post.forwarded; delete post.forwarded;
$.rmClass(post.nodes.root, 'forwarded'); $.rmClass(post.nodes.root, 'forwarded');
} }
_ref = $$('.inlined', el); while (inlined = $('.inlined', el)) {
for (_i = 0, _len = _ref.length; _i < _len; _i++) { _ref = Get.postDataFromLink(inlined), board = _ref.board, threadID = _ref.threadID, postID = _ref.postID;
inline = _ref[_i]; QuoteInline.rm(inlined, board, threadID, postID, context);
_ref1 = Get.postDataFromLink(inline), board = _ref1.board, threadID = _ref1.threadID, postID = _ref1.postID; $.rmClass(inlined, 'inlined');
root = QuoteInline.findRoot(inline, $.hasClass(inline, 'backlink'));
root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
if (!(el = root.firstElementChild)) {
continue;
}
post = g.posts["" + board + "." + postID];
post.rmClone(el.dataset.clone);
if (Conf['Forward Hiding'] && context.thread === g.threads["" + board + "." + threadID] && $.hasClass(inline, 'backlink') && !--post.forwarded) {
delete post.forwarded;
$.rmClass(post.nodes.root, 'forwarded');
}
} }
} }
}; };
@ -1798,7 +1852,7 @@
if (!(Conf['OP Backlinks'] || this.isReply)) { if (!(Conf['OP Backlinks'] || this.isReply)) {
return; return;
} }
container = QuoteBacklink.getContainer("" + this.board + "." + this); container = QuoteBacklink.getContainer(this.fullID);
this.nodes.backlinkContainer = container; this.nodes.backlinkContainer = container;
return $.add(this.nodes.info, container); return $.add(this.nodes.info, container);
}, },
@ -1819,7 +1873,7 @@
}); });
}, },
node: function() { node: function() {
var board, op, postID, quote, quotelinks, quotes, thread, _i, _j, _len, _len1, _ref, _ref1; var board, op, postID, quote, quotelinks, quotes, _i, _j, _len, _len1, _ref;
if (this.isClone && this.thread === this.context.thread) { if (this.isClone && this.thread === this.context.thread) {
return; return;
} }
@ -1827,20 +1881,19 @@
return; return;
} }
quotelinks = this.nodes.quotelinks; quotelinks = this.nodes.quotelinks;
if (this.isClone && -1 < quotes.indexOf("" + this.board + "." + this.thread)) { if (this.isClone && -1 < quotes.indexOf(this.fullID)) {
for (_i = 0, _len = quotelinks.length; _i < _len; _i++) { for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
quote = quotelinks[_i]; quote = quotelinks[_i];
quote.textContent = quote.textContent.replace(QuoteOP.text, ''); quote.textContent = quote.textContent.replace(QuoteOP.text, '');
} }
} }
_ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread; op = (this.isClone ? this.context : this).thread.fullID;
op = "" + board + "." + thread;
if (!(-1 < quotes.indexOf(op))) { if (!(-1 < quotes.indexOf(op))) {
return; return;
} }
for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) { for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
quote = quotelinks[_j]; quote = quotelinks[_j];
_ref1 = Get.postDataFromLink(quote), board = _ref1.board, postID = _ref1.postID; _ref = Get.postDataFromLink(quote), board = _ref.board, postID = _ref.postID;
if (("" + board + "." + postID) === op) { if (("" + board + "." + postID) === op) {
$.add(quote, $.tn(QuoteOP.text)); $.add(quote, $.tn(QuoteOP.text));
} }
@ -2609,6 +2662,7 @@
function Thread(ID, board) { function Thread(ID, board) {
this.board = board; this.board = board;
this.ID = +ID; this.ID = +ID;
this.fullID = "" + this.board + "." + this.ID;
this.posts = {}; this.posts = {};
g.threads["" + board + "." + this] = board.threads[this] = this; g.threads["" + board + "." + this] = board.threads[this] = this;
} }
@ -2633,6 +2687,7 @@
that = {}; that = {};
} }
this.ID = +root.id.slice(2); this.ID = +root.id.slice(2);
this.fullID = "" + this.board + "." + this.ID;
post = $('.post', root); post = $('.post', root);
info = $('.postInfo', post); info = $('.postInfo', post);
this.nodes = { this.nodes = {
@ -2786,7 +2841,7 @@
var file, index, info, inline, inlined, key, nodes, post, quotelink, root, val, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _ref4; var file, index, info, inline, inlined, key, nodes, post, quotelink, root, val, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _ref4;
this.origin = origin; this.origin = origin;
this.context = context; this.context = context;
_ref = ['ID', 'board', 'thread', 'info', 'quotes', 'isReply']; _ref = ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
key = _ref[_i]; key = _ref[_i];
this[key] = origin[key]; this[key] = origin[key];
@ -2968,6 +3023,13 @@
settings.disableAll = true; settings.disableAll = true;
localStorage.setItem('4chan-settings', JSON.stringify(settings)); localStorage.setItem('4chan-settings', JSON.stringify(settings));
} }
if (Conf['Resurrect Quotes']) {
try {
Quotify.init();
} catch (err) {
$.log(err, 'Resurrect Quotes');
}
}
if (Conf['Thread Hiding']) { if (Conf['Thread Hiding']) {
try { try {
ThreadHiding.init(); ThreadHiding.init();
@ -2982,12 +3044,10 @@
$.log(err, 'Reply Hiding'); $.log(err, 'Reply Hiding');
} }
} }
if (Conf['Resurrect Quotes']) { try {
try { Recursive.init();
Quotify.init(); } catch (err) {
} catch (err) { $.log(err, 'Recursive');
$.log(err, 'Resurrect Quotes');
}
} }
if (Conf['Quote Inline']) { if (Conf['Quote Inline']) {
try { try {
@ -3134,14 +3194,15 @@
callback.cb.call(nodes[i]); callback.cb.call(nodes[i]);
} }
} catch (err) { } catch (err) {
$.log(callback.name, 'crashed. error:', err.message, nodes[i], err); $.log(callback.name, 'crashed. error:', err.message, nodes[i]);
$.log(err.stack);
} }
} }
}, },
settings: function() { settings: function() {
return alert('Here be settings'); return alert('Here be settings');
}, },
css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n\n/* fixed, z-index */\n#qp, #ihover,\n#updater, #stats,\n#boardNavDesktop.reply,\n#qr, #watcher {\n position: fixed;\n}\n#qp, #ihover {\n z-index: 100;\n}\n#updater, #stats {\n z-index: 90;\n}\n#boardNavDesktop.reply:hover {\n z-index: 80;\n}\n#qr {\n z-index: 50;\n}\n#watcher {\n z-index: 30;\n}\n#boardNavDesktop.reply {\n z-index: 10;\n}\n\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* thread updater */\n#updater {\n text-align: right;\n}\n#updater:not(:hover) {\n background: none;\n border: none;\n}\n#updater input[type=number] {\n width: 4em;\n}\n#updater:not(:hover) > div:not(.move) {\n display: none;\n}\n.new {\n color: limegreen;\n}\n\n/* quote */\n.quotelink.deadlink {\n text-decoration: underline !important;\n}\n.deadlink:not(.quotelink) {\n text-decoration: none !important;\n}\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.filtered {\n text-decoration: underline line-through;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n box-shadow: 0 0 0 2px rgba(216, 94, 49, .7);\n}\n\n/* file */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull {\n display: none;\n}\n#ihover {\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n max-height: 100%;\n max-width: 75%;\n padding-bottom: 16px;\n}\n\n/* thread hiding */\n.opContainer > .hide-thread-button {\n float: left;\n}\n\n/* reply hiding */\n.replyContainer > .hide-reply-button {\n float: left;\n margin-right: 2px;\n}" css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n[hidden] {\n display: none !important;\n}\n\n/* fixed, z-index */\n#qp, #ihover,\n#updater, #stats,\n#boardNavDesktop.reply,\n#qr, #watcher {\n position: fixed;\n}\n#qp, #ihover {\n z-index: 100;\n}\n#updater, #stats {\n z-index: 90;\n}\n#boardNavDesktop.reply:hover {\n z-index: 80;\n}\n#qr {\n z-index: 50;\n}\n#watcher {\n z-index: 30;\n}\n#boardNavDesktop.reply {\n z-index: 10;\n}\n\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* thread updater */\n#updater {\n text-align: right;\n}\n#updater:not(:hover) {\n background: none;\n border: none;\n}\n#updater input[type=number] {\n width: 4em;\n}\n#updater:not(:hover) > div:not(.move) {\n display: none;\n}\n.new {\n color: limegreen;\n}\n\n/* quote */\n.quotelink.deadlink {\n text-decoration: underline !important;\n}\n.deadlink:not(.quotelink) {\n text-decoration: none !important;\n}\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.filtered {\n text-decoration: underline line-through;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n box-shadow: 0 0 0 2px rgba(216, 94, 49, .7);\n}\n\n/* file */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull {\n display: none;\n}\n#ihover {\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n max-height: 100%;\n max-width: 75%;\n padding-bottom: 16px;\n}\n\n/* thread & reply hiding */\n.hide-thread-button,\n.hide-reply-button {\n float: left;\n margin-right: 2px;\n}\n.stub ~ .sideArrows,\n.stub ~ .hide-reply-button,\n.stub ~ .post {\n display: none !important;\n}"
}; };
Main.init(); Main.init();

View File

@ -24,6 +24,9 @@ a[href="javascript:;"] {
.post { .post {
overflow: visible !important; overflow: visible !important;
} }
[hidden] {
display: none !important;
}
/* fixed, z-index */ /* fixed, z-index */
#qp, #ihover, #qp, #ihover,
@ -160,13 +163,14 @@ body.fourchan_x {
padding-bottom: 16px; padding-bottom: 16px;
} }
/* thread hiding */ /* thread & reply hiding */
.opContainer > .hide-thread-button { .hide-thread-button,
float: left; .hide-reply-button {
}
/* reply hiding */
.replyContainer > .hide-reply-button {
float: left; float: left;
margin-right: 2px; margin-right: 2px;
} }
.stub ~ .sideArrows,
.stub ~ .hide-reply-button,
.stub ~ .post {
display: none !important;
}

View File

@ -14,7 +14,7 @@ Config =
Filtering: Filtering:
'Anonymize': [false, 'Turn everyone Anonymous.'] 'Anonymize': [false, 'Turn everyone Anonymous.']
'Filter': [true, 'Self-moderation placebo.'] 'Filter': [true, 'Self-moderation placebo.']
'Recursive Filtering': [true, 'Filter replies of filtered posts, recursively.'] 'Recursive Hiding': [true, 'Filter replies of filtered posts, recursively.']
'Reply Hiding': [true, 'Hide single replies.'] 'Reply Hiding': [true, 'Hide single replies.']
'Thread Hiding': [true, 'Hide entire threads.'] 'Thread Hiding': [true, 'Hide entire threads.']
'Stubs': [true, 'Make stubs of hidden threads / replies.'] 'Stubs': [true, 'Make stubs of hidden threads / replies.']

View File

@ -11,7 +11,7 @@ ThreadHiding =
node: -> node: ->
if @ID in ThreadHiding.hiddenThreads.threads if @ID in ThreadHiding.hiddenThreads.threads
ThreadHiding.hide @ ThreadHiding.hide @
$.prepend @posts[@].nodes.root, ThreadHiding.makeButton @, '-' $.prepend @posts[@].nodes.root, ThreadHiding.makeButton @, 'hide'
getHiddenThreads: -> getHiddenThreads: ->
hiddenThreads = $.get "hiddenThreads.#{g.BOARD}" hiddenThreads = $.get "hiddenThreads.#{g.BOARD}"
@ -47,10 +47,10 @@ ThreadHiding =
hiddenThreads.threads = threads hiddenThreads.threads = threads
$.set "hiddenThreads.#{g.BOARD}", hiddenThreads $.set "hiddenThreads.#{g.BOARD}", hiddenThreads
makeButton: (thread, sign) -> makeButton: (thread, type) ->
a = $.el 'a', a = $.el 'a',
className: 'hide-thread-button' className: "#{type}-thread-button"
innerHTML: "<span>[&nbsp;#{sign}&nbsp;]</span>&nbsp;" innerHTML: "<span>[&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;]</span>"
href: 'javascript:;' href: 'javascript:;'
$.on a, 'click', -> ThreadHiding.toggle thread $.on a, 'click', -> ThreadHiding.toggle thread
a a
@ -91,9 +91,10 @@ ThreadHiding =
else else
$('.nameBlock', op.nodes.info).textContent $('.nameBlock', op.nodes.info).textContent
a = ThreadHiding.makeButton thread, '+' a = ThreadHiding.makeButton thread, 'show'
$.add a, $.tn "#{opInfo} (#{numReplies})" $.add a, $.tn " #{opInfo} (#{numReplies})"
thread.stub = $.el 'div' thread.stub = $.el 'div',
className: 'stub'
$.add thread.stub, a $.add thread.stub, a
# if Conf['Menu'] # if Conf['Menu']
# $.add thread.stub, [$.tn(' '), Menu.makeButton()] # $.add thread.stub, [$.tn(' '), Menu.makeButton()]
@ -120,7 +121,7 @@ ReplyHiding =
if thread = ReplyHiding.hiddenPosts.threads[@thread] if thread = ReplyHiding.hiddenPosts.threads[@thread]
if @ID in thread if @ID in thread
ReplyHiding.hide @ ReplyHiding.hide @
$.replace $('.sideArrows', @nodes.root), ReplyHiding.makeButton @, '-' $.replace $('.sideArrows', @nodes.root), ReplyHiding.makeButton @, 'hide'
getHiddenPosts: -> getHiddenPosts: ->
hiddenPosts = $.get "hiddenPosts.#{g.BOARD}" hiddenPosts = $.get "hiddenPosts.#{g.BOARD}"
@ -151,10 +152,10 @@ ReplyHiding =
hiddenPosts.threads = threads hiddenPosts.threads = threads
$.set "hiddenPosts.#{g.BOARD}", hiddenPosts $.set "hiddenPosts.#{g.BOARD}", hiddenPosts
makeButton: (post, sign) -> makeButton: (post, type) ->
a = $.el 'a', a = $.el 'a',
className: 'hide-reply-button' className: "#{type}-reply-button"
innerHTML: "<span>[&nbsp;#{sign}&nbsp;]</span>" innerHTML: "<span>[&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;]</span>"
href: 'javascript:;' href: 'javascript:;'
$.on a, 'click', -> ReplyHiding.toggle post $.on a, 'click', -> ReplyHiding.toggle post
a a
@ -162,49 +163,86 @@ ReplyHiding =
toggle: (post) -> toggle: (post) ->
# Get fresh hidden posts. # Get fresh hidden posts.
hiddenPosts = ReplyHiding.getHiddenPosts() hiddenPosts = ReplyHiding.getHiddenPosts()
quotelinks = Get.allQuotelinksLinkingTo post
if post.isHidden if post.isHidden
ReplyHiding.show post ReplyHiding.show post
for quotelink in quotelinks
$.rmClass quotelink, 'filtered'
# XXX recursive filtering
thread = hiddenPosts.threads[post.thread] thread = hiddenPosts.threads[post.thread]
if thread.length is 1 if (index = thread.indexOf post.ID) > -1
delete hiddenPosts.threads[post.thread] # Was manually hidden, not by recursion/filtering.
else if thread.length is 1
thread.splice thread.indexOf(post.ID), 1 delete hiddenPosts.threads[post.thread]
else
thread.splice index, 1
else else
ReplyHiding.hide post ReplyHiding.hide post
for quotelink in quotelinks
$.addClass quotelink, 'filtered'
unless thread = hiddenPosts.threads[post.thread] unless thread = hiddenPosts.threads[post.thread]
thread = hiddenPosts.threads[post.thread] = [] thread = hiddenPosts.threads[post.thread] = []
thread.push post.ID thread.push post.ID
$.set "hiddenPosts.#{g.BOARD}", hiddenPosts $.set "hiddenPosts.#{g.BOARD}", hiddenPosts
hide: (post, makeStub=Conf['Stubs']) -> hide: (post, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) ->
return if post.isHidden return if post.isHidden
post.nodes.root.hidden = post.isHidden = true post.isHidden = true
Recursive.hide post, makeStub, true if hideRecursively
for quotelink in Get.allQuotelinksLinkingTo post
$.addClass quotelink, 'filtered'
return unless makeStub return unless makeStub
a = ReplyHiding.makeButton post, '+' a = ReplyHiding.makeButton post, 'show'
postInfo = postInfo =
if Conf['Anonymize'] if Conf['Anonymize']
'Anonymous' 'Anonymous'
else else
$('.nameBlock', post.nodes.info).textContent $('.nameBlock', post.nodes.info).textContent
$.add a, $.tn " #{postInfo}" $.add a, $.tn " #{postInfo}"
post.stub = $.el 'div' post.nodes.stub = $.el 'div',
$.add post.stub, a className: 'stub'
$.add post.nodes.stub, a
# if Conf['Menu'] # if Conf['Menu']
# $.add post.stub, [$.tn(' '), Menu.makeButton()] # $.add post.nodes.stub, [$.tn(' '), Menu.makeButton()]
$.before post.nodes.root, post.stub $.prepend post.nodes.root, post.nodes.stub
show: (post) -> show: (post) ->
if post.stub if post.nodes.stub
$.rm post.stub $.rm post.nodes.stub
delete post.stub delete post.nodes.stub
post.nodes.root.hidden = post.isHidden = false post.isHidden = false
for quotelink in Get.allQuotelinksLinkingTo post
$.rmClass quotelink, 'filtered'
return
Recursive =
toHide: []
init: ->
Post::callbacks.push
name: 'Recursive'
cb: @node
node: ->
return if @isClone
# In fetched posts:
# - Strike-through quotelinks
# - Hide recursively
for quote in @quotes
if quote in Recursive.toHide
ReplyHiding.hide @, !!g.posts[quote].nodes.stub, true
for quotelink in @nodes.quotelinks
{board, postID} = Get.postDataFromLink quotelink
if g.posts["#{board}.#{postID}"]?.isHidden
$.addClass quotelink, 'filtered'
return
hide: (post, makeStub) ->
{fullID} = post
Recursive.toHide.push fullID
for ID, post of g.posts
continue if !post.isReply or post.isHidden
for quote in post.quotes
if quote is fullID
ReplyHiding.hide post, makeStub, true
break
return
Redirect = Redirect =
image: (board, filename) -> image: (board, filename) ->
@ -239,7 +277,7 @@ Redirect =
# https://github.com/eksopl/fuuka/issues/27 # https://github.com/eksopl/fuuka/issues/27
to: (data) -> to: (data) ->
{board} = data {board} = data
switch "#{board}" switch board
when 'a', 'co', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'wsg', 'dev', 'foolz' when 'a', 'co', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'wsg', 'dev', 'foolz'
url = Redirect.path '//archive.foolz.us', 'foolfuuka', data url = Redirect.path '//archive.foolz.us', 'foolfuuka', data
when 'u', 'kuku' when 'u', 'kuku'
@ -579,13 +617,12 @@ Get =
allQuotelinksLinkingTo: (post) -> allQuotelinksLinkingTo: (post) ->
# Get quotelinks & backlinks linking to the given post. # Get quotelinks & backlinks linking to the given post.
quotelinks = [] quotelinks = []
fullID = "#{post.board}.#{post}"
# First: # First:
# In every posts, # In every posts,
# if it did quote this post, # if it did quote this post,
# get all their backlinks. # get all their backlinks.
for ID, quoterPost of g.posts for ID, quoterPost of g.posts
if -1 isnt quoterPost.quotes.indexOf fullID if -1 isnt quoterPost.quotes.indexOf post.fullID
for quoterPost in [quoterPost].concat quoterPost.clones for quoterPost in [quoterPost].concat quoterPost.clones
quotelinks.push.apply quotelinks, quoterPost.nodes.quotelinks quotelinks.push.apply quotelinks, quoterPost.nodes.quotelinks
# Second: # Second:
@ -595,7 +632,7 @@ Get =
# get all of their backlinks. # get all of their backlinks.
if Conf['Quote Backlinks'] if Conf['Quote Backlinks']
for quote in post.quotes for quote in post.quotes
quotedPost = g.posts[quote] continue unless quotedPost = g.posts[quote]
for quotedPost in [quotedPost].concat quotedPost.clones for quotedPost in [quotedPost].concat quotedPost.clones
quotelinks.push.apply quotelinks, Array::slice.call quotedPost.nodes.backlinks quotelinks.push.apply quotelinks, Array::slice.call quotedPost.nodes.backlinks
# Third: # Third:
@ -854,11 +891,12 @@ QuoteInline =
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
e.preventDefault() e.preventDefault()
{board, threadID, postID} = Get.postDataFromLink @ {board, threadID, postID} = Get.postDataFromLink @
context = Get.contextFromLink @
if $.hasClass @, 'inlined' if $.hasClass @, 'inlined'
QuoteInline.rm @, board, threadID, postID QuoteInline.rm @, board, threadID, postID, context
else else
return if $.x "ancestor::div[@id='p#{postID}']", @ return if $.x "ancestor::div[@id='p#{postID}']", @
QuoteInline.add @, board, threadID, postID QuoteInline.add @, board, threadID, postID, context
@classList.toggle 'inlined' @classList.toggle 'inlined'
findRoot: (quotelink, isBacklink) -> findRoot: (quotelink, isBacklink) ->
@ -866,17 +904,16 @@ QuoteInline =
quotelink.parentNode.parentNode quotelink.parentNode.parentNode
else else
$.x 'ancestor-or-self::*[parent::blockquote][1]', quotelink $.x 'ancestor-or-self::*[parent::blockquote][1]', quotelink
add: (quotelink, board, threadID, postID) -> add: (quotelink, board, threadID, postID, context) ->
isBacklink = $.hasClass quotelink, 'backlink' isBacklink = $.hasClass quotelink, 'backlink'
inline = $.el 'div', inline = $.el 'div',
id: "i#{postID}" id: "i#{postID}"
className: 'inline' className: 'inline'
context = Get.contextFromLink quotelink
$.after QuoteInline.findRoot(quotelink, isBacklink), inline $.after QuoteInline.findRoot(quotelink, isBacklink), inline
Get.postClone board, threadID, postID, inline, context Get.postClone board, threadID, postID, inline, context
return unless context.thread is g.threads["#{board}.#{threadID}"] return unless (post = g.posts["#{board}.#{postID}"]) and
post = g.posts["#{board}.#{postID}"] context.thread is post.thread
# Hide forward post if it's a backlink of a post in this thread. # Hide forward post if it's a backlink of a post in this thread.
# Will only unhide if there's no inlined backlinks of it anymore. # Will only unhide if there's no inlined backlinks of it anymore.
@ -890,9 +927,10 @@ QuoteInline =
# Unread.replies.splice i, 1 # Unread.replies.splice i, 1
# Unread.update true # Unread.update true
rm: (quotelink, board, threadID, postID) -> rm: (quotelink, board, threadID, postID, context) ->
isBacklink = $.hasClass quotelink, 'backlink'
# Select the corresponding inlined quote, and remove it. # Select the corresponding inlined quote, and remove it.
root = QuoteInline.findRoot quotelink, $.hasClass quotelink, 'backlink' root = QuoteInline.findRoot quotelink, isBacklink
root = $.x "following-sibling::div[@id='i#{postID}'][1]", root root = $.x "following-sibling::div[@id='i#{postID}'][1]", root
$.rm root $.rm root
@ -903,31 +941,19 @@ QuoteInline =
post = g.posts["#{board}.#{postID}"] post = g.posts["#{board}.#{postID}"]
post.rmClone el.dataset.clone post.rmClone el.dataset.clone
context = Get.contextFromLink quotelink
# Decrease forward count and unhide. # Decrease forward count and unhide.
if Conf['Forward Hiding'] and if Conf['Forward Hiding'] and
isBacklink and
context.thread is g.threads["#{board}.#{threadID}"] and context.thread is g.threads["#{board}.#{threadID}"] and
$.hasClass(quotelink, 'backlink') and
not --post.forwarded not --post.forwarded
delete post.forwarded delete post.forwarded
$.rmClass post.nodes.root, 'forwarded' $.rmClass post.nodes.root, 'forwarded'
# Repeat. # Repeat.
for inline in $$ '.inlined', el while inlined = $ '.inlined', el
{board, threadID, postID} = Get.postDataFromLink inline {board, threadID, postID} = Get.postDataFromLink inlined
root = QuoteInline.findRoot inline, $.hasClass inline, 'backlink' QuoteInline.rm inlined, board, threadID, postID, context
root = $.x "following-sibling::div[@id='i#{postID}'][1]", root $.rmClass inlined, 'inlined'
continue unless el = root.firstElementChild
post = g.posts["#{board}.#{postID}"]
post.rmClone el.dataset.clone
if Conf['Forward Hiding'] and
context.thread is g.threads["#{board}.#{threadID}"] and
$.hasClass(inline, 'backlink') and
not --post.forwarded
delete post.forwarded
$.rmClass post.nodes.root, 'forwarded'
return return
QuotePreview = QuotePreview =
@ -1032,7 +1058,7 @@ QuoteBacklink =
return return
# Don't backlink the OP. # Don't backlink the OP.
return unless Conf['OP Backlinks'] or @isReply return unless Conf['OP Backlinks'] or @isReply
container = QuoteBacklink.getContainer "#{@board}.#{@}" container = QuoteBacklink.getContainer @fullID
@nodes.backlinkContainer = container @nodes.backlinkContainer = container
$.add @nodes.info, container $.add @nodes.info, container
getContainer: (id) -> getContainer: (id) ->
@ -1054,12 +1080,11 @@ QuoteOP =
quotelinks = @nodes.quotelinks quotelinks = @nodes.quotelinks
# rm (OP) from cross-thread quotes. # rm (OP) from cross-thread quotes.
if @isClone and -1 < quotes.indexOf "#{@board}.#{@thread}" if @isClone and -1 < quotes.indexOf @fullID
for quote in quotelinks for quote in quotelinks
quote.textContent = quote.textContent.replace QuoteOP.text, '' quote.textContent = quote.textContent.replace QuoteOP.text, ''
{board, thread} = if @isClone then @context else @ op = (if @isClone then @context else @).thread.fullID
op = "#{board}.#{thread}"
# add (OP) to quotes quoting this context's OP. # add (OP) to quotes quoting this context's OP.
return unless -1 < quotes.indexOf op return unless -1 < quotes.indexOf op
for quote in quotelinks for quote in quotelinks

View File

@ -12,8 +12,9 @@ class Thread
toString: -> @ID toString: -> @ID
constructor: (ID, @board) -> constructor: (ID, @board) ->
@ID = +ID @ID = +ID
@posts = {} @fullID = "#{@board}.#{@ID}"
@posts = {}
# XXX Can't check when parsing single posts # XXX Can't check when parsing single posts
# move to Post constructor? unless @isReply # move to Post constructor? unless @isReply
@ -28,7 +29,8 @@ class Post
toString: -> @ID toString: -> @ID
constructor: (root, @thread, @board, that={}) -> constructor: (root, @thread, @board, that={}) ->
@ID = +root.id[2..] @ID = +root.id[2..]
@fullID = "#{@board}.#{@ID}"
post = $ '.post', root post = $ '.post', root
info = $ '.postInfo', post info = $ '.postInfo', post
@ -169,7 +171,7 @@ class Post
class Clone extends Post class Clone extends Post
constructor: (@origin, @context) -> constructor: (@origin, @context) ->
for key in ['ID', 'board', 'thread', 'info', 'quotes', 'isReply'] for key in ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply']
# Copy or point to the origin's key value. # Copy or point to the origin's key value.
@[key] = origin[key] @[key] = origin[key]
@ -313,6 +315,13 @@ Main =
settings.disableAll = true settings.disableAll = true
localStorage.setItem '4chan-settings', JSON.stringify settings localStorage.setItem '4chan-settings', JSON.stringify settings
if Conf['Resurrect Quotes']
try
Quotify.init()
catch err
# XXX handle error
$.log err, 'Resurrect Quotes'
if Conf['Thread Hiding'] if Conf['Thread Hiding']
try try
ThreadHiding.init() ThreadHiding.init()
@ -327,12 +336,11 @@ Main =
# XXX handle error # XXX handle error
$.log err, 'Reply Hiding' $.log err, 'Reply Hiding'
if Conf['Resurrect Quotes'] try
try Recursive.init()
Quotify.init() catch err
catch err # XXX handle error
# XXX handle error $.log err, 'Recursive'
$.log err, 'Resurrect Quotes'
if Conf['Quote Inline'] if Conf['Quote Inline']
try try
@ -466,7 +474,8 @@ Main =
callback.cb.call nodes[i] callback.cb.call nodes[i]
catch err catch err
# XXX handle error if notify # XXX handle error if notify
$.log callback.name, 'crashed. error:', err.message, nodes[i], err $.log callback.name, 'crashed. error:', err.message, nodes[i]
$.log err.stack
return return
settings: -> settings: ->