NeoGAF: Blacklists

Experimental blocking based on user-set blacklists

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @id             neo-blacklist
// @name           NeoGAF: Blacklists
// @namespace      hateradio)))
// @author         hateradio
// @version        1.1
// @description    Experimental blocking based on user-set blacklists
// @include        http*://*.neogaf.com/forum/*
// @match          *://*.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();

}());