diff --git a/4chan_x.user.js b/4chan_x.user.js
index e365c8737..568af7011 100644
--- a/4chan_x.user.js
+++ b/4chan_x.user.js
@@ -90,9 +90,8 @@
},
Filtering: {
'Anonymize': [false, 'Make everybody anonymous'],
- 'Filter': [false, 'Self-moderation placebo'],
- 'Filter OPs': [false, 'Filter OPs along with their threads'],
- 'Recursive Filtering': [false, 'Filter replies of filtered posts, recursively'],
+ 'Filter': [true, 'Self-moderation placebo'],
+ 'Recursive Filtering': [true, 'Filter replies of filtered posts, recursively'],
'Reply Hiding': [true, 'Hide single replies'],
'Thread Hiding': [true, 'Hide entire threads'],
'Show Stubs': [true, 'Of hidden threads / replies']
@@ -119,6 +118,7 @@
'Cooldown': [true, 'Prevent "flood detected" errors.'],
'Persistent QR': [false, 'The Quick reply won\'t disappear after posting.'],
'Auto Hide QR': [true, 'Automatically hide the quick reply when posting.'],
+ 'Open Reply in New Tab': [false, 'Open replies in a new tab that are made from the main board.'],
'Remember QR size': [false, 'Remember the size of the Quick reply (Firefox only).'],
'Remember Subject': [false, 'Remember the subject field, instead of resetting after posting.'],
'Remember Spoiler': [false, 'Remember the spoiler state, instead of resetting after posting.'],
@@ -136,14 +136,15 @@
}
},
filter: {
- name: '',
- tripcode: '',
- email: '',
- subject: '',
- comment: '',
- filename: '',
- filesize: '',
- md5: ''
+ name: ['# Filter any namefags:', '#/^(?!Anonymous$)/'].join('\n'),
+ tripcode: ['# Filter any tripfags', '#/^!/'].join('\n'),
+ email: ['# Filter any e-mails that are not `sage` on /a/ and /jp/:', '#/^(?!sage$)/;boards:a,jp'].join('\n'),
+ subject: ['# Filter Generals on /v/:', '#/general/i;boards:v;op:only'].join('\n'),
+ comment: ['# Filter Stallman copypasta on /g/:', '#/what you\'re refer+ing to as linux/i;boards:g'].join('\n'),
+ filename: [''].join('\n'),
+ dimensions: ['# Highlight potential wallpapers:', '#/1920x1080/;op:yes;highlight;top:no;boards:w,wg'].join('\n'),
+ filesize: [''].join('\n'),
+ md5: [''].join('\n')
},
sauces: ['http://iqdb.org/?url=$1', 'http://www.google.com/searchbyimage?image_url=$1', '#http://tineye.com/search?url=$1', '#http://saucenao.com/search.php?db=999&url=$1', '#http://3d.iqdb.org/?url=$1', '#http://regex.info/exif.cgi?imgurl=$2', '# uploaders:', '#http://imgur.com/upload?url=$2', '#http://omploader.org/upload?url1=$2', '# "View Same" in archives:', '#http://archive.foolz.us/a/image/$3/', '#http://archive.installgentoo.net/g/image/$3'].join('\n'),
time: '%m/%d/%y(%a)%H:%M',
@@ -532,86 +533,126 @@
};
filter = {
- regexps: {},
- callbacks: [],
+ filters: {},
init: function() {
- var f, filter, key, m, _i, _len;
+ var boards, filter, hl, key, op, regexp, top, _i, _len, _ref, _ref2, _ref3, _ref4, _ref5;
for (key in config.filter) {
- if (!(m = conf[key].match(/^\/.+\/\w*$/gm))) continue;
- this.regexps[key] = [];
- for (_i = 0, _len = m.length; _i < _len; _i++) {
- filter = m[_i];
- f = filter.match(/^\/(.+)\/(\w*)$/);
+ this.filters[key] = [];
+ _ref = conf[key].split('\n');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ filter = _ref[_i];
+ if (filter[0] === '#') continue;
+ if (!(regexp = filter.match(/\/(.+)\/(\w*)/))) continue;
+ filter = filter.replace(regexp[0], '');
+ boards = ((_ref2 = filter.match(/boards:([^;]+)/)) != null ? _ref2[1].toLowerCase() : void 0) || 'global';
+ if (boards !== 'global' && boards.split(',').indexOf(g.BOARD) === -1) {
+ continue;
+ }
try {
- this.regexps[key].push(RegExp(f[1], f[2]));
+ regexp = RegExp(regexp[1], regexp[2]);
} catch (e) {
alert(e.message);
+ continue;
}
+ op = ((_ref3 = filter.match(/[^t]op:(yes|no|only)/)) != null ? _ref3[1].toLowerCase() : void 0) || 'no';
+ if (hl = /highlight/.test(filter)) {
+ hl = ((_ref4 = filter.match(/highlight:(\w+)/)) != null ? _ref4[1].toLowerCase() : void 0) || 'filter_highlight';
+ top = ((_ref5 = filter.match(/top:(yes|no)/)) != null ? _ref5[1].toLowerCase() : void 0) || 'yes';
+ top = top === 'yes';
+ }
+ this.filters[key].push(this.createFilter(regexp, op, hl, top));
}
- this.callbacks.push(this[key]);
+ if (!this.filters[key].length) delete this.filters[key];
}
- return g.callbacks.push(this.node);
+ if (Object.keys(this.filters).length) return g.callbacks.push(this.node);
+ },
+ createFilter: function(regexp, op, hl, top) {
+ return function(root, value, isOP) {
+ var firstThread, thisThread;
+ if (isOP && op === 'no' || !isOP && op === 'only') return false;
+ if (!regexp.test(value)) return false;
+ if (hl) {
+ $.addClass(root, 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.previousSibling);
+ }
+ return true;
+ };
},
node: function(root) {
- if (!root.className) {
- if (filter.callbacks.some(function(callback) {
- return callback(root);
- })) {
- return replyHiding.hideHide($('td:not([nowrap])', root));
- }
- } else if (root.className === 'op' && !g.REPLY && conf['Filter OPs']) {
- if (filter.callbacks.some(function(callback) {
- return callback(root);
- })) {
- return threadHiding.hideHide(root.parentNode);
- }
+ var isOP, key, klass;
+ klass = root.className;
+ if (/\binlined\b/.test(klass)) return;
+ if (!(isOP = klass === 'op')) root = $('td[id]', root);
+ for (key in filter.filters) {
+ if (filter.test(root, key, isOP)) return;
}
},
- test: function(key, value) {
- return filter.regexps[key].some(function(regexp) {
- return regexp.test(value);
- });
+ test: function(root, key, isOP) {
+ var filter, value, _i, _len, _ref;
+ value = this[key](root, isOP);
+ if (value === false) return false;
+ _ref = this.filters[key];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ filter = _ref[_i];
+ if (filter(root, value, isOP)) return true;
+ }
+ return false;
},
- name: function(root) {
+ name: function(root, isOP) {
var name;
- name = root.className === 'op' ? $('.postername', root) : $('.commentpostername', root);
- return filter.test('name', name.textContent);
+ name = isOP ? $('.postername', root) : $('.commentpostername', root);
+ return name.textContent;
},
tripcode: function(root) {
var trip;
- if (trip = $('.postertrip', root)) {
- return filter.test('tripcode', trip.textContent);
- }
+ if (trip = $('.postertrip', root)) return trip.textContent;
+ return false;
},
email: function(root) {
var mail;
- if (mail = $('.linkmail', root)) return filter.test('email', mail.href);
+ if (!(mail = $('.linkmail', root))) return mail.href;
+ return false;
},
- subject: function(root) {
+ subject: function(root, isOP) {
var sub;
- sub = root.className === 'op' ? $('.filetitle', root) : $('.replytitle', root);
- return filter.test('subject', sub.textContent);
+ sub = isOP ? $('.filetitle', root) : $('.replytitle', root);
+ return sub.textContent;
},
comment: function(root) {
- return filter.test('comment', ($.el('a', {
+ return ($.el('a', {
innerHTML: $('blockquote', root).innerHTML.replace(/
/g, '\n')
- })).textContent);
+ })).textContent;
},
filename: function(root) {
var file;
- if (file = $('.filesize span', root)) {
- return filter.test('filename', file.title);
- }
+ if (file = $('.filesize > span', root)) return file.title;
+ return false;
+ },
+ dimensions: function(root) {
+ var span;
+ if (span = $('.filesize', root)) return span.textContent.match(/\d+x\d+/)[0];
+ return false;
},
filesize: function(root) {
var img;
- if (img = $('img[md5]', root)) return filter.test('filesize', img.alt);
+ if (img = $('img[md5]', root)) return img.alt;
+ return false;
},
md5: function(root) {
var img;
- if (img = $('img[md5]', root)) {
- return filter.test('md5', img.getAttribute('md5'));
- }
+ if (img = $('img[md5]', root)) return img.getAttribute('md5');
+ return false;
}
};
@@ -1223,7 +1264,7 @@
$.before(form, link);
}
g.callbacks.push(this.node);
- if (engine === 'webkit') {
+ if (/chrome/i.test(navigator.userAgent)) {
qr.status({
ready: true
});
@@ -1379,7 +1420,7 @@
if (e != null) e.preventDefault();
qr.open();
if (!g.REPLY) {
- $('select', qr.el).value = $.x('ancestor::div', this).firstChild.id;
+ $('select', qr.el).value = $.x('ancestor::div[@class="thread"]', this).firstChild.id;
}
id = this.previousElementSibling.hash.slice(1);
text = ">>" + id + "\n";
@@ -1678,7 +1719,7 @@
});
ta.style.cssText = $.get('qr.size', '');
}
- mimeTypes = $('.rules').textContent.match(/: (.+) /)[1].toLowerCase().replace(/\w+/g, function(type) {
+ mimeTypes = $('.rules').firstChild.textContent.match(/: (.+) /)[1].toLowerCase().replace(/\w+/g, function(type) {
switch (type) {
case 'jpg':
return 'image/jpeg';
@@ -1832,14 +1873,14 @@
reader.readAsBinaryString(reply.file);
return;
}
- if (engine === 'webkit') {
+ if (/chrome/i.test(navigator.userAgent)) {
qr.message.post(post);
return;
}
return qr.message.send(post);
},
response: function(html) {
- var b, doc, err, node, persona, postNumber, reply, thread, _, _ref;
+ var b, doc, err, node, open, persona, postNumber, reply, thread, _, _ref;
doc = $.el('a', {
innerHTML: html
});
@@ -1887,6 +1928,10 @@
} else {
qr.cooldown.auto = qr.replies.length > 1;
qr.cooldown.set(/sage/i.test(reply.email) ? 60 : 30);
+ if (conf['Open Reply in New Tab'] && !g.REPLY && !qr.cooldown.auto) {
+ open = GM_openInTab || window.open;
+ open("http://boards.4chan.org/" + g.BOARD + "/res/" + thread + "#" + postNumber, "_blank");
+ }
}
if (conf['Persistent QR'] || qr.cooldown.auto) {
reply.rm();
@@ -1899,7 +1944,7 @@
message: {
send: function(data) {
var host, window;
- if (engine === 'webkit') {
+ if (/chrome/i.test(navigator.userAgent)) {
qr.message.receive(data);
return;
}
@@ -2071,7 +2116,7 @@
\
Sauce is disabled.# will be ignored.# will be ignored.\
Filter is disabled.# will be ignored./weeaboo/i will filter posts containing `weeaboo` case-insensitive.\
+ boards:a,jp;.op:only;, op:no; or op:yes;.highlight; or hightlight:wallpaper;.top:yes or top:no.Name:
Tripcode:
E-mail:
Subject:
Comment:
Filename:
Image dimensions:
Filesize:
Image MD5:
Sauce is disabled.# will be ignored.# will be ignored.
Filter is disabled.# will be ignored./weeaboo/i will filter posts containing `weeaboo` case-insensitive.
+ boards:a,jp;.op:only;, op:no; or op:yes;.highlight; or hightlight:wallpaper;.top:yes or top:no.Name:
Tripcode:
E-mail:
Subject:
Comment:
Filename:
Image dimensions:
Filesize:
Image MD5: