jehan / Australian Financial Review Paywall Bypass

// ==UserScript==
// @name        Australian Financial Review Paywall Bypass
// @description	Resets article limit for Australian Financial Review - afr.com and Smart Investor - afrsmartinvestor.com.au
// @include     /^https?://(\w+\.)?afr.com/.*$/
// @include     /^https?://(\w+\.)?afrsmartinvestor.com.au/.*$/
// @include     /^https?://(\w+\.)?misaustralia.com.au/.*$/
// @require		http://code.jquery.com/jquery-latest.min.js
// @grant       GM_log
// @grant       GM_addStyle
// @grant		GM_xmlhttpRequest
// @run-at		document-start
// @version     3.1
// ==/UserScript==

GM_addStyle(".subscription-overlay { display: none!important; }");
GM_addStyle(".cq-article-content-paras p { color: inherit!important; }");
 
function findNodesByClass(nodes, className, partial){
	className = className.toLowerCase();
	if(typeof partial == 'undefined')
		var partial = false;
	var foundNodes = [];
	if(nodes)
		for(var i = 0; i < nodes.length; i++){
			if(!('classList' in nodes[i]))
				continue;
			for(var j = 0; j < nodes[i].classList.length; j++)
				if(partial){
					if(nodes[i].classList.item(j).toLowerCase().indexOf(className)!=-1)
						foundNodes.push(nodes[i]);
				}
				else
					if(nodes[i].classList.item(j) == className)
						foundNodes.push(nodes[i]);
		}
	return foundNodes;
}

fns = [
function(mutation){
	removeClassFromNodes(mutation, 'paywall', true);
	return false;
},

function(mutation){
	removeClassFromNodes(mutation, 'bind-hagrid', true);
	return false;
},

function(mutation){
	procNodesByClass(mutation, 'subscription-overlay',
		function(node){
			node.parentNode.removeChild(node);
			return true;
		}
	);
}
];

function removeClassFromNodes(mutation, class_, partial){
	if(typeof partial == 'undefined')
		var partial = true;
	procNodesByClass(mutation, class_, function(node){
		node.className = node.className.replace( 
			new RegExp(partial ?
				('[/w-]*' + class_ + '[/w-]*') :
				('\b' + class_ + '\b'),
				'gi'),
			'' );
			return true;
		}
	, partial);
}

function procNodesByClass(mutation, class_, callback, partial){
	var nodes = [];
	
	if(mutation.addedNodes.length)
		nodes = nodes.concat(findNodesByClass(mutation.addedNodes, class_, partial));
	
	if(mutation.attributeName && (mutation.attributeName == 'class') && (mutation.target.className.indexOf(class_)!==-1)){
		console.log('mutation class:' + mutation.target.className);
		nodes = nodes.push(mutation.target);
	}

	for(var i = 0; i < nodes.length; i++)
		if(callback(nodes[i])===false){
			console.log("Error in callback");
			return false;
		}
	return nodes.length;
}

function doFns(mutation){
	for(var i in fns)
		if(fns[i](mutation)===true)
			delete fns[i];
	if(fns.length == 0)
		observer.disconnect();
}

var observer = new MutationObserver(function(mutations) {
	mutations.forEach(doFns);
});
 
observer.observe(document.documentElement,
	{ attributes: true, childList: true, subtree: true, attributeFilter: ['class']}
);