This commit is contained in:
commit
92714d702c
358
4chan_x.user.js
358
4chan_x.user.js
@ -1,6 +1,6 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name 4chan x
|
// @name 4chan x
|
||||||
// @version 2.27.1
|
// @version 2.28.0
|
||||||
// @namespace aeosynth
|
// @namespace aeosynth
|
||||||
// @description Adds various features.
|
// @description Adds various features.
|
||||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||||
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||||
* http://mayhemydg.github.com/4chan-x/
|
* http://mayhemydg.github.com/4chan-x/
|
||||||
* 4chan X 2.27.1
|
* 4chan X 2.28.0
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation
|
* obtaining a copy of this software and associated documentation
|
||||||
@ -72,7 +72,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var $, $$, DAY, Favicon, FileInfo, HOUR, MINUTE, Main, NAMESPACE, SECOND, Time, VERSION, anonymize, conf, config, d, engine, expandComment, expandThread, filter, flatten, g, getTitle, imgExpand, imgGif, imgHover, key, keybinds, log, nav, options, qr, quoteBacklink, quoteIndicators, quoteInline, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _base;
|
var $, $$, DAY, Favicon, FileInfo, HOUR, MINUTE, Main, NAMESPACE, SECOND, Time, VERSION, anonymize, conf, config, d, engine, expandComment, expandThread, filter, flatten, g, getTitle, imgExpand, imgGif, imgHover, key, keybinds, log, nav, options, qr, quoteBacklink, quoteDR, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _base;
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
main: {
|
main: {
|
||||||
@ -209,7 +209,7 @@
|
|||||||
|
|
||||||
NAMESPACE = '4chan_x.';
|
NAMESPACE = '4chan_x.';
|
||||||
|
|
||||||
VERSION = '2.27.1';
|
VERSION = '2.28.0';
|
||||||
|
|
||||||
SECOND = 1000;
|
SECOND = 1000;
|
||||||
|
|
||||||
@ -575,109 +575,115 @@
|
|||||||
if (Object.keys(this.filters).length) return g.callbacks.push(this.node);
|
if (Object.keys(this.filters).length) return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
createFilter: function(regexp, op, hl, top) {
|
createFilter: function(regexp, op, hl, top) {
|
||||||
return function(root, value, isOP) {
|
var test;
|
||||||
var firstThread, thisThread;
|
test = typeof regexp === 'string' ? function(value) {
|
||||||
|
return regexp === value;
|
||||||
|
} : function(value) {
|
||||||
|
return regexp.test(value);
|
||||||
|
};
|
||||||
|
return function(value, isOP) {
|
||||||
if (isOP && op === 'no' || !isOP && op === 'only') return false;
|
if (isOP && op === 'no' || !isOP && op === 'only') return false;
|
||||||
if (typeof regexp === 'string') {
|
if (!test(value)) return false;
|
||||||
if (regexp !== value) return false;
|
if (hl) return [hl, top];
|
||||||
} else if (!regexp.test(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (hl) {
|
|
||||||
if (isOP) {
|
|
||||||
$.addClass(root, hl);
|
|
||||||
} else {
|
|
||||||
$.addClass(root.parentNode, hl);
|
|
||||||
}
|
|
||||||
if (isOP && top && !g.REPLY) {
|
|
||||||
thisThread = root.parentNode;
|
|
||||||
if (firstThread = $('div[class=op]')) {
|
|
||||||
$.before(firstThread.parentNode, [thisThread, thisThread.nextElementSibling]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isOP) {
|
|
||||||
if (!g.REPLY) threadHiding.hideHide(root.parentNode);
|
|
||||||
} else {
|
|
||||||
replyHiding.hideHide(root);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var Filter, isOP, key, klass, value, _i, _len, _ref;
|
var Filter, el, firstThread, isOP, key, result, thisThread, value, _i, _len, _ref;
|
||||||
klass = root.className;
|
if (post.isInlined) return;
|
||||||
if (/\binlined\b/.test(klass)) return;
|
isOP = post.isOP, el = post.el;
|
||||||
if (!(isOP = klass === 'op')) root = $('td[id]', root);
|
|
||||||
for (key in filter.filters) {
|
for (key in filter.filters) {
|
||||||
value = filter[key](root, isOP);
|
value = filter[key](post);
|
||||||
if (value === false) continue;
|
if (value === false) continue;
|
||||||
_ref = filter.filters[key];
|
_ref = filter.filters[key];
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
Filter = _ref[_i];
|
Filter = _ref[_i];
|
||||||
if (Filter(root, value, isOP)) return;
|
if (!(result = Filter(value, isOP))) continue;
|
||||||
|
if (result === true) {
|
||||||
|
if (isOP) {
|
||||||
|
if (!g.REPLY) {
|
||||||
|
threadHiding.hideHide(post.el.parentNode);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
replyHiding.hideHide(post.el);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isOP) {
|
||||||
|
$.addClass(el, result[0]);
|
||||||
|
} else {
|
||||||
|
$.addClass(el.parentNode, result[0]);
|
||||||
|
}
|
||||||
|
if (isOP && result[1] && !g.REPLY) {
|
||||||
|
thisThread = el.parentNode;
|
||||||
|
if (firstThread = $('div[class=op]')) {
|
||||||
|
$.before(firstThread.parentNode, [thisThread, thisThread.nextElementSibling]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
name: function(root, isOP) {
|
name: function(post) {
|
||||||
var name;
|
var name;
|
||||||
name = isOP ? $('.postername', root) : $('.commentpostername', root);
|
name = post.isOP ? $('.postername', post.el) : $('.commentpostername', post.el);
|
||||||
return name.textContent;
|
return name.textContent;
|
||||||
},
|
},
|
||||||
tripcode: function(root) {
|
tripcode: function(post) {
|
||||||
var trip;
|
var trip;
|
||||||
if (trip = $('.postertrip', root)) return trip.textContent;
|
if (trip = $('.postertrip', post.el)) return trip.textContent;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
mod: function(root, isOP) {
|
mod: function(post) {
|
||||||
var mod;
|
var mod;
|
||||||
if (mod = (isOP ? $('.commentpostername', root) : $('.commentpostername ~ .commentpostername', root))) {
|
if (mod = (post.isOP ? $('.commentpostername', post.el) : $('.commentpostername ~ .commentpostername', post.el))) {
|
||||||
return mod.textContent;
|
return mod.textContent;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
email: function(root) {
|
email: function(post) {
|
||||||
var mail;
|
var mail;
|
||||||
if (mail = $('.linkmail', root)) return mail.href;
|
if (mail = $('.linkmail', post.el)) return mail.href;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
subject: function(root, isOP) {
|
subject: function(post) {
|
||||||
var sub;
|
var sub;
|
||||||
sub = isOP ? $('.filetitle', root) : $('.replytitle', root);
|
sub = post.isOP ? $('.filetitle', post.el) : $('.replytitle', post.el);
|
||||||
return sub.textContent;
|
return sub.textContent;
|
||||||
},
|
},
|
||||||
comment: function(root) {
|
comment: function(post) {
|
||||||
var data, i, len, nodes, text;
|
var data, i, nodes, text, _ref;
|
||||||
text = [];
|
text = [];
|
||||||
nodes = d.evaluate('.//br|.//text()', root.lastChild, null, 7, null);
|
nodes = d.evaluate('.//br|.//text()', post.el.lastChild, null, 7, null);
|
||||||
i = 0;
|
for (i = 0, _ref = nodes.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
|
||||||
len = nodes.snapshotLength;
|
text.push((data = nodes.snapshotItem(i).data) ? data : '\n');
|
||||||
while (i < len) {
|
|
||||||
text.push((data = nodes.snapshotItem(i++).data) ? data : '\n');
|
|
||||||
}
|
}
|
||||||
return text.join('');
|
return text.join('');
|
||||||
},
|
},
|
||||||
filename: function(root) {
|
filename: function(post) {
|
||||||
var file;
|
var file;
|
||||||
if (file = $('.filesize > span', root)) return file.title;
|
if (file = $('span', post.filesize)) return file.title;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
dimensions: function(root) {
|
dimensions: function(post) {
|
||||||
var match, span;
|
var filesize, match;
|
||||||
if ((span = $('.filesize', root)) && (match = span.textContent.match(/\d+x\d+/))) {
|
filesize = post.filesize;
|
||||||
|
if (filesize && (match = filesize.textContent.match(/\d+x\d+/))) {
|
||||||
return match[0];
|
return match[0];
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
filesize: function(root) {
|
filesize: function(post) {
|
||||||
var img;
|
var img;
|
||||||
if (img = $('img[md5]', root)) return img.alt;
|
img = post.img;
|
||||||
|
if (img) return img.alt;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
md5: function(root) {
|
md5: function(post) {
|
||||||
var img;
|
var img;
|
||||||
if (img = $('img[md5]', root)) return img.getAttribute('md5');
|
img = post.img;
|
||||||
|
if (img) return img.getAttribute('md5');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -686,15 +692,15 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var el, quote, _i, _len, _ref;
|
var el, quote, _i, _len, _ref;
|
||||||
if (root.className === 'inline') return;
|
if (post.isInlined) return;
|
||||||
_ref = $$('.quotelink', root);
|
_ref = post.quotes;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
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']) root.hidden = true;
|
if (conf['Recursive Filtering']) post.root.hidden = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,7 +759,8 @@
|
|||||||
$.replace(a.parentNode.parentNode, bq);
|
$.replace(a.parentNode.parentNode, bq);
|
||||||
if (conf['Quote Preview']) quotePreview.node(bq);
|
if (conf['Quote Preview']) quotePreview.node(bq);
|
||||||
if (conf['Quote Inline']) quoteInline.node(bq);
|
if (conf['Quote Inline']) quoteInline.node(bq);
|
||||||
return quoteIndicators.node(bq);
|
if (conf['Indicate OP quote']) quoteOP.node(bq);
|
||||||
|
if (conf['Indicate Cross-thread Quotes']) return quoteDR.node(bq);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -866,9 +873,10 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var a, dd, id, reply;
|
var a, dd, id, reply;
|
||||||
if (!(dd = $('.doubledash', root))) return;
|
if (post["class"]) return;
|
||||||
|
dd = $('.doubledash', post.root);
|
||||||
dd.className = 'replyhider';
|
dd.className = 'replyhider';
|
||||||
a = $.el('a', {
|
a = $.el('a', {
|
||||||
textContent: '[ - ]',
|
textContent: '[ - ]',
|
||||||
@ -1257,7 +1265,7 @@
|
|||||||
|
|
||||||
qr = {
|
qr = {
|
||||||
init: function() {
|
init: function() {
|
||||||
var form, iframe, link, loadChecking, script;
|
var form, iframe, link, loadChecking;
|
||||||
if (!$.id('recaptcha_challenge_field_holder')) return;
|
if (!$.id('recaptcha_challenge_field_holder')) return;
|
||||||
if (conf['Hide Original Post Form']) {
|
if (conf['Hide Original Post Form']) {
|
||||||
link = $.el('h1', {
|
link = $.el('h1', {
|
||||||
@ -1298,11 +1306,14 @@
|
|||||||
});
|
});
|
||||||
$.add(d.head, iframe);
|
$.add(d.head, iframe);
|
||||||
}
|
}
|
||||||
script = $.el('script', {
|
setTimeout(function() {
|
||||||
textContent: 'Recaptcha.focus_response_field=function(){}'
|
var script;
|
||||||
|
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']) {
|
||||||
qr.dialog();
|
qr.dialog();
|
||||||
if (conf['Auto Hide QR']) qr.hide();
|
if (conf['Auto Hide QR']) qr.hide();
|
||||||
@ -1312,8 +1323,8 @@
|
|||||||
$.on(d, 'dragstart', qr.drag);
|
$.on(d, 'dragstart', qr.drag);
|
||||||
return $.on(d, 'dragend', qr.drag);
|
return $.on(d, 'dragend', qr.drag);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
return $.on($('.quotejs + .quotejs', root), 'click', qr.quote);
|
return $.on($('.quotejs + .quotejs', post.el), 'click', qr.quote);
|
||||||
},
|
},
|
||||||
open: function() {
|
open: function() {
|
||||||
if (qr.el) {
|
if (qr.el) {
|
||||||
@ -2745,11 +2756,11 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var name, trip;
|
var name, trip;
|
||||||
name = $('.commentpostername, .postername', root);
|
name = $('.commentpostername, .postername', post.el);
|
||||||
name.textContent = 'Anonymous';
|
name.textContent = 'Anonymous';
|
||||||
if (trip = $('.postertrip', root)) {
|
if (trip = $('.postertrip', post.el)) {
|
||||||
if (trip.parentNode.nodeName === 'A') {
|
if (trip.parentNode.nodeName === 'A') {
|
||||||
return $.rm(trip.parentNode);
|
return $.rm(trip.parentNode);
|
||||||
} else {
|
} else {
|
||||||
@ -2797,17 +2808,18 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var img, link, nodes, span, _i, _len, _ref;
|
var img, link, nodes, _i, _len, _ref;
|
||||||
if (root.className === 'inline' || !(span = $('.filesize', root))) return;
|
img = post.img;
|
||||||
img = span.nextElementSibling.nextElementSibling;
|
if (post["class"] === 'inline' || !img) return;
|
||||||
|
img = img.parentNode;
|
||||||
nodes = [];
|
nodes = [];
|
||||||
_ref = sauce.links;
|
_ref = sauce.links;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
link = _ref[_i];
|
link = _ref[_i];
|
||||||
nodes.push($.tn(' '), link(img));
|
nodes.push($.tn(' '), link(img));
|
||||||
}
|
}
|
||||||
return $.add(span, nodes);
|
return $.add(post.filesize, nodes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2815,11 +2827,12 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var img;
|
var img;
|
||||||
if (!(img = $('img[alt^=Spoil]', root)) || root.className === 'inline') {
|
img = {
|
||||||
return;
|
post: post
|
||||||
}
|
};
|
||||||
|
if (!(img && /^Spoil/.test(img.alt)) || post["class"] === 'inline') return;
|
||||||
img.removeAttribute('height');
|
img.removeAttribute('height');
|
||||||
img.removeAttribute('width');
|
img.removeAttribute('width');
|
||||||
return img.src = "http://thumbs.4chan.org" + (img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg'));
|
return img.src = "http://thumbs.4chan.org" + (img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg'));
|
||||||
@ -2844,10 +2857,10 @@
|
|||||||
};
|
};
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var node, time;
|
var node, time;
|
||||||
if (root.className === 'inline') return;
|
if (post["class"] === 'inline') return;
|
||||||
node = $('.posttime', root) || $('span[id]', root).previousSibling;
|
node = $('.posttime', post.el) || $('span[id]', post.el).previousSibling;
|
||||||
Time.date = Time.parse(node);
|
Time.date = Time.parse(node);
|
||||||
time = $.el('time', {
|
time = $.el('time', {
|
||||||
textContent: ' ' + Time.funk(Time) + ' '
|
textContent: ' ' + Time.funk(Time) + ' '
|
||||||
@ -2937,9 +2950,9 @@
|
|||||||
this.setFormats();
|
this.setFormats();
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var fullname, link, node, regexp, resolution, shortname, size, type, unit, _, _ref;
|
var fullname, link, node, regexp, resolution, shortname, size, type, unit, _, _ref;
|
||||||
if (root.className === 'inline' || !(node = $('.filesize', root))) return;
|
if (post["class"] === 'inline' || !(node = post.filesize)) return;
|
||||||
type = node.childElementCount === 2 ? 0 : 1;
|
type = node.childElementCount === 2 ? 0 : 1;
|
||||||
regexp = type ? /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF)/ : /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF), <span title="(.+)">([^<]+)/;
|
regexp = type ? /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF)/ : /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF), <span title="(.+)">([^<]+)/;
|
||||||
_ref = node.innerHTML.match(regexp), _ = _ref[0], link = _ref[1], size = _ref[2], unit = _ref[3], resolution = _ref[4], fullname = _ref[5], shortname = _ref[6];
|
_ref = node.innerHTML.match(regexp), _ = _ref[0], link = _ref[1], size = _ref[2], unit = _ref[3], resolution = _ref[4], fullname = _ref[5], shortname = _ref[6];
|
||||||
@ -3059,20 +3072,19 @@
|
|||||||
quoteBacklink.funk = Function('id', "return '" + format + "'");
|
quoteBacklink.funk = Function('id', "return '" + format + "'");
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var a, container, el, id, link, qid, quote, quotes, _i, _len, _ref;
|
var a, container, el, link, qid, quote, quotes, root, _i, _len, _ref;
|
||||||
if (/\binline\b/.test(root.className)) return;
|
if (post.isInlined) return;
|
||||||
quotes = {};
|
quotes = {};
|
||||||
_ref = $$('.quotelink', root);
|
_ref = post.quotes;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
quote = _ref[_i];
|
quote = _ref[_i];
|
||||||
if (qid = quote.hash.slice(1)) quotes[qid] = true;
|
if (qid = quote.hash.slice(1)) quotes[qid] = true;
|
||||||
}
|
}
|
||||||
id = $('input', root).name;
|
|
||||||
a = $.el('a', {
|
a = $.el('a', {
|
||||||
href: "#" + id,
|
href: "#" + post.id,
|
||||||
className: root.hidden ? 'filtered backlink' : 'backlink',
|
className: post.root.hidden ? 'filtered backlink' : 'backlink',
|
||||||
textContent: quoteBacklink.funk(id)
|
textContent: quoteBacklink.funk(post.id)
|
||||||
});
|
});
|
||||||
for (qid in quotes) {
|
for (qid in quotes) {
|
||||||
if (!(el = $.id(qid)) || el.className === 'op' && !conf['OP Backlinks']) {
|
if (!(el = $.id(qid)) || el.className === 'op' && !conf['OP Backlinks']) {
|
||||||
@ -3085,10 +3097,12 @@
|
|||||||
container = $.el('span', {
|
container = $.el('span', {
|
||||||
className: 'container'
|
className: 'container'
|
||||||
});
|
});
|
||||||
|
$.add(container, [$.tn(' '), link]);
|
||||||
root = $('.reportbutton', el) || $('span[id]', el);
|
root = $('.reportbutton', el) || $('span[id]', el);
|
||||||
$.after(root, container);
|
$.after(root, container);
|
||||||
|
} else {
|
||||||
|
$.add(container, [$.tn(' '), link]);
|
||||||
}
|
}
|
||||||
$.add(container, [$.tn(' '), link]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3097,9 +3111,9 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var quote, _i, _len, _ref;
|
var quote, _i, _len, _ref;
|
||||||
_ref = $$('.quotelink, .backlink', root);
|
_ref = post.quotes.concat(post.backlinks);
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
quote = _ref[_i];
|
quote = _ref[_i];
|
||||||
if (!quote.hash) continue;
|
if (!quote.hash) continue;
|
||||||
@ -3223,9 +3237,9 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var quote, _i, _len, _ref;
|
var quote, _i, _len, _ref;
|
||||||
_ref = $$('.quotelink, .backlink', root);
|
_ref = post.quotes.concat(post.backlinks);
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
quote = _ref[_i];
|
quote = _ref[_i];
|
||||||
if (quote.hash) $.on(quote, 'mouseover', quotePreview.mouseover);
|
if (quote.hash) $.on(quote, 'mouseover', quotePreview.mouseover);
|
||||||
@ -3301,24 +3315,36 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quoteIndicators = {
|
quoteOP = {
|
||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var hash, path, quote, tid, _i, _len, _ref;
|
var quote, _i, _len, _ref;
|
||||||
if (root.className === 'inline') return;
|
if (post["class"] === 'inline') return;
|
||||||
tid = g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', root).firstChild.id;
|
_ref = post.quotes;
|
||||||
_ref = $$('.quotelink', root);
|
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
quote = _ref[_i];
|
quote = _ref[_i];
|
||||||
if (!(hash = quote.hash.slice(1))) continue;
|
if (quote.hash.slice(1) === post.threadId) {
|
||||||
if (conf['Indicate OP quote'] && hash === tid) {
|
|
||||||
$.add(quote, $.tn('\u00A0(OP)'));
|
$.add(quote, $.tn('\u00A0(OP)'));
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
path = quote.pathname;
|
}
|
||||||
if (conf['Indicate Cross-thread Quotes'] && path.lastIndexOf("/" + tid) === -1 && path.indexOf("/" + g.BOARD + "/") === 0) {
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
quoteDR = {
|
||||||
|
init: function() {
|
||||||
|
return g.callbacks.push(this.node);
|
||||||
|
},
|
||||||
|
node: function(post) {
|
||||||
|
var path, quote, _i, _len, _ref;
|
||||||
|
if (post["class"] === 'inline') return;
|
||||||
|
_ref = post.quotes;
|
||||||
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
|
quote = _ref[_i];
|
||||||
|
if (!quote.hash) continue;
|
||||||
|
path = quote.pathname.split('/');
|
||||||
|
if (path[1] === g.BOARD && path[3] !== post.threadId) {
|
||||||
$.add(quote, $.tn('\u00A0(Cross-thread)'));
|
$.add(quote, $.tn('\u00A0(Cross-thread)'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3329,16 +3355,15 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var a, span;
|
var a;
|
||||||
if (!(a = $('.reportbutton', root))) {
|
if (!(a = $('.reportbutton', post.el))) {
|
||||||
span = $('span[id]', root);
|
|
||||||
a = $.el('a', {
|
a = $.el('a', {
|
||||||
className: 'reportbutton',
|
className: 'reportbutton',
|
||||||
innerHTML: '[ ! ]',
|
innerHTML: '[ ! ]',
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
});
|
});
|
||||||
$.after(span, [$.tn(' '), a]);
|
$.after($('span[id]', post.el), [$.tn(' '), a]);
|
||||||
}
|
}
|
||||||
return $.on(a, 'click', reportButton.report);
|
return $.on(a, 'click', reportButton.report);
|
||||||
},
|
},
|
||||||
@ -3372,11 +3397,11 @@
|
|||||||
})();
|
})();
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var imgcount;
|
var imgcount;
|
||||||
if (/\binline\b/.test(root.className)) return;
|
if (post.isInlined) return;
|
||||||
$.id('postcount').textContent = ++threadStats.posts;
|
$.id('postcount').textContent = ++threadStats.posts;
|
||||||
if (!$('img[md5]', root)) return;
|
if (!post.img) return;
|
||||||
imgcount = $.id('imagecount');
|
imgcount = $.id('imagecount');
|
||||||
imgcount.textContent = ++threadStats.images;
|
imgcount.textContent = ++threadStats.images;
|
||||||
if (threadStats.images > threadStats.imgLimit) {
|
if (threadStats.images > threadStats.imgLimit) {
|
||||||
@ -3393,9 +3418,9 @@
|
|||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
replies: [],
|
replies: [],
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
if (root.hidden || root.className) return;
|
if (post.root.hidden || post["class"]) return;
|
||||||
unread.replies.push(root);
|
unread.replies.push(post.root);
|
||||||
return unread.update();
|
return unread.update();
|
||||||
},
|
},
|
||||||
scroll: function() {
|
scroll: function() {
|
||||||
@ -3530,10 +3555,9 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var thumb;
|
if (!post.img) return;
|
||||||
if (!(thumb = $('img[md5]', root))) return;
|
return $.on(post.img, 'mouseover', imgHover.mouseover);
|
||||||
return $.on(thumb, 'mouseover', imgHover.mouseover);
|
|
||||||
},
|
},
|
||||||
mouseover: function() {
|
mouseover: function() {
|
||||||
ui.el = $.el('img', {
|
ui.el = $.el('img', {
|
||||||
@ -3565,14 +3589,14 @@
|
|||||||
init: function() {
|
init: function() {
|
||||||
return g.callbacks.push(this.node);
|
return g.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var img, src, thumb;
|
var img, src;
|
||||||
if (root.hidden || !(thumb = $('img[md5]', root))) return;
|
if (post.root.hidden || !post.img) return;
|
||||||
src = thumb.parentNode.href;
|
src = post.img.parentNode.href;
|
||||||
if (/gif$/.test(src) && !/spoiler/.test(src)) {
|
if (/gif$/.test(src) && !/spoiler/.test(src)) {
|
||||||
img = $.el('img');
|
img = $.el('img');
|
||||||
$.on(img, 'load', function() {
|
$.on(img, 'load', function() {
|
||||||
return thumb.src = src;
|
return post.img.src = src;
|
||||||
});
|
});
|
||||||
return img.src = src;
|
return img.src = src;
|
||||||
}
|
}
|
||||||
@ -3584,12 +3608,12 @@
|
|||||||
g.callbacks.push(this.node);
|
g.callbacks.push(this.node);
|
||||||
return imgExpand.dialog();
|
return imgExpand.dialog();
|
||||||
},
|
},
|
||||||
node: function(root) {
|
node: function(post) {
|
||||||
var a, thumb;
|
var a;
|
||||||
if (!(thumb = $('img[md5]', root))) return;
|
if (!post.img) return;
|
||||||
a = thumb.parentNode;
|
a = post.img.parentNode;
|
||||||
$.on(a, 'click', imgExpand.cb.toggle);
|
$.on(a, 'click', imgExpand.cb.toggle);
|
||||||
if (imgExpand.on && !root.hidden && root.className !== 'inline') {
|
if (imgExpand.on && !post.root.hidden && post["class"] !== 'inline') {
|
||||||
return imgExpand.expand(a.firstChild);
|
return imgExpand.expand(a.firstChild);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3814,20 +3838,24 @@
|
|||||||
if (conf['Quote Inline']) quoteInline.init();
|
if (conf['Quote Inline']) quoteInline.init();
|
||||||
if (conf['Quote Preview']) quotePreview.init();
|
if (conf['Quote Preview']) quotePreview.init();
|
||||||
if (conf['Quote Backlinks']) quoteBacklink.init();
|
if (conf['Quote Backlinks']) quoteBacklink.init();
|
||||||
if (conf['Indicate OP quote'] || conf['Indicate Cross-thread Quotes']) {
|
if (conf['Indicate OP quote']) quoteOP.init();
|
||||||
quoteIndicators.init();
|
if (conf['Indicate Cross-thread Quotes']) quoteDR.init();
|
||||||
}
|
|
||||||
return $.ready(Main.ready);
|
return $.ready(Main.ready);
|
||||||
},
|
},
|
||||||
ready: function() {
|
ready: function() {
|
||||||
var MutationObserver, form, nodes, observer;
|
var MutationObserver, form, nav, nodes, observer, _i, _len, _ref;
|
||||||
if (d.title === '4chan - 404') {
|
if (d.title === '4chan - 404') {
|
||||||
redirect.init();
|
redirect.init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$.id('navtopr')) return;
|
if (!$.id('navtopr')) return;
|
||||||
$.addClass(d.body, "chanx_" + (VERSION.match(/\.(\d+)/)[1]));
|
$.addClass(d.body, "chanx_" + (VERSION.split('.')[1]));
|
||||||
$.addClass(d.body, engine);
|
$.addClass(d.body, engine);
|
||||||
|
_ref = ['navtop', 'navbot'];
|
||||||
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
|
nav = _ref[_i];
|
||||||
|
$.addClass($("a[href$='/" + g.BOARD + "/']", $.id(nav)), 'current');
|
||||||
|
}
|
||||||
form = $('form[name=delform]');
|
form = $('form[name=delform]');
|
||||||
threading.thread(form.firstElementChild);
|
threading.thread(form.firstElementChild);
|
||||||
Favicon.init();
|
Favicon.init();
|
||||||
@ -3880,17 +3908,37 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
node: function(nodes, notify) {
|
node: function(nodes, notify) {
|
||||||
var callback, node, _i, _j, _len, _len2, _ref;
|
var callback, klass, node, post, posts, _i, _j, _k, _len, _len2, _len3, _ref;
|
||||||
|
posts = [];
|
||||||
|
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
||||||
|
node = nodes[_i];
|
||||||
|
klass = node.className;
|
||||||
|
posts.push({
|
||||||
|
root: node,
|
||||||
|
el: klass === 'op' ? node : $('td[id]', node),
|
||||||
|
"class": klass,
|
||||||
|
id: $('input', node).name,
|
||||||
|
threadId: g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id,
|
||||||
|
isOP: klass === 'op',
|
||||||
|
isInlined: /\binline\b/.test(klass),
|
||||||
|
filesize: $('.filesize', node),
|
||||||
|
img: $('img[md5]', node),
|
||||||
|
quotes: $$('.quotelink', node),
|
||||||
|
backlinks: $$('.backlink', node)
|
||||||
|
});
|
||||||
|
}
|
||||||
_ref = g.callbacks;
|
_ref = g.callbacks;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
|
||||||
callback = _ref[_i];
|
callback = _ref[_j];
|
||||||
try {
|
try {
|
||||||
for (_j = 0, _len2 = nodes.length; _j < _len2; _j++) {
|
for (_k = 0, _len3 = posts.length; _k < _len3; _k++) {
|
||||||
node = nodes[_j];
|
post = posts[_k];
|
||||||
callback(node);
|
callback(post);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (notify) alert(err.message);
|
if (notify) {
|
||||||
|
alert("4chan X error: " + err.message + "\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n" + err.stack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
2
Cakefile
2
Cakefile
@ -2,7 +2,7 @@
|
|||||||
{exec} = require 'child_process'
|
{exec} = require 'child_process'
|
||||||
fs = require 'fs'
|
fs = require 'fs'
|
||||||
|
|
||||||
VERSION = '2.27.1'
|
VERSION = '2.28.0'
|
||||||
|
|
||||||
HEADER = """
|
HEADER = """
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
master
|
master
|
||||||
|
- Mayhem
|
||||||
|
General performance improvements.
|
||||||
|
|
||||||
|
2.28.0
|
||||||
- ahodesuka
|
- ahodesuka
|
||||||
Reply/Thread File Info Formatting:
|
Reply/Thread File Info Formatting:
|
||||||
- Link: %l, %L (Original file names are shown inside threads).
|
- Link: %l, %L (Original file names are shown inside threads).
|
||||||
@ -6,7 +10,7 @@ master
|
|||||||
- Resolution/PDF: %r
|
- Resolution/PDF: %r
|
||||||
- Original filename: %n, %N.
|
- Original filename: %n, %N.
|
||||||
- noface
|
- noface
|
||||||
Update imagelimit for mlp.
|
Update imagelimit for /mlp/.
|
||||||
Fix stubs if poster has unique ID.
|
Fix stubs if poster has unique ID.
|
||||||
- Mayhem
|
- Mayhem
|
||||||
You can now filter or highlight admin/mod posts.
|
You can now filter or highlight admin/mod posts.
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
postMessage({version:'2.27.1'},'*');
|
postMessage({version:'2.28.0'},'*');
|
||||||
|
|||||||
313
script.coffee
313
script.coffee
@ -161,7 +161,7 @@ conf = {}
|
|||||||
) null, config
|
) null, config
|
||||||
|
|
||||||
NAMESPACE = '4chan_x.'
|
NAMESPACE = '4chan_x.'
|
||||||
VERSION = '2.27.1'
|
VERSION = '2.28.0'
|
||||||
SECOND = 1000
|
SECOND = 1000
|
||||||
MINUTE = 60*SECOND
|
MINUTE = 60*SECOND
|
||||||
HOUR = 60*MINUTE
|
HOUR = 60*MINUTE
|
||||||
@ -499,102 +499,110 @@ filter =
|
|||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
|
|
||||||
createFilter: (regexp, op, hl, top) ->
|
createFilter: (regexp, op, hl, top) ->
|
||||||
(root, value, isOP) ->
|
test =
|
||||||
if isOP and op is 'no' or !isOP and op is 'only'
|
|
||||||
return false
|
|
||||||
if typeof regexp is 'string'
|
if typeof regexp is 'string'
|
||||||
# MD5 checking
|
# MD5 checking
|
||||||
if regexp isnt value
|
(value) -> regexp is value
|
||||||
return false
|
else
|
||||||
else unless regexp.test value
|
(value) -> regexp.test value
|
||||||
|
(value, isOP) ->
|
||||||
|
if isOP and op is 'no' or !isOP and op is 'only'
|
||||||
|
return false
|
||||||
|
unless test value
|
||||||
return false
|
return false
|
||||||
if hl
|
if hl
|
||||||
if isOP
|
return [hl, top]
|
||||||
$.addClass root, hl
|
|
||||||
else
|
|
||||||
$.addClass root.parentNode, hl
|
|
||||||
if isOP and top and not g.REPLY
|
|
||||||
# Put the highlighted OPs' threads on top of the board pages...
|
|
||||||
thisThread = root.parentNode
|
|
||||||
# ...before the first non highlighted thread.
|
|
||||||
if firstThread = $ 'div[class=op]'
|
|
||||||
$.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling]
|
|
||||||
# Continue the filter lookup to add more classes or hide it.
|
|
||||||
return false
|
|
||||||
if isOP
|
|
||||||
unless g.REPLY
|
|
||||||
threadHiding.hideHide root.parentNode
|
|
||||||
else
|
|
||||||
replyHiding.hideHide root
|
|
||||||
true
|
true
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
klass = root.className
|
return if post.isInlined
|
||||||
return if /\binlined\b/.test klass
|
{isOP, el} = post
|
||||||
unless isOP = klass is 'op'
|
|
||||||
root = $ 'td[id]', root
|
|
||||||
for key of filter.filters
|
for key of filter.filters
|
||||||
value = filter[key] root, isOP
|
value = filter[key] post
|
||||||
if value is false
|
if value is false
|
||||||
# Continue if there's nothing to filter (no tripcode for example).
|
# Continue if there's nothing to filter (no tripcode for example).
|
||||||
continue
|
continue
|
||||||
for Filter in filter.filters[key]
|
for Filter in filter.filters[key]
|
||||||
if Filter root, value, isOP
|
unless result = Filter value, isOP
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Hide
|
||||||
|
if result is true
|
||||||
|
if isOP
|
||||||
|
unless g.REPLY
|
||||||
|
threadHiding.hideHide post.el.parentNode
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
replyHiding.hideHide post.el
|
||||||
return
|
return
|
||||||
|
|
||||||
name: (root, isOP) ->
|
# Highlight
|
||||||
name = if isOP then $ '.postername', root else $ '.commentpostername', root
|
if isOP
|
||||||
|
$.addClass el, result[0]
|
||||||
|
else
|
||||||
|
$.addClass el.parentNode, result[0]
|
||||||
|
if isOP and result[1] and not g.REPLY
|
||||||
|
# Put the highlighted OPs' threads on top of the board pages...
|
||||||
|
thisThread = el.parentNode
|
||||||
|
# ...before the first non highlighted thread.
|
||||||
|
if firstThread = $ 'div[class=op]'
|
||||||
|
$.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling]
|
||||||
|
|
||||||
|
name: (post) ->
|
||||||
|
name = if post.isOP then $ '.postername', post.el else $ '.commentpostername', post.el
|
||||||
name.textContent
|
name.textContent
|
||||||
tripcode: (root) ->
|
tripcode: (post) ->
|
||||||
if trip = $ '.postertrip', root
|
if trip = $ '.postertrip', post.el
|
||||||
return trip.textContent
|
return trip.textContent
|
||||||
false
|
false
|
||||||
mod: (root, isOP) ->
|
mod: (post) ->
|
||||||
if mod = (if isOP then $ '.commentpostername', root else $ '.commentpostername ~ .commentpostername', root)
|
if mod = (if post.isOP then $ '.commentpostername', post.el else $ '.commentpostername ~ .commentpostername', post.el)
|
||||||
return mod.textContent
|
return mod.textContent
|
||||||
false
|
false
|
||||||
email: (root) ->
|
email: (post) ->
|
||||||
if mail = $ '.linkmail', root
|
if mail = $ '.linkmail', post.el
|
||||||
return mail.href
|
return mail.href
|
||||||
false
|
false
|
||||||
subject: (root, isOP) ->
|
subject: (post) ->
|
||||||
sub = if isOP then $ '.filetitle', root else $ '.replytitle', root
|
sub = if post.isOP then $ '.filetitle', post.el else $ '.replytitle', post.el
|
||||||
sub.textContent
|
sub.textContent
|
||||||
comment: (root) ->
|
comment: (post) ->
|
||||||
text = []
|
text = []
|
||||||
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 7
|
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 7
|
||||||
nodes = d.evaluate './/br|.//text()', root.lastChild, null, 7, null
|
nodes = d.evaluate './/br|.//text()', post.el.lastChild, null, 7, null
|
||||||
i = 0
|
for i in [0...nodes.snapshotLength]
|
||||||
len = nodes.snapshotLength
|
text.push if data = nodes.snapshotItem(i).data then data else '\n'
|
||||||
while i < len
|
|
||||||
text.push if data = nodes.snapshotItem(i++).data then data else '\n'
|
|
||||||
text.join ''
|
text.join ''
|
||||||
filename: (root) ->
|
filename: (post) ->
|
||||||
if file = $ '.filesize > span', root
|
if file = $ 'span', post.filesize
|
||||||
return file.title
|
return file.title
|
||||||
false
|
false
|
||||||
dimensions: (root) ->
|
dimensions: (post) ->
|
||||||
if (span = $ '.filesize', root) and match = span.textContent.match /\d+x\d+/
|
{filesize} = post
|
||||||
|
if filesize and match = filesize.textContent.match /\d+x\d+/
|
||||||
return match[0]
|
return match[0]
|
||||||
return false
|
return false
|
||||||
filesize: (root) ->
|
filesize: (post) ->
|
||||||
if img = $ 'img[md5]', root
|
{img} = post
|
||||||
|
if img
|
||||||
return img.alt
|
return img.alt
|
||||||
false
|
false
|
||||||
md5: (root) ->
|
md5: (post) ->
|
||||||
if img = $ 'img[md5]', root
|
{img} = post
|
||||||
|
if img
|
||||||
return img.getAttribute 'md5'
|
return img.getAttribute 'md5'
|
||||||
false
|
false
|
||||||
|
|
||||||
strikethroughQuotes =
|
strikethroughQuotes =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.className is 'inline'
|
return if post.isInlined
|
||||||
for quote in $$ '.quotelink', root
|
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'
|
||||||
root.hidden = true if conf['Recursive Filtering']
|
post.root.hidden = true if conf['Recursive Filtering']
|
||||||
return
|
return
|
||||||
|
|
||||||
expandComment =
|
expandComment =
|
||||||
@ -633,7 +641,10 @@ expandComment =
|
|||||||
quotePreview.node bq
|
quotePreview.node bq
|
||||||
if conf['Quote Inline']
|
if conf['Quote Inline']
|
||||||
quoteInline.node bq
|
quoteInline.node bq
|
||||||
quoteIndicators.node bq
|
if conf['Indicate OP quote']
|
||||||
|
quoteOP.node bq
|
||||||
|
if conf['Indicate Cross-thread Quotes']
|
||||||
|
quoteDR.node bq
|
||||||
|
|
||||||
expandThread =
|
expandThread =
|
||||||
init: ->
|
init: ->
|
||||||
@ -711,8 +722,9 @@ replyHiding =
|
|||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return unless dd = $ '.doubledash', root
|
return if post.class
|
||||||
|
dd = $ '.doubledash', post.root
|
||||||
dd.className = 'replyhider'
|
dd.className = 'replyhider'
|
||||||
a = $.el 'a',
|
a = $.el 'a',
|
||||||
textContent: '[ - ]'
|
textContent: '[ - ]'
|
||||||
@ -755,8 +767,8 @@ replyHiding =
|
|||||||
|
|
||||||
if conf['Show Stubs']
|
if conf['Show Stubs']
|
||||||
name = $('.commentpostername', reply).textContent
|
name = $('.commentpostername', reply).textContent
|
||||||
uid = $('.posteruid', reply)?.textContent or ''
|
uid = $('.posteruid', reply)?.textContent or ''
|
||||||
trip = $('.postertrip', reply)?.textContent or ''
|
trip = $('.postertrip', reply)?.textContent or ''
|
||||||
|
|
||||||
div = $.el 'div',
|
div = $.el 'div',
|
||||||
className: 'stub'
|
className: 'stub'
|
||||||
@ -1024,10 +1036,12 @@ 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
|
||||||
|
|
||||||
# Prevent original captcha input from being focused on reload.
|
# This is extemely slow, execute is asynchronously.
|
||||||
script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}'
|
setTimeout ->
|
||||||
$.add d.head, script
|
# Prevent original captcha input from being focused on reload.
|
||||||
$.rm script
|
script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}'
|
||||||
|
$.add d.head, script
|
||||||
|
$.rm script
|
||||||
|
|
||||||
if conf['Persistent QR']
|
if conf['Persistent QR']
|
||||||
qr.dialog()
|
qr.dialog()
|
||||||
@ -1037,8 +1051,8 @@ qr =
|
|||||||
$.on d, 'dragstart', qr.drag
|
$.on d, 'dragstart', qr.drag
|
||||||
$.on d, 'dragend', qr.drag
|
$.on d, 'dragend', qr.drag
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
$.on $('.quotejs + .quotejs', root), 'click', qr.quote
|
$.on $('.quotejs + .quotejs', post.el), 'click', qr.quote
|
||||||
|
|
||||||
open: ->
|
open: ->
|
||||||
if qr.el
|
if qr.el
|
||||||
@ -2264,10 +2278,10 @@ watcher =
|
|||||||
anonymize =
|
anonymize =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
name = $ '.commentpostername, .postername', root
|
name = $ '.commentpostername, .postername', post.el
|
||||||
name.textContent = 'Anonymous'
|
name.textContent = 'Anonymous'
|
||||||
if trip = $ '.postertrip', root
|
if trip = $ '.postertrip', post.el
|
||||||
if trip.parentNode.nodeName is 'A'
|
if trip.parentNode.nodeName is 'A'
|
||||||
$.rm trip.parentNode
|
$.rm trip.parentNode
|
||||||
else
|
else
|
||||||
@ -2302,19 +2316,22 @@ sauce =
|
|||||||
target: '_blank'
|
target: '_blank'
|
||||||
textContent: domain
|
textContent: domain
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.className is 'inline' or not span = $ '.filesize', root
|
{img} = post
|
||||||
img = span.nextElementSibling.nextElementSibling
|
return if post.class is 'inline' or not img
|
||||||
|
img = img.parentNode
|
||||||
nodes = []
|
nodes = []
|
||||||
for link in sauce.links
|
for link in sauce.links
|
||||||
nodes.push $.tn(' '), link img
|
nodes.push $.tn(' '), link img
|
||||||
$.add span, nodes
|
$.add post.filesize, nodes
|
||||||
|
|
||||||
revealSpoilers =
|
revealSpoilers =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if not (img = $ 'img[alt^=Spoil]', root) or root.className is 'inline'
|
img = {post}
|
||||||
|
if not (img and /^Spoil/.test img.alt) or post.class is 'inline'
|
||||||
|
return
|
||||||
img.removeAttribute 'height'
|
img.removeAttribute 'height'
|
||||||
img.removeAttribute 'width'
|
img.removeAttribute 'width'
|
||||||
img.src = "http://thumbs.4chan.org#{img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg')}"
|
img.src = "http://thumbs.4chan.org#{img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg')}"
|
||||||
@ -2341,10 +2358,10 @@ Time =
|
|||||||
new Date year, month, day, hour, min
|
new Date year, month, day, hour, min
|
||||||
|
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.className is 'inline'
|
return if post.class is 'inline'
|
||||||
# .posttime exists on every board except /f/
|
# .posttime exists on every board except /f/
|
||||||
node = $('.posttime', root) or $('span[id]', root).previousSibling
|
node = $('.posttime', post.el) or $('span[id]', post.el).previousSibling
|
||||||
Time.date = Time.parse node
|
Time.date = Time.parse node
|
||||||
time = $.el 'time',
|
time = $.el 'time',
|
||||||
textContent: ' ' + Time.funk(Time) + ' '
|
textContent: ' ' + Time.funk(Time) + ' '
|
||||||
@ -2402,8 +2419,8 @@ FileInfo =
|
|||||||
return if g.BOARD is 'f'
|
return if g.BOARD is 'f'
|
||||||
@setFormats()
|
@setFormats()
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.className is 'inline' or not node = $ '.filesize', root
|
return if post.class is 'inline' or not node = post.filesize
|
||||||
type = if node.childElementCount is 2 then 0 else 1
|
type = if node.childElementCount is 2 then 0 else 1
|
||||||
regexp =
|
regexp =
|
||||||
if type
|
if type
|
||||||
@ -2484,20 +2501,18 @@ quoteBacklink =
|
|||||||
format = conf['backlink'].replace /%id/g, "' + id + '"
|
format = conf['backlink'].replace /%id/g, "' + id + '"
|
||||||
quoteBacklink.funk = Function 'id', "return '#{format}'"
|
quoteBacklink.funk = Function 'id', "return '#{format}'"
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if /\binline\b/.test root.className
|
return if post.isInlined
|
||||||
quotes = {}
|
quotes = {}
|
||||||
for quote in $$ '.quotelink', root
|
for quote in post.quotes
|
||||||
# Don't process >>>/b/.
|
# Don't process >>>/b/.
|
||||||
if qid = quote.hash[1..]
|
if qid = quote.hash[1..]
|
||||||
# Duplicate quotes get overwritten.
|
# Duplicate quotes get overwritten.
|
||||||
quotes[qid] = true
|
quotes[qid] = true
|
||||||
# OP or reply id.
|
|
||||||
id = $('input', root).name
|
|
||||||
a = $.el 'a',
|
a = $.el 'a',
|
||||||
href: "##{id}"
|
href: "##{post.id}"
|
||||||
className: if root.hidden then 'filtered backlink' else 'backlink'
|
className: if post.root.hidden then 'filtered backlink' else 'backlink'
|
||||||
textContent: quoteBacklink.funk id
|
textContent: quoteBacklink.funk post.id
|
||||||
for qid of quotes
|
for qid of quotes
|
||||||
# Don't backlink the OP.
|
# Don't backlink the OP.
|
||||||
continue if !(el = $.id qid) or el.className is 'op' and !conf['OP Backlinks']
|
continue if !(el = $.id qid) or el.className is 'op' and !conf['OP Backlinks']
|
||||||
@ -2508,16 +2523,18 @@ quoteBacklink =
|
|||||||
$.on link, 'click', quoteInline.toggle
|
$.on link, 'click', quoteInline.toggle
|
||||||
unless (container = $ '.container', el) and container.parentNode is el
|
unless (container = $ '.container', el) and container.parentNode is el
|
||||||
container = $.el 'span', className: 'container'
|
container = $.el 'span', className: 'container'
|
||||||
|
$.add container, [$.tn(' '), link]
|
||||||
root = $('.reportbutton', el) or $('span[id]', el)
|
root = $('.reportbutton', el) or $('span[id]', el)
|
||||||
$.after root, container
|
$.after root, container
|
||||||
$.add container, [$.tn(' '), link]
|
else
|
||||||
|
$.add container, [$.tn(' '), link]
|
||||||
return
|
return
|
||||||
|
|
||||||
quoteInline =
|
quoteInline =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
for quote in $$ '.quotelink, .backlink', root
|
for quote in post.quotes.concat post.backlinks
|
||||||
continue unless quote.hash
|
continue unless quote.hash
|
||||||
quote.removeAttribute 'onclick'
|
quote.removeAttribute 'onclick'
|
||||||
$.on quote, 'click', quoteInline.toggle
|
$.on quote, 'click', quoteInline.toggle
|
||||||
@ -2608,8 +2625,8 @@ quoteInline =
|
|||||||
quotePreview =
|
quotePreview =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
for quote in $$ '.quotelink, .backlink', root
|
for quote in post.quotes.concat post.backlinks
|
||||||
$.on quote, 'mouseover', quotePreview.mouseover if quote.hash
|
$.on quote, 'mouseover', quotePreview.mouseover if quote.hash
|
||||||
return
|
return
|
||||||
mouseover: (e) ->
|
mouseover: (e) ->
|
||||||
@ -2668,23 +2685,29 @@ quotePreview =
|
|||||||
if conf['File Info Formatting']
|
if conf['File Info Formatting']
|
||||||
FileInfo.node qp
|
FileInfo.node qp
|
||||||
|
|
||||||
quoteIndicators =
|
quoteOP =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.className is 'inline'
|
return if post.class is 'inline'
|
||||||
# We use contains() so that it works with hidden threads
|
for quote in post.quotes
|
||||||
tid = g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', root).firstChild.id
|
if quote.hash[1..] is post.threadId
|
||||||
for quote in $$ '.quotelink', root
|
|
||||||
unless hash = quote.hash[1..]
|
|
||||||
continue
|
|
||||||
if conf['Indicate OP quote'] and hash is tid
|
|
||||||
# \u00A0 is nbsp
|
# \u00A0 is nbsp
|
||||||
$.add quote, $.tn '\u00A0(OP)'
|
$.add quote, $.tn '\u00A0(OP)'
|
||||||
|
return
|
||||||
|
|
||||||
|
quoteDR =
|
||||||
|
init: ->
|
||||||
|
g.callbacks.push @node
|
||||||
|
node: (post) ->
|
||||||
|
return if post.class is 'inline'
|
||||||
|
for quote in post.quotes
|
||||||
|
unless quote.hash
|
||||||
|
# Make sure this isn't a link to the board we're on.
|
||||||
continue
|
continue
|
||||||
path = quote.pathname
|
path = quote.pathname.split '/'
|
||||||
#if quote leads to a different thread id and is located on the same board (index 0)
|
# If quote leads to a different thread id and is located on the same board.
|
||||||
if conf['Indicate Cross-thread Quotes'] and path.lastIndexOf("/#{tid}") is -1 and path.indexOf("/#{g.BOARD}/") is 0
|
if path[1] is g.BOARD and path[3] isnt post.threadId
|
||||||
# \u00A0 is nbsp
|
# \u00A0 is nbsp
|
||||||
$.add quote, $.tn '\u00A0(Cross-thread)'
|
$.add quote, $.tn '\u00A0(Cross-thread)'
|
||||||
return
|
return
|
||||||
@ -2692,14 +2715,13 @@ quoteIndicators =
|
|||||||
reportButton =
|
reportButton =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
if not a = $ '.reportbutton', root
|
if not a = $ '.reportbutton', post.el
|
||||||
span = $ 'span[id]', root
|
|
||||||
a = $.el 'a',
|
a = $.el 'a',
|
||||||
className: 'reportbutton'
|
className: 'reportbutton'
|
||||||
innerHTML: '[ ! ]'
|
innerHTML: '[ ! ]'
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
$.after span, [$.tn(' '), a]
|
$.after $('span[id]', post.el), [$.tn(' '), a]
|
||||||
$.on a, 'click', reportButton.report
|
$.on a, 'click', reportButton.report
|
||||||
report: ->
|
report: ->
|
||||||
url = "http://sys.4chan.org/#{g.BOARD}/imgboard.php?mode=report&no=#{$.x('preceding-sibling::input', @).name}"
|
url = "http://sys.4chan.org/#{g.BOARD}/imgboard.php?mode=report&no=#{$.x('preceding-sibling::input', @).name}"
|
||||||
@ -2722,10 +2744,10 @@ threadStats =
|
|||||||
else
|
else
|
||||||
151
|
151
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if /\binline\b/.test root.className
|
return if post.isInlined
|
||||||
$.id('postcount').textContent = ++threadStats.posts
|
$.id('postcount').textContent = ++threadStats.posts
|
||||||
return unless $ 'img[md5]', root
|
return unless post.img
|
||||||
imgcount = $.id 'imagecount'
|
imgcount = $.id 'imagecount'
|
||||||
imgcount.textContent = ++threadStats.images
|
imgcount.textContent = ++threadStats.images
|
||||||
if threadStats.images > threadStats.imgLimit
|
if threadStats.images > threadStats.imgLimit
|
||||||
@ -2740,9 +2762,9 @@ unread =
|
|||||||
|
|
||||||
replies: []
|
replies: []
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.hidden or root.className
|
return if post.root.hidden or post.class
|
||||||
unread.replies.push root
|
unread.replies.push post.root
|
||||||
unread.update()
|
unread.update()
|
||||||
|
|
||||||
scroll: ->
|
scroll: ->
|
||||||
@ -2848,9 +2870,9 @@ redirect =
|
|||||||
imgHover =
|
imgHover =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return unless thumb = $ 'img[md5]', root
|
return unless post.img
|
||||||
$.on thumb, 'mouseover', imgHover.mouseover
|
$.on post.img, 'mouseover', imgHover.mouseover
|
||||||
mouseover: ->
|
mouseover: ->
|
||||||
ui.el = $.el 'img'
|
ui.el = $.el 'img'
|
||||||
id: 'ihover'
|
id: 'ihover'
|
||||||
@ -2874,14 +2896,14 @@ imgHover =
|
|||||||
imgGif =
|
imgGif =
|
||||||
init: ->
|
init: ->
|
||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return if root.hidden or !thumb = $ 'img[md5]', root
|
return if post.root.hidden or not post.img
|
||||||
src = thumb.parentNode.href
|
src = post.img.parentNode.href
|
||||||
if /gif$/.test(src) and !/spoiler/.test src
|
if /gif$/.test(src) and !/spoiler/.test src
|
||||||
img = $.el 'img'
|
img = $.el 'img'
|
||||||
$.on img, 'load', ->
|
$.on img, 'load', ->
|
||||||
# Replace the thumbnail once the GIF has finished loading.
|
# Replace the thumbnail once the GIF has finished loading.
|
||||||
thumb.src = src
|
post.img.src = src
|
||||||
img.src = src
|
img.src = src
|
||||||
|
|
||||||
imgExpand =
|
imgExpand =
|
||||||
@ -2889,11 +2911,11 @@ imgExpand =
|
|||||||
g.callbacks.push @node
|
g.callbacks.push @node
|
||||||
imgExpand.dialog()
|
imgExpand.dialog()
|
||||||
|
|
||||||
node: (root) ->
|
node: (post) ->
|
||||||
return unless thumb = $ 'img[md5]', root
|
return unless post.img
|
||||||
a = thumb.parentNode
|
a = post.img.parentNode
|
||||||
$.on a, 'click', imgExpand.cb.toggle
|
$.on a, 'click', imgExpand.cb.toggle
|
||||||
if imgExpand.on and !root.hidden and root.className isnt 'inline'
|
if imgExpand.on and !post.root.hidden and post.class isnt 'inline'
|
||||||
imgExpand.expand a.firstChild
|
imgExpand.expand a.firstChild
|
||||||
cb:
|
cb:
|
||||||
toggle: (e) ->
|
toggle: (e) ->
|
||||||
@ -3103,8 +3125,11 @@ Main =
|
|||||||
if conf['Quote Backlinks']
|
if conf['Quote Backlinks']
|
||||||
quoteBacklink.init()
|
quoteBacklink.init()
|
||||||
|
|
||||||
if conf['Indicate OP quote'] or conf['Indicate Cross-thread Quotes']
|
if conf['Indicate OP quote']
|
||||||
quoteIndicators.init()
|
quoteOP.init()
|
||||||
|
|
||||||
|
if conf['Indicate Cross-thread Quotes']
|
||||||
|
quoteDR.init()
|
||||||
|
|
||||||
$.ready Main.ready
|
$.ready Main.ready
|
||||||
|
|
||||||
@ -3114,8 +3139,10 @@ Main =
|
|||||||
return
|
return
|
||||||
if not $.id 'navtopr'
|
if not $.id 'navtopr'
|
||||||
return
|
return
|
||||||
$.addClass d.body, "chanx_#{VERSION.match(/\.(\d+)/)[1]}"
|
$.addClass d.body, "chanx_#{VERSION.split('.')[1]}"
|
||||||
$.addClass d.body, engine
|
$.addClass d.body, engine
|
||||||
|
for nav in ['navtop', 'navbot']
|
||||||
|
$.addClass $("a[href$='/#{g.BOARD}/']", $.id nav), 'current'
|
||||||
form = $ 'form[name=delform]'
|
form = $ 'form[name=delform]'
|
||||||
threading.thread form.firstElementChild
|
threading.thread form.firstElementChild
|
||||||
Favicon.init()
|
Favicon.init()
|
||||||
@ -3162,7 +3189,6 @@ Main =
|
|||||||
if conf['Index Navigation']
|
if conf['Index Navigation']
|
||||||
nav.init()
|
nav.init()
|
||||||
|
|
||||||
|
|
||||||
nodes = $$ '.op, a + table', form
|
nodes = $$ '.op, a + table', form
|
||||||
Main.node nodes, true
|
Main.node nodes, true
|
||||||
|
|
||||||
@ -3191,11 +3217,26 @@ Main =
|
|||||||
window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js"
|
window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js"
|
||||||
|
|
||||||
node: (nodes, notify) ->
|
node: (nodes, notify) ->
|
||||||
|
posts = []
|
||||||
|
for node in nodes
|
||||||
|
klass = node.className
|
||||||
|
posts.push
|
||||||
|
root: node
|
||||||
|
el: if klass is 'op' then node else $ 'td[id]', node
|
||||||
|
class: klass
|
||||||
|
id: $('input', node).name
|
||||||
|
threadId: g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id
|
||||||
|
isOP: klass is 'op'
|
||||||
|
isInlined: /\binline\b/.test klass
|
||||||
|
filesize: $ '.filesize', node
|
||||||
|
img: $ 'img[md5]', node
|
||||||
|
quotes: $$ '.quotelink', node
|
||||||
|
backlinks: $$ '.backlink', node
|
||||||
for callback in g.callbacks
|
for callback in g.callbacks
|
||||||
try
|
try
|
||||||
callback node for node in nodes
|
callback post for post in posts
|
||||||
catch err
|
catch err
|
||||||
alert err.message if notify
|
alert "4chan X 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 = []
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user