// ==UserScript==
// @id neo-blacklist
// @name NeoGAF: Blacklists
// @namespace hateradio)))
// @author hateradio
// @version 1
// @description Experimental blocking based on user-set blacklists
// @include http://*.neogaf.com/forum/*
// @match http://*.neogaf.com/forum/*
// @updated 28 Feb 2016
// @grant unsafeWindow
// @run-at document-end
// ==/UserScript==
/*jslint indent: 4, maxerr: 50, browser: true, devel: true, sub: false, fragment: false, nomen: true, plusplus: true, bitwise: true, regexp: true, newcap: true */
//var blacklist = ['NSFW', 'G/A/F/?', 'Pop*', 'Ariana Grande', 'Iggy', 'Nicki', 'Police', 'WorldStar', 'OT', 'Do you*', 'Help me*', 'bug', '...', 'Florida', 'GAF, I just*', 'LTTP'];
(function () {
'use strict';
/** Array intersection */
function intersectClassList(a, cl) {
// console.log(a, cl);
return a.filter(function (e) { return cl.contains(e); });
}
/** Basic functionallity to find an element's parent
* The parentTag can contain a CSS selector, but it has to match exactly
*
* Eg: 'div.post' and 'p.purple'
*
* A 'div' has to have 'post' as a class name
* A 'p' has to have a 'purple' class
*
* parentTag can also contiain multiple class names
*
* Eg: 'div.post.alt2'
* Where 'post' and 'alt2' are class selectors
*/
function findParent(el, parentTag) {
var splits = parentTag.toLowerCase().split('.'),
tag = splits[0].trim(),
classList = splits.slice(1).filter(function (e) { return !!e.trim(); });
// console.log("Tag:", tag, classList);
function loop(parent) {
var ptag = parent.tagName.toLowerCase(), inter;
if (classList.length > 0) {
inter = intersectClassList(classList, parent.classList);
// console.log('Inter:', tag, inter);
// console.log(parent, parent.tagName.toLowerCase() === tag, inter.length === classList.length);
if (ptag === tag && inter.length === classList.length) {
// console.log('found parent');
return parent;
}
} else if (ptag === tag) {
return parent;
}
if (parent.parentElement) {
return loop(parent.parentElement);
}
return null;
}
return tag ? loop(el.parentElement) : null;
}
function Block(selector, parent, blacklist) {
if (!selector) {
return;
}
this.selector = selector;
this.parent = parent;
this.blacklist = blacklist;
}
Block.createFromBlacklist = function (set) {
return new Block[set.type](set.selector, set.parent, set.blacklist);
};
Block.prototype.toggle = function (display) {
display = !!display;
var i, j, p, s = document.querySelectorAll(this.selector), style = display ? '' : 'none';
for (i = 0; i < s.length; i++) {
for (j = 0; j < this.blacklist.length; j++) {
if (this.compare(s[i].textContent, this.blacklist[j])) {
p = findParent(s[i], this.parent);
// console.log(p);
if (p) {
p.style.display = style;
p.dataset.gmhide = display;
}
}
}
}
};
Block.prototype.hide = function () {
this.toggle(false);
};
Block.prototype.show = function () {
this.toggle(true);
};
/** Only matches words that are identical to some text */
Block.Exact = function (selector, parent, blacklist) {
Block.call(this, selector, parent, blacklist);
};
/** Simply matches word "OT" inside of phrase "Marvel |OT| jk Marvel doesn't have an OT" */
Block.Simple = function (selector, parent, blacklist) {
Block.call(this, selector, parent, blacklist);
};
/** Uses RegExps to match text; plain text is converted to a RegExp */
Block.Complex = function (selector, parent, blacklist) {
Block.call(this, selector, parent, blacklist);
};
Block.Exact.prototype = new Block();
Block.Simple.prototype = new Block();
Block.Complex.prototype = new Block();
Block.Exact.prototype.compare = function (text, word) {
return text.trim() === word.trim();
};
Block.Simple.prototype.compare = function (text, word) {
return text.trim().toLowerCase().contains(word.trim().toLowerCase());
};
Block.Complex.prototype.compare = function (text, regexp) {
var r = regexp instanceof RegExp ? regexp : new RegExp(regexp, 'ig');
return r.test(text);
};
/** Modify and add items to the set */
var massBlock = {
set: {
userThreads: { // block threads from these users
selector: '.threadbit.alt1 td[nowrap]:nth-child(3)',
parent: 'tr', // hide the table row that the element belongs to
blacklist: ['user1', 'user2', 'etc-users'], // Block some usernames
type: 'Exact'
},
topics: { // block threads with these phrases
selector: 'td[id^="td_threadtitle"]',
parent: 'tr',
blacklist: ['NSFW', 'G/A/F', 'Pop', 'Ariana Grande', 'Iggy', 'Nicki', 'Police', 'WorldStar', 'OT', 'Do you', 'Help me', 'bug', '...', 'Florida', 'GAF, I just', 'LTTP', 'Marvel'],
type: 'Simple'
},
posts: { // block posts from these users
selector: '.postbit-details-username a',
parent: 'div.postbit',
blacklist: ['user1', 'user2', 'etc-users'],
type: 'Exact'
},
RegExample: { // block using regular expressions
selector: '.RegExample',
parent: 'div.RegExample',
blacklist: [/badWord/ig, /an*/ig, /LOL/g],
type: 'Complex'
}
},
main: function () {
var s;
for (s in this.set) {
if (this.set.hasOwnProperty(s)) {
Block.createFromBlacklist(this.set[s]).hide();
}
}
}
};
massBlock.main();
}());