Merge branch 'master' into quotify

This commit is contained in:
Nicolas Stepien 2012-03-11 17:33:51 +01:00
commit e3fe3f6606
2 changed files with 326 additions and 412 deletions

View File

@ -73,7 +73,7 @@
*/ */
(function() { (function() {
var $, $$, Anonymize, AutoGif, DAY, DeadQuotes, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, GetTitle, HOUR, ImageExpand, ImageHover, Keybinds, MINUTE, Main, NAMESPACE, Nav, Options, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Redirect, ReplyHiding, ReportButton, RevealSpoilers, SECOND, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Threading, Time, TitlePost, Unread, Updater, VERSION, Watcher, conf, config, d, engine, flatten, g, key, log, qr, ui, val, _base; var $, $$, Anonymize, AutoGif, DAY, DeadQuotes, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, GetTitle, HOUR, ImageExpand, ImageHover, Keybinds, MINUTE, Main, NAMESPACE, Nav, Options, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Redirect, ReplyHiding, ReportButton, RevealSpoilers, SECOND, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Threading, Time, TitlePost, Unread, Updater, VERSION, Watcher, conf, config, d, engine, flatten, g, log, qr, ui, _base;
config = { config = {
main: { main: {
@ -387,7 +387,7 @@
return conf[this.name] = this.checked; return conf[this.name] = this.checked;
}, },
value: function() { value: function() {
$.set(this.name, this.value); $.set(this.name, this.value.trim());
return conf[this.name] = this.value; return conf[this.name] = this.value;
} }
}, },
@ -417,7 +417,7 @@
}, },
nodes: function(nodes) { nodes: function(nodes) {
var frag, node, _i, _len; var frag, node, _i, _len;
if (!(nodes instanceof Array)) return nodes; if (nodes instanceof Node) return nodes;
frag = d.createDocumentFragment(); frag = d.createDocumentFragment();
for (_i = 0, _len = nodes.length; _i < _len; _i++) { for (_i = 0, _len = nodes.length; _i < _len; _i++) {
node = nodes[_i]; node = nodes[_i];
@ -535,11 +535,6 @@
} }
}); });
for (key in conf) {
val = conf[key];
conf[key] = $.get(key, val);
}
$$ = function(selector, root) { $$ = function(selector, root) {
if (root == null) root = d.body; if (root == null) root = d.body;
return Array.prototype.slice.call(root.querySelectorAll(selector)); return Array.prototype.slice.call(root.querySelectorAll(selector));
@ -611,12 +606,12 @@
if (result === true) { if (result === true) {
if (isOP) { if (isOP) {
if (!g.REPLY) { if (!g.REPLY) {
ThreadHiding.hideHide(post.el.parentNode); ThreadHiding.hide(post.el.parentNode);
} else { } else {
continue; continue;
} }
} else { } else {
ReplyHiding.hideHide(post.el); ReplyHiding.hide(post.root);
} }
return; return;
} }
@ -715,7 +710,7 @@
quote = _ref[_i]; quote = _ref[_i];
if ((el = $.id(quote.hash.slice(1))) && el.parentNode.parentNode.parentNode.hidden) { if ((el = $.id(quote.hash.slice(1))) && el.parentNode.parentNode.parentNode.hidden) {
$.addClass(quote, 'filtered'); $.addClass(quote, 'filtered');
if (conf['Recursive Filtering']) post.root.hidden = true; if (conf['Recursive Filtering']) ReplyHiding.hide(post.root);
} }
} }
} }
@ -742,34 +737,22 @@
})); }));
}, },
parse: function(req, a, threadID, replyID) { parse: function(req, a, threadID, replyID) {
var body, bq, post, quote, quotes, reply, _i, _j, _len, _len2, _ref; var bq, doc, post, quote, quotes, _i, _len;
if (req.status !== 200) { if (req.status !== 200) {
a.textContent = "" + req.status + " " + req.statusText; a.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
body = $.el('body', { doc = d.implementation.createHTMLDocument(null);
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText;
}); bq = threadID === replyID ? $('blockquote', doc) : $('blockquote', doc.getElementById(replyID));
if (threadID === replyID) { $.replace(a.parentNode.parentNode, bq);
bq = $('blockquote', body);
} else {
_ref = $$('td[id]', body);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref[_i];
if (reply.id === replyID) {
bq = $('blockquote', reply);
break;
}
}
}
quotes = $$('.quotelink', bq); quotes = $$('.quotelink', bq);
for (_j = 0, _len2 = quotes.length; _j < _len2; _j++) { for (_i = 0, _len = quotes.length; _i < _len; _i++) {
quote = quotes[_j]; quote = quotes[_i];
if (quote.getAttribute('href') === quote.hash) { if (quote.getAttribute('href') === quote.hash) {
quote.pathname = "/" + g.BOARD + "/res/" + threadID; quote.pathname = "/" + g.BOARD + "/res/" + threadID;
} }
} }
$.replace(a.parentNode.parentNode, bq);
post = { post = {
threadId: threadID, threadId: threadID,
quotes: quotes, quotes: quotes,
@ -890,76 +873,61 @@
ReplyHiding = { ReplyHiding = {
init: function() { init: function() {
this.a = $.el('a', { this.td = $.el('td', {
textContent: '[ - ]', noWrap: true,
href: 'javascript:;' className: 'replyhider',
innerHTML: '<a href="javascript:;">[ - ]</a>'
}); });
return g.callbacks.push(this.node); return g.callbacks.push(this.node);
}, },
node: function(post) { node: function(post) {
var a, dd; var td;
if (post["class"]) return; if (post["class"]) return;
dd = post.el.previousSibling; td = ReplyHiding.td.cloneNode(true);
dd.className = 'replyhider'; $.on(td.firstChild, 'click', ReplyHiding.toggle);
a = ReplyHiding.a.cloneNode(true); $.replace(post.el.previousSibling, td);
$.on(a, 'click', ReplyHiding.cb.hide); if (post.id in g.hiddenReplies) return ReplyHiding.hide(post.root);
$.replace(dd.firstChild, a);
if (post.id in g.hiddenReplies) return ReplyHiding.hide(post.el);
}, },
cb: { toggle: function() {
hide: function() { var id, parent, quote, table, _i, _j, _len, _len2, _ref, _ref2;
var reply; parent = this.parentNode;
reply = this.parentNode.nextSibling; if (parent.className === 'replyhider') {
return ReplyHiding.hide(reply); ReplyHiding.hide(parent.parentNode.parentNode.parentNode);
}, id = parent.nextSibling.id;
show: function() { _ref = $$(".quotelink[href='#" + id + "'], .backlink[href='#" + id + "']");
var div, table; for (_i = 0, _len = _ref.length; _i < _len; _i++) {
div = this.parentNode; quote = _ref[_i];
table = div.nextSibling; $.addClass(quote, 'filtered');
ReplyHiding.show(table); }
return $.rm(div); g.hiddenReplies[id] = Date.now();
} else {
table = parent.nextSibling;
table.hidden = false;
$.rm(parent);
id = table.firstChild.firstChild.lastChild.id;
_ref2 = $$(".quotelink[href='#" + id + "'], .backlink[href='#" + id + "']");
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
quote = _ref2[_j];
$.removeClass(quote, 'filtered');
}
delete g.hiddenReplies[id];
} }
},
hide: function(reply) {
var id, quote, _i, _len, _ref;
ReplyHiding.hideHide(reply);
id = reply.id;
_ref = $$(".quotelink[href='#" + id + "'], .backlink[href='#" + id + "']");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i];
$.addClass(quote, 'filtered');
}
g.hiddenReplies[id] = Date.now();
return $.set("hiddenReplies/" + g.BOARD + "/", g.hiddenReplies); return $.set("hiddenReplies/" + g.BOARD + "/", g.hiddenReplies);
}, },
hideHide: function(reply) { hide: function(table) {
var div, name, table, trip, uid, _ref, _ref2; var div, name, trip, uid, _ref, _ref2;
table = reply.parentNode.parentNode.parentNode;
if (table.hidden) return; if (table.hidden) return;
table.hidden = true; table.hidden = true;
if (conf['Show Stubs']) { if (!conf['Show Stubs']) return;
name = $('.commentpostername', reply).textContent; name = $('td[id] > .commentpostername', table).textContent;
uid = ((_ref = $('.posteruid', reply)) != null ? _ref.textContent : void 0) || ''; uid = ((_ref = $('td[id] > .posteruid', table)) != null ? _ref.textContent : void 0) || '';
trip = ((_ref2 = $('.postertrip', reply)) != null ? _ref2.textContent : void 0) || ''; trip = ((_ref2 = $('td[id] > .postertrip', table)) != null ? _ref2.textContent : void 0) || '';
div = $.el('div', { div = $.el('div', {
className: 'stub', className: 'stub',
innerHTML: "<a href=javascript:;><span>[ + ]</span> " + name + " " + uid + " " + trip + "</a>" innerHTML: "<a href=javascript:;><span>[ + ]</span> " + name + " " + uid + " " + trip + "</a>"
}); });
$.on($('a', div), 'click', ReplyHiding.cb.show); $.on(div.firstChild, 'click', ReplyHiding.toggle);
return $.before(table, div); return $.before(table, div);
}
},
show: function(table) {
var id, quote, _i, _len, _ref;
table.hidden = false;
id = $('td[id]', table).id;
_ref = $$(".quotelink[href='#" + id + "'], .backlink[href='#" + id + "']");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i];
$.removeClass(quote, 'filtered');
}
delete g.hiddenReplies[id];
return $.set("hiddenReplies/" + g.BOARD + "/", g.hiddenReplies);
} }
}; };
@ -974,7 +942,7 @@
return $.on(d, 'keydown', Keybinds.keydown); return $.on(d, 'keydown', Keybinds.keydown);
}, },
keydown: function(e) { keydown: function(e) {
var o, range, selEnd, selStart, ta, thread, value, _ref, _ref2; var key, o, range, selEnd, selStart, ta, thread, value, _ref, _ref2;
if (!(key = Keybinds.keyCode(e)) || /TEXTAREA|INPUT/.test(e.target.nodeName) && !(e.altKey || e.ctrlKey || e.keyCode === 27)) { if (!(key = Keybinds.keyCode(e)) || /TEXTAREA|INPUT/.test(e.target.nodeName) && !(e.altKey || e.ctrlKey || e.keyCode === 27)) {
return; return;
} }
@ -1058,7 +1026,7 @@
Keybinds.hl(-1, thread); Keybinds.hl(-1, thread);
break; break;
case conf.hide: case conf.hide:
ThreadHiding.toggle(thread); if (/\bthread\b/.test(thread.className)) ThreadHiding.toggle(thread);
break; break;
default: default:
return; return;
@ -1066,7 +1034,7 @@
return e.preventDefault(); return e.preventDefault();
}, },
keyCode: function(e) { keyCode: function(e) {
var c, kc; var c, kc, key;
key = (function() { key = (function() {
switch (kc = e.keyCode) { switch (kc = e.keyCode) {
case 8: case 8:
@ -1265,20 +1233,24 @@
qr = { qr = {
init: function() { init: function() {
var form, iframe, link, loadChecking;
if (!$.id('recaptcha_challenge_field_holder')) return; if (!$.id('recaptcha_challenge_field_holder')) return;
g.callbacks.push(this.node);
return setTimeout(this.asyncInit);
},
asyncInit: function() {
var form, iframe, link, loadChecking, script;
if (conf['Hide Original Post Form']) { if (conf['Hide Original Post Form']) {
link = $.el('h1', { link = $.el('h1', {
innerHTML: "<a href=javascript:;>" + (g.REPLY ? 'Quick Reply' : 'New Thread') + "</a>" innerHTML: "<a href=javascript:;>" + (g.REPLY ? 'Quick Reply' : 'New Thread') + "</a>"
}); });
$.on($('a', link), 'click', function() { $.on($('a', link), 'click', function() {
qr.open(); qr.open();
if (!g.REPLY) $('select', qr.el).value = 'new';
return $('textarea', qr.el).focus(); return $('textarea', qr.el).focus();
}); });
form = d.forms[0]; form = d.forms[0];
$.before(form, link); $.before(form, link);
} }
g.callbacks.push(this.node);
if (/chrome/i.test(navigator.userAgent)) { if (/chrome/i.test(navigator.userAgent)) {
qr.status({ qr.status({
ready: true ready: true
@ -1306,19 +1278,14 @@
}); });
$.add(d.head, iframe); $.add(d.head, iframe);
} }
setTimeout(function() { script = $.el('script', {
var script; textContent: 'Recaptcha.focus_response_field=function(){}'
script = $.el('script', {
textContent: 'Recaptcha.focus_response_field=function(){}'
});
$.add(d.head, script);
return $.rm(script);
}); });
$.add(d.head, script);
$.rm(script);
if (conf['Persistent QR']) { if (conf['Persistent QR']) {
setTimeout(function() { qr.dialog();
qr.dialog(); if (conf['Auto Hide QR']) qr.hide();
if (conf['Auto Hide QR']) return qr.hide();
});
} }
$.on(d, 'dragover', qr.dragOver); $.on(d, 'dragover', qr.dragOver);
$.on(d, 'drop', qr.dropFile); $.on(d, 'drop', qr.dropFile);
@ -2374,6 +2341,7 @@
return g.hiddenReplies = {}; return g.hiddenReplies = {};
}, },
keybind: function(e) { keybind: function(e) {
var key;
if (e.keyCode === 9) return; if (e.keyCode === 9) return;
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -2451,10 +2419,9 @@
ThreadHiding = { ThreadHiding = {
init: function() { init: function() {
var a, hiddenThreads, op, thread, _i, _len, _ref, _results; var a, hiddenThreads, op, thread, _i, _len, _ref;
hiddenThreads = $.get("hiddenThreads/" + g.BOARD + "/", {}); hiddenThreads = $.get("hiddenThreads/" + g.BOARD + "/", {});
_ref = $$('.thread'); _ref = $$('.thread');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
thread = _ref[_i]; thread = _ref[_i];
op = thread.firstChild; op = thread.firstChild;
@ -2462,83 +2429,60 @@
textContent: '[ - ]', textContent: '[ - ]',
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(a, 'click', ThreadHiding.cb.hide); $.on(a, 'click', ThreadHiding.cb);
$.prepend(op, a); $.prepend(op, a);
if (op.id in hiddenThreads) { if (op.id in hiddenThreads) ThreadHiding.hide(thread);
_results.push(ThreadHiding.hideHide(thread));
} else {
_results.push(void 0);
}
} }
return _results;
}, },
cb: { cb: function() {
hide: function() { return ThreadHiding.toggle(this.parentNode.parentNode);
var thread;
thread = this.parentNode.parentNode;
return ThreadHiding.hide(thread);
},
show: function() {
var thread;
thread = this.parentNode.parentNode;
return ThreadHiding.show(thread);
}
}, },
toggle: function(thread) { toggle: function(thread) {
if (/\bstub\b/.test(thread.className) || thread.hidden) { var hiddenThreads, id;
return ThreadHiding.show(thread); hiddenThreads = $.get("hiddenThreads/" + g.BOARD + "/", {});
id = $('.op', thread).id;
if (thread.hidden || thread.firstChild.className === 'block') {
ThreadHiding.show(thread);
delete hiddenThreads[id];
} else { } else {
return ThreadHiding.hide(thread); ThreadHiding.hide(thread);
hiddenThreads[id] = Date.now();
} }
return $.set("hiddenThreads/" + g.BOARD + "/", hiddenThreads);
}, },
hide: function(thread) { hide: function(thread) {
var hiddenThreads, id; var a, div, name, num, op, span, text, trip, uid, _ref, _ref2;
ThreadHiding.hideHide(thread); if (!conf['Show Stubs']) {
id = thread.firstChild.id;
hiddenThreads = $.get("hiddenThreads/" + g.BOARD + "/", {});
hiddenThreads[id] = Date.now();
return $.set("hiddenThreads/" + g.BOARD + "/", hiddenThreads);
},
hideHide: function(thread) {
var a, div, name, num, span, text, trip, uid, _ref, _ref2;
if (conf['Show Stubs']) {
if (/stub/.test(thread.className)) return;
if (span = $('.omittedposts', thread)) {
num = Number(span.textContent.match(/\d+/)[0]);
} else {
num = 0;
}
num += $$('table', thread).length;
text = num === 1 ? "1 reply" : "" + num + " replies";
name = $('.postername', thread).textContent;
uid = ((_ref = $('.posteruid', thread)) != null ? _ref.textContent : void 0) || '';
trip = ((_ref2 = $('.postername + .postertrip', thread)) != null ? _ref2.textContent : void 0) || '';
a = $.el('a', {
innerHTML: "<span>[ + ]</span> " + name + uid + trip + " (" + text + ")",
href: 'javascript:;'
});
$.on(a, 'click', ThreadHiding.cb.show);
div = $.el('div', {
className: 'block'
});
$.add(div, a);
$.add(thread, div);
return $.addClass(thread, 'stub');
} else {
thread.hidden = true; thread.hidden = true;
return thread.nextSibling.hidden = true; thread.nextSibling.hidden = true;
return;
} }
if (thread.firstChild.className === 'block') return;
num = 0;
if (span = $('.omittedposts', thread)) {
num = Number(span.textContent.match(/\d+/)[0]);
}
num += $$('.op ~ table', thread).length;
text = num === 1 ? '1 reply' : "" + num + " replies";
op = $('.op', thread);
name = $('.postername', op).textContent;
uid = ((_ref = $('.posteruid', op)) != null ? _ref.textContent : void 0) || '';
trip = ((_ref2 = $('.postertrip', op)) != null ? _ref2.textContent : void 0) || '';
a = $.el('a', {
innerHTML: "<span>[ + ]</span> " + name + " " + uid + " " + trip + " (" + text + ")",
href: 'javascript:;'
});
$.on(a, 'click', ThreadHiding.cb);
div = $.el('div', {
className: 'block'
});
$.add(div, a);
return $.prepend(thread, div);
}, },
show: function(thread) { show: function(thread, id) {
var hiddenThreads, id; $.rm($('.block', thread));
$.rm($('div.block', thread));
$.removeClass(thread, 'stub');
thread.hidden = false; thread.hidden = false;
thread.nextSibling.hidden = false; return thread.nextSibling.hidden = false;
id = thread.firstChild.id;
hiddenThreads = $.get("hiddenThreads/" + g.BOARD + "/", {});
delete hiddenThreads[id];
return $.set("hiddenThreads/" + g.BOARD + "/", hiddenThreads);
} }
}; };
@ -2616,7 +2560,7 @@
}; };
}, },
update: function() { update: function() {
var body, id, newPosts, nodes, reply, scroll, _i, _len, _ref, _ref2; var body, id, newPosts, nodes, reply, scroll, _i, _len, _ref;
if (this.status === 404) { if (this.status === 404) {
Updater.timer.textContent = ''; Updater.timer.textContent = '';
Updater.count.textContent = 404; Updater.count.textContent = 404;
@ -2655,23 +2599,19 @@
body = $.el('body', { body = $.el('body', {
innerHTML: this.responseText innerHTML: this.responseText
}); });
id = ((_ref = $('td[id]', Updater.br.previousElementSibling)) != null ? _ref.id : void 0) || 0; id = $('input', Updater.br.previousElementSibling).name;
nodes = []; nodes = [];
_ref2 = $$('.reply', body).reverse(); _ref = $$('.reply', body).reverse();
for (_i = 0, _len = _ref2.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref2[_i]; reply = _ref[_i];
if (reply.id <= id) break; if (reply.id <= id) break;
nodes.push(reply.parentNode.parentNode.parentNode); nodes.push(reply.parentNode.parentNode.parentNode);
} }
newPosts = nodes.length; newPosts = nodes.length;
scroll = conf['Scrolling'] && Updater.scrollBG() && newPosts && Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25; scroll = conf['Scrolling'] && Updater.scrollBG() && newPosts && Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25;
if (conf['Verbose']) { if (conf['Verbose']) {
Updater.count.textContent = '+' + newPosts; Updater.count.textContent = "+" + newPosts;
if (newPosts === 0) { Updater.count.className = newPosts ? 'new' : null;
Updater.count.className = null;
} else {
Updater.count.className = 'new';
}
} }
$.before(Updater.br, nodes.reverse()); $.before(Updater.br, nodes.reverse());
if (scroll) return Updater.br.previousSibling.scrollIntoView(); if (scroll) return Updater.br.previousSibling.scrollIntoView();
@ -3247,32 +3187,19 @@
} }
}, },
parse: function(req, pathname, id, threadID, inline) { parse: function(req, pathname, id, threadID, inline) {
var body, href, html, link, newInline, op, quote, reply, _i, _j, _len, _len2, _ref, _ref2; var doc, href, link, newInline, node, quote, _i, _len, _ref;
if (!inline.parentNode) return; if (!inline.parentNode) return;
if (req.status !== 200) { if (req.status !== 200) {
inline.textContent = "" + req.status + " " + req.statusText; inline.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
body = $.el('body', { doc = d.implementation.createHTMLDocument(null);
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText;
}); node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
if (id === threadID) { newInline = QuoteInline.table(id, node.innerHTML);
op = Threading.op($('body > form', body).firstChild); _ref = $$('.quotelink', newInline);
html = op.innerHTML; for (_i = 0, _len = _ref.length; _i < _len; _i++) {
} else { quote = _ref[_i];
_ref = $$('.reply', body);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref[_i];
if (reply.id === id) {
html = reply.innerHTML;
break;
}
}
}
newInline = QuoteInline.table(id, html);
_ref2 = $$('.quotelink', newInline);
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
quote = _ref2[_j];
if ((href = quote.getAttribute('href')) === quote.hash) { if ((href = quote.getAttribute('href')) === quote.hash) {
quote.pathname = pathname; quote.pathname = pathname;
} else if (!g.REPLY && href !== quote.href) { } else if (!g.REPLY && href !== quote.href) {
@ -3352,29 +3279,16 @@
return $.off(this, 'click', QuotePreview.mouseout); return $.off(this, 'click', QuotePreview.mouseout);
}, },
parse: function(req, id, threadID) { parse: function(req, id, threadID) {
var body, html, op, post, qp, reply, _i, _len, _ref; var doc, node, post, qp;
if (!((qp = ui.el) && (qp.innerHTML === ("Loading " + id + "...")))) return; if (!((qp = ui.el) && qp.textContent === ("Loading " + id + "..."))) return;
if (req.status !== 200) { if (req.status !== 200) {
qp.textContent = "" + req.status + " " + req.statusText; qp.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
body = $.el('body', { doc = d.implementation.createHTMLDocument(null);
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText;
}); node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
if (id === threadID) { qp.innerHTML = node.innerHTML;
op = Threading.op($('body > form', body).firstChild);
html = op.innerHTML;
} else {
_ref = $$('.reply', body);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref[_i];
if (reply.id === id) {
html = reply.innerHTML;
break;
}
}
}
qp.innerHTML = html;
post = { post = {
root: qp, root: qp,
filesize: $('.filesize', qp), filesize: $('.filesize', qp),
@ -3865,7 +3779,7 @@
Main = { Main = {
init: function() { init: function() {
var cutoff, hiddenThreads, id, now, path, pathname, temp, timestamp, _ref; var cutoff, hiddenThreads, id, key, now, path, pathname, temp, timestamp, val, _ref;
path = location.pathname; path = location.pathname;
pathname = path.slice(1).split('/'); pathname = path.slice(1).split('/');
g.BOARD = pathname[0], temp = pathname[1]; g.BOARD = pathname[0], temp = pathname[1];
@ -3875,6 +3789,10 @@
} else { } else {
g.PAGENUM = parseInt(temp) || 0; g.PAGENUM = parseInt(temp) || 0;
} }
for (key in conf) {
val = conf[key];
conf[key] = $.get(key, val);
}
$.on(window, 'message', Main.message); $.on(window, 'message', Main.message);
switch (location.hostname) { switch (location.hostname) {
case 'sys.4chan.org': case 'sys.4chan.org':
@ -3977,19 +3895,51 @@
Favicon.init(); Favicon.init();
if (conf['Quick Reply']) qr.init(); if (conf['Quick Reply']) qr.init();
if (conf['Image Expansion']) ImageExpand.init(); if (conf['Image Expansion']) ImageExpand.init();
if (conf['Thread Watcher']) Watcher.init(); if (conf['Thread Watcher']) {
if (conf['Keybinds']) Keybinds.init(); setTimeout(function() {
return Watcher.init();
});
}
if (conf['Keybinds']) {
setTimeout(function() {
return Keybinds.init();
});
}
if (g.REPLY) { if (g.REPLY) {
if (conf['Thread Updater']) Updater.init(); if (conf['Thread Updater']) {
setTimeout(function() {
return Updater.init();
});
}
if (conf['Thread Stats']) ThreadStats.init(); if (conf['Thread Stats']) ThreadStats.init();
if (conf['Reply Navigation']) Nav.init(); if (conf['Reply Navigation']) {
setTimeout(function() {
return Nav.init();
});
}
if (conf['Post in Title']) TitlePost.init(); if (conf['Post in Title']) TitlePost.init();
if (conf['Unread Count'] || conf['Unread Favicon']) Unread.init(); if (conf['Unread Count'] || conf['Unread Favicon']) Unread.init();
} else { } else {
if (conf['Thread Hiding']) ThreadHiding.init(); if (conf['Thread Hiding']) {
if (conf['Thread Expansion']) ExpandThread.init(); setTimeout(function() {
if (conf['Comment Expansion']) ExpandComment.init(); return ThreadHiding.init();
if (conf['Index Navigation']) Nav.init(); });
}
if (conf['Thread Expansion']) {
setTimeout(function() {
return ExpandThread.init();
});
}
if (conf['Comment Expansion']) {
setTimeout(function() {
return ExpandComment.init();
});
}
if (conf['Index Navigation']) {
setTimeout(function() {
return Nav.init();
});
}
} }
nodes = []; nodes = [];
_ref2 = $$('.op, a + table', form); _ref2 = $$('.op, a + table', form);
@ -4036,7 +3986,7 @@
el: klass === 'op' ? node : node.firstChild.firstChild.lastChild, el: klass === 'op' ? node : node.firstChild.firstChild.lastChild,
"class": klass, "class": klass,
id: node.getElementsByTagName('input')[0].name, id: node.getElementsByTagName('input')[0].name,
threadId: g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id, threadId: g.THREAD_ID || $.x('ancestor::div[@class="thread"]', node).firstChild.id,
isOP: klass === 'op', isOP: klass === 'op',
isInlined: /\binline\b/.test(klass), isInlined: /\binline\b/.test(klass),
filesize: node.getElementsByClassName('filesize')[0] || false, filesize: node.getElementsByClassName('filesize')[0] || false,
@ -4058,7 +4008,7 @@
} }
} catch (err) { } catch (err) {
if (notify) { if (notify) {
alert("4chan X error: " + err.message + "\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n" + err.stack); alert("4chan X (" + VERSION + ") error: " + err.message + "\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n" + err.stack);
} }
} }
} }
@ -4096,7 +4046,9 @@ a[href="javascript:;"] {\
text-decoration: none;\ text-decoration: none;\
}\ }\
\ \
.thread.stub > :not(.block),\ .block ~ .op,\
.block ~ .omittedposts,\
.block ~ table,\
#content > [name=tab]:not(:checked) + div,\ #content > [name=tab]:not(:checked) + div,\
#updater:not(:hover) > :not(.move),\ #updater:not(:hover) > :not(.move),\
#qp > input, #qp .inline, .forwarded {\ #qp > input, #qp .inline, .forwarded {\

View File

@ -314,7 +314,7 @@ $.extend $,
$.set @name, @checked $.set @name, @checked
conf[@name] = @checked conf[@name] = @checked
value: -> value: ->
$.set @name, @value $.set @name, @value.trim()
conf[@name] = @value conf[@name] = @value
addStyle: (css) -> addStyle: (css) ->
style = $.el 'style', style = $.el 'style',
@ -334,7 +334,7 @@ $.extend $,
tn: (s) -> tn: (s) ->
d.createTextNode s d.createTextNode s
nodes: (nodes) -> nodes: (nodes) ->
unless nodes instanceof Array if nodes instanceof Node
return nodes return nodes
frag = d.createDocumentFragment() frag = d.createDocumentFragment()
for node in nodes for node in nodes
@ -450,10 +450,6 @@ $.extend $,
name = NAMESPACE + name name = NAMESPACE + name
localStorage[name] = JSON.stringify value localStorage[name] = JSON.stringify value
#load values from localStorage
for key, val of conf
conf[key] = $.get key, val
$$ = (selector, root=d.body) -> $$ = (selector, root=d.body) ->
Array::slice.call root.querySelectorAll selector Array::slice.call root.querySelectorAll selector
@ -545,11 +541,11 @@ Filter =
if result is true if result is true
if isOP if isOP
unless g.REPLY unless g.REPLY
ThreadHiding.hideHide post.el.parentNode ThreadHiding.hide post.el.parentNode
else else
continue continue
else else
ReplyHiding.hideHide post.el ReplyHiding.hide post.root
return return
# Highlight # Highlight
@ -622,7 +618,7 @@ StrikethroughQuotes =
for quote in post.quotes for quote in post.quotes
if (el = $.id quote.hash[1..]) and el.parentNode.parentNode.parentNode.hidden if (el = $.id quote.hash[1..]) and el.parentNode.parentNode.parentNode.hidden
$.addClass quote, 'filtered' $.addClass quote, 'filtered'
post.root.hidden = true if conf['Recursive Filtering'] ReplyHiding.hide post.root if conf['Recursive Filtering']
return return
ExpandComment = ExpandComment =
@ -642,23 +638,19 @@ ExpandComment =
a.textContent = "#{req.status} #{req.statusText}" a.textContent = "#{req.status} #{req.statusText}"
return return
body = $.el 'body', doc = d.implementation.createHTMLDocument null
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText
if threadID is replyID #OP bq =
bq = $ 'blockquote', body if threadID is replyID # OP
else $ 'blockquote', doc
#css selectors don't like ids starting with numbers, else
# getElementById only works for root document. $ 'blockquote', doc.getElementById replyID
for reply in $$ 'td[id]', body $.replace a.parentNode.parentNode, bq
if reply.id == replyID
bq = $ 'blockquote', reply
break
quotes = $$ '.quotelink', bq quotes = $$ '.quotelink', bq
for quote in quotes for quote in quotes
if quote.getAttribute('href') is quote.hash if quote.getAttribute('href') is quote.hash
quote.pathname = "/#{g.BOARD}/res/#{threadID}" quote.pathname = "/#{g.BOARD}/res/#{threadID}"
$.replace a.parentNode.parentNode, bq
post = post =
threadId: threadID threadId: threadID
quotes: quotes quotes: quotes
@ -749,70 +741,55 @@ ExpandThread =
ReplyHiding = ReplyHiding =
init: -> init: ->
@a = $.el 'a', @td = $.el 'td',
textContent: '[ - ]' noWrap: true
href: 'javascript:;' className: 'replyhider'
innerHTML: '<a href="javascript:;">[ - ]</a>'
g.callbacks.push @node g.callbacks.push @node
node: (post) -> node: (post) ->
return if post.class return if post.class
dd = post.el.previousSibling td = ReplyHiding.td.cloneNode true
dd.className = 'replyhider' $.on td.firstChild, 'click', ReplyHiding.toggle
a = ReplyHiding.a.cloneNode true $.replace post.el.previousSibling, td
$.on a, 'click', ReplyHiding.cb.hide
$.replace dd.firstChild, a
if post.id of g.hiddenReplies if post.id of g.hiddenReplies
ReplyHiding.hide post.el ReplyHiding.hide post.root
cb: toggle: ->
hide: -> parent = @parentNode
reply = @parentNode.nextSibling if parent.className is 'replyhider'
ReplyHiding.hide reply ReplyHiding.hide parent.parentNode.parentNode.parentNode
id = parent.nextSibling.id
show: -> for quote in $$ ".quotelink[href='##{id}'], .backlink[href='##{id}']"
div = @parentNode $.addClass quote, 'filtered'
table = div.nextSibling g.hiddenReplies[id] = Date.now()
ReplyHiding.show table else
table = parent.nextSibling
$.rm div table.hidden = false
$.rm parent
hide: (reply) -> id = table.firstChild.firstChild.lastChild.id
ReplyHiding.hideHide reply for quote in $$ ".quotelink[href='##{id}'], .backlink[href='##{id}']"
$.removeClass quote, 'filtered'
id = reply.id delete g.hiddenReplies[id]
for quote in $$ ".quotelink[href='##{id}'], .backlink[href='##{id}']"
$.addClass quote, 'filtered'
g.hiddenReplies[id] = Date.now()
$.set "hiddenReplies/#{g.BOARD}/", g.hiddenReplies $.set "hiddenReplies/#{g.BOARD}/", g.hiddenReplies
hideHide: (reply) -> hide: (table) ->
table = reply.parentNode.parentNode.parentNode return if table.hidden # already hidden by filter
return if table.hidden #already hidden by filter
table.hidden = true table.hidden = true
if conf['Show Stubs'] return unless conf['Show Stubs']
name = $('.commentpostername', reply).textContent
uid = $('.posteruid', reply)?.textContent or ''
trip = $('.postertrip', reply)?.textContent or ''
div = $.el 'div', name = $('td[id] > .commentpostername', table).textContent
className: 'stub' uid = $('td[id] > .posteruid', table)?.textContent or ''
innerHTML: "<a href=javascript:;><span>[ + ]</span> #{name} #{uid} #{trip}</a>" trip = $('td[id] > .postertrip', table)?.textContent or ''
$.on $('a', div), 'click', ReplyHiding.cb.show
$.before table, div
show: (table) -> div = $.el 'div',
table.hidden = false className: 'stub'
innerHTML: "<a href=javascript:;><span>[ + ]</span> #{name} #{uid} #{trip}</a>"
id = $('td[id]', table).id $.on div.firstChild, 'click', ReplyHiding.toggle
for quote in $$ ".quotelink[href='##{id}'], .backlink[href='##{id}']" $.before table, div
$.removeClass quote, 'filtered'
delete g.hiddenReplies[id]
$.set "hiddenReplies/#{g.BOARD}/", g.hiddenReplies
Keybinds = Keybinds =
init: -> init: ->
@ -895,7 +872,7 @@ Keybinds =
when conf.previousReply when conf.previousReply
Keybinds.hl -1, thread Keybinds.hl -1, thread
when conf.hide when conf.hide
ThreadHiding.toggle thread ThreadHiding.toggle thread if /\bthread\b/.test thread.className
else else
return return
e.preventDefault() e.preventDefault()
@ -1038,14 +1015,18 @@ Nav =
qr = qr =
init: -> init: ->
return unless $.id 'recaptcha_challenge_field_holder' return unless $.id 'recaptcha_challenge_field_holder'
g.callbacks.push @node
setTimeout @asyncInit
asyncInit: ->
if conf['Hide Original Post Form'] if conf['Hide Original Post Form']
link = $.el 'h1', innerHTML: "<a href=javascript:;>#{if g.REPLY then 'Quick Reply' else 'New Thread'}</a>" link = $.el 'h1', innerHTML: "<a href=javascript:;>#{if g.REPLY then 'Quick Reply' else 'New Thread'}</a>"
$.on $('a', link), 'click', -> $.on $('a', link), 'click', ->
qr.open() qr.open()
$('select', qr.el).value = 'new' unless g.REPLY
$('textarea', qr.el).focus() $('textarea', qr.el).focus()
form = d.forms[0] form = d.forms[0]
$.before form, link $.before form, link
g.callbacks.push @node
# CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox. # CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox.
if /chrome/i.test navigator.userAgent if /chrome/i.test navigator.userAgent
@ -1063,17 +1044,14 @@ qr =
$.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @ $.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @
$.add d.head, iframe $.add d.head, iframe
# This is extemely slow, execute is asynchronously. # Prevent original captcha input from being focused on reload.
setTimeout -> script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}'
# Prevent original captcha input from being focused on reload. $.add d.head, script
script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}' $.rm script
$.add d.head, script
$.rm script
if conf['Persistent QR'] if conf['Persistent QR']
setTimeout -> qr.dialog()
qr.dialog() qr.hide() if conf['Auto Hide QR']
qr.hide() if conf['Auto Hide QR']
$.on d, 'dragover', qr.dragOver $.on d, 'dragover', qr.dragOver
$.on d, 'drop', qr.dropFile $.on d, 'drop', qr.dropFile
$.on d, 'dragstart', qr.drag $.on d, 'dragstart', qr.drag
@ -2061,78 +2039,64 @@ ThreadHiding =
hiddenThreads = $.get "hiddenThreads/#{g.BOARD}/", {} hiddenThreads = $.get "hiddenThreads/#{g.BOARD}/", {}
for thread in $$ '.thread' for thread in $$ '.thread'
op = thread.firstChild op = thread.firstChild
a = $.el 'a', a = $.el 'a',
textContent: '[ - ]' textContent: '[ - ]'
href: 'javascript:;' href: 'javascript:;'
$.on a, 'click', ThreadHiding.cb.hide $.on a, 'click', ThreadHiding.cb
$.prepend op, a $.prepend op, a
if op.id of hiddenThreads if op.id of hiddenThreads
ThreadHiding.hideHide thread ThreadHiding.hide thread
return
cb: cb: ->
hide: -> ThreadHiding.toggle @parentNode.parentNode
thread = @parentNode.parentNode
ThreadHiding.hide thread
show: ->
thread = @parentNode.parentNode
ThreadHiding.show thread
toggle: (thread) -> toggle: (thread) ->
if /\bstub\b/.test(thread.className) or thread.hidden hiddenThreads = $.get "hiddenThreads/#{g.BOARD}/", {}
id = $('.op', thread).id
if thread.hidden or thread.firstChild.className is 'block'
ThreadHiding.show thread ThreadHiding.show thread
delete hiddenThreads[id]
else else
ThreadHiding.hide thread ThreadHiding.hide thread
hiddenThreads[id] = Date.now()
$.set "hiddenThreads/#{g.BOARD}/", hiddenThreads
hide: (thread) -> hide: (thread) ->
ThreadHiding.hideHide thread unless conf['Show Stubs']
id = thread.firstChild.id
hiddenThreads = $.get "hiddenThreads/#{g.BOARD}/", {}
hiddenThreads[id] = Date.now()
$.set "hiddenThreads/#{g.BOARD}/", hiddenThreads
hideHide: (thread) ->
if conf['Show Stubs']
return if /stub/.test thread.className #already hidden by filter
if span = $ '.omittedposts', thread
num = Number span.textContent.match(/\d+/)[0]
else
num = 0
num += $$('table', thread).length
text = if num is 1 then "1 reply" else "#{num} replies"
name = $('.postername', thread).textContent
uid = $('.posteruid', thread)?.textContent or ''
trip = $('.postername + .postertrip', thread)?.textContent or ''
a = $.el 'a',
innerHTML: "<span>[ + ]</span> #{name}#{uid}#{trip} (#{text})"
href: 'javascript:;'
$.on a, 'click', ThreadHiding.cb.show
div = $.el 'div',
className: 'block'
$.add div, a
$.add thread, div
$.addClass thread, 'stub'
else
thread.hidden = true thread.hidden = true
thread.nextSibling.hidden = true thread.nextSibling.hidden = true
return
show: (thread) -> return if thread.firstChild.className is 'block' # already hidden by filter
$.rm $ 'div.block', thread
$.removeClass thread, 'stub' num = 0
if span = $ '.omittedposts', thread
num = Number span.textContent.match(/\d+/)[0]
num += $$('.op ~ table', thread).length
text = if num is 1 then '1 reply' else "#{num} replies"
op = $ '.op', thread
name = $('.postername', op).textContent
uid = $('.posteruid', op)?.textContent or ''
trip = $('.postertrip', op)?.textContent or ''
a = $.el 'a',
innerHTML: "<span>[ + ]</span> #{name} #{uid} #{trip} (#{text})"
href: 'javascript:;'
$.on a, 'click', ThreadHiding.cb
div = $.el 'div',
className: 'block'
$.add div, a
$.prepend thread, div
show: (thread, id) ->
$.rm $ '.block', thread
thread.hidden = false thread.hidden = false
thread.nextSibling.hidden = false thread.nextSibling.hidden = false
id = thread.firstChild.id
hiddenThreads = $.get "hiddenThreads/#{g.BOARD}/", {}
delete hiddenThreads[id]
$.set "hiddenThreads/#{g.BOARD}/", hiddenThreads
Updater = Updater =
init: -> init: ->
html = "<div class=move><span id=count></span> <span id=timer>-#{conf['Interval']}</span></div>" html = "<div class=move><span id=count></span> <span id=timer>-#{conf['Interval']}</span></div>"
@ -2236,22 +2200,18 @@ Updater =
body = $.el 'body', body = $.el 'body',
innerHTML: @responseText innerHTML: @responseText
id = $('td[id]', Updater.br.previousElementSibling)?.id or 0 id = $('input', Updater.br.previousElementSibling).name
nodes = [] nodes = []
for reply in $$('.reply', body).reverse() for reply in $$('.reply', body).reverse()
if reply.id <= id #make sure to not insert older posts break if reply.id <= id #make sure to not insert older posts
break
nodes.push reply.parentNode.parentNode.parentNode #table nodes.push reply.parentNode.parentNode.parentNode #table
newPosts = nodes.length newPosts = nodes.length
scroll = conf['Scrolling'] && Updater.scrollBG() && newPosts && scroll = conf['Scrolling'] && Updater.scrollBG() && newPosts &&
Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25 Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25
if conf['Verbose'] if conf['Verbose']
Updater.count.textContent = '+' + newPosts Updater.count.textContent = "+#{newPosts}"
if newPosts is 0 Updater.count.className = if newPosts then 'new' else null
Updater.count.className = null
else
Updater.count.className = 'new'
$.before Updater.br, nodes.reverse() $.before Updater.br, nodes.reverse()
if scroll if scroll
@ -2688,19 +2648,17 @@ QuoteInline =
inline.textContent = "#{req.status} #{req.statusText}" inline.textContent = "#{req.status} #{req.statusText}"
return return
body = $.el 'body', doc = d.implementation.createHTMLDocument null
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText
if id is threadID #OP
op = Threading.op $('body > form', body).firstChild node =
html = op.innerHTML if id is threadID #OP
else Threading.op $('body > form', doc).firstChild
for reply in $$ '.reply', body else
if reply.id == id doc.getElementById id
html = reply.innerHTML newInline = QuoteInline.table id, node.innerHTML
break
newInline = QuoteInline.table id, html
for quote in $$ '.quotelink', newInline for quote in $$ '.quotelink', newInline
if (href = quote.getAttribute('href')) is quote.hash #add pathname to normal quotes if (href = quote.getAttribute 'href') is quote.hash #add pathname to normal quotes
quote.pathname = pathname quote.pathname = pathname
else if !g.REPLY and href isnt quote.href #fix x-thread links, not x-board ones else if !g.REPLY and href isnt quote.href #fix x-thread links, not x-board ones
quote.href = "res/#{href}" quote.href = "res/#{href}"
@ -2756,23 +2714,21 @@ QuotePreview =
$.off @, 'mouseout', QuotePreview.mouseout $.off @, 'mouseout', QuotePreview.mouseout
$.off @, 'click', QuotePreview.mouseout $.off @, 'click', QuotePreview.mouseout
parse: (req, id, threadID) -> parse: (req, id, threadID) ->
return unless (qp = ui.el) and (qp.innerHTML is "Loading #{id}...") return unless (qp = ui.el) and qp.textContent is "Loading #{id}..."
if req.status isnt 200 if req.status isnt 200
qp.textContent = "#{req.status} #{req.statusText}" qp.textContent = "#{req.status} #{req.statusText}"
return return
body = $.el 'body', doc = d.implementation.createHTMLDocument null
innerHTML: req.responseText doc.documentElement.innerHTML = req.responseText
if id is threadID #OP
op = Threading.op $('body > form', body).firstChild node =
html = op.innerHTML if id is threadID #OP
else Threading.op $('body > form', doc).firstChild
for reply in $$ '.reply', body else
if reply.id == id doc.getElementById id
html = reply.innerHTML qp.innerHTML = node.innerHTML
break
qp.innerHTML = html
post = post =
root: qp root: qp
filesize: $ '.filesize', qp filesize: $ '.filesize', qp
@ -3176,6 +3132,10 @@ Main =
else else
g.PAGENUM = parseInt(temp) or 0 g.PAGENUM = parseInt(temp) or 0
#load values from localStorage
for key, val of conf
conf[key] = $.get key, val
$.on window, 'message', Main.message $.on window, 'message', Main.message
switch location.hostname switch location.hostname
@ -3302,20 +3262,20 @@ Main =
ImageExpand.init() ImageExpand.init()
if conf['Thread Watcher'] if conf['Thread Watcher']
Watcher.init() setTimeout -> Watcher.init()
if conf['Keybinds'] if conf['Keybinds']
Keybinds.init() setTimeout -> Keybinds.init()
if g.REPLY if g.REPLY
if conf['Thread Updater'] if conf['Thread Updater']
Updater.init() setTimeout -> Updater.init()
if conf['Thread Stats'] if conf['Thread Stats']
ThreadStats.init() ThreadStats.init()
if conf['Reply Navigation'] if conf['Reply Navigation']
Nav.init() setTimeout -> Nav.init()
if conf['Post in Title'] if conf['Post in Title']
TitlePost.init() TitlePost.init()
@ -3325,16 +3285,16 @@ Main =
else #not reply else #not reply
if conf['Thread Hiding'] if conf['Thread Hiding']
ThreadHiding.init() setTimeout -> ThreadHiding.init()
if conf['Thread Expansion'] if conf['Thread Expansion']
ExpandThread.init() setTimeout -> ExpandThread.init()
if conf['Comment Expansion'] if conf['Comment Expansion']
ExpandComment.init() setTimeout -> ExpandComment.init()
if conf['Index Navigation'] if conf['Index Navigation']
Nav.init() setTimeout -> Nav.init()
nodes = [] nodes = []
for node in $$ '.op, a + table', form for node in $$ '.op, a + table', form
@ -3372,7 +3332,7 @@ Main =
el: if klass is 'op' then node else node.firstChild.firstChild.lastChild el: if klass is 'op' then node else node.firstChild.firstChild.lastChild
class: klass class: klass
id: node.getElementsByTagName('input')[0].name id: node.getElementsByTagName('input')[0].name
threadId: g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id threadId: g.THREAD_ID or $.x('ancestor::div[@class="thread"]', node).firstChild.id
isOP: klass is 'op' isOP: klass is 'op'
isInlined: /\binline\b/.test klass isInlined: /\binline\b/.test klass
filesize: node.getElementsByClassName('filesize')[0] or false filesize: node.getElementsByClassName('filesize')[0] or false
@ -3385,7 +3345,7 @@ Main =
try try
callback node for node in nodes callback node for node in nodes
catch err catch err
alert "4chan X error: #{err.message}\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n#{err.stack}" if notify alert "4chan X (#{VERSION}) error: #{err.message}\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n#{err.stack}" if notify
return return
observer: (mutations) -> observer: (mutations) ->
nodes = [] nodes = []
@ -3412,7 +3372,9 @@ a[href="javascript:;"] {
text-decoration: none; text-decoration: none;
} }
.thread.stub > :not(.block), .block ~ .op,
.block ~ .omittedposts,
.block ~ table,
#content > [name=tab]:not(:checked) + div, #content > [name=tab]:not(:checked) + div,
#updater:not(:hover) > :not(.move), #updater:not(:hover) > :not(.move),
#qp > input, #qp .inline, .forwarded { #qp > input, #qp .inline, .forwarded {