Walla Enhancer

By Lior Zur Last update May 20, 2007 — Installed 699 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
// ==UserScript==
// @name           Walla Enhancer
// @namespace      liorzur
// @description    Lets you read all articles in the same page at www.walla.co.il
// @include        http://*.walla.co.il/
// ==/UserScript==
//########################################################################
// Walla Enhancer
// Version 0.11
//
//
// By: Lior Zur, 2007
// Released under the GPL license (http://www.gnu.org/copyleft/gpl.html)
// If you reuse parts of the code, please give credit. Thanks.
// Improvements & suggestions are welcome.
//
// See userscripts.org page for full description and changelog.
//
//########################################################################

var currentURL = location.href;
var allElements, thisElement, newElement;
var f;
var someHTML;

// ==== Functions ====
function $(id) {
  return document.getElementById(id);
}
function $x(p, context) {
  if (!context) context = document;
  var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item);
  return arr;
}
function createEl(elObj, parent) { //By Arvid
  var el;
  if (typeof elObj == 'string') {
	  el = document.createTextNode(elObj);
  } else {
	  el = document.createElement(elObj.n);
	  if (elObj.a) {
		  attributes = elObj.a;
		  for (var key in attributes) {
			  if (key.charAt(0) == '@')  el.setAttribute(key.substring(1), attributes[key]);
			  else  el[key] = attributes[key];
		  }
	  }
	  if (elObj.evl) { el.addEventListener(elObj.evl.type, elObj.evl.f, elObj.evl.bubble);  }
	  if (elObj.c) { elObj.c.forEach(function (v, i, a) { createEl(v, el); });  }
  }
  if (parent) parent.appendChild(el);
  return el;
}
function insertAfter(newNode, node) {
  return node.parentNode.insertBefore(newNode, node.nextSibling);
}
function removeNode (element){
	if (element)
		element.parentNode.removeChild(element);
}
function removeElements (xPath) {
	var thisElement, allElements = document.evaluate(xPath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	for (f = 0; f < allElements.snapshotLength; f++) {
    thisElement = allElements.snapshotItem(f);
    thisElement.parentNode.removeChild(thisElement);
	}
	if (allElements.snapshotLength > 0) return true; 
		else return false;
}
function addClass (element, className ) {
	var currentClass = element.getAttribute ("class") || '';
	if (!currentClass) currentClass = "";
	if (currentClass.indexOf(className) == -1)
		element.setAttribute ("class", currentClass + " " + className);
}
function removeClass (element, className ) {
	var currentClass = element.getAttribute ("class") || '';
	if (currentClass.indexOf(className) != -1)
		element.setAttribute ("class", currentClass.replace(className, "").replace(/^\s+/, '').replace(/\s+$/, ''));
}
//Two custom string functions by me
String.prototype.trimUpTo = function (trimTexts){
   if (typeof trimTexts == 'string') trimTexts = [trimTexts];
	var trimPoint, s = this.toString();
	for (var i=0; i < trimTexts.length; i++){
		trimPoint = s.indexOf(trimTexts[i]);
		if (trimPoint != -1 ) return s.substring(trimPoint + trimTexts[i].length ,s.length);
	}
	return "";
}
String.prototype.trimFrom = function (trimTexts){
   if (typeof trimTexts == 'string') trimTexts = [trimTexts];
	var trimPoint, s = this.toString();
	for (var i=0; i < trimTexts.length; i++){
		trimPoint = s.lastIndexOf(trimTexts[i]);
		if (trimPoint != -1 ) return s.substring(0, trimPoint);
	}
	return "";
}
// ==== End Functions ====

//feature is active only inside main page + printed list articles.
if ( 1==1 ){

//## Create the bottom bar (with checkbox).
GM_addStyle('div.gmbottombar {  background-color: #fef8c7;' +
' border: 1px solid #eab742; width: 630px; margin-left: auto; margin-right: auto;'+
' font-size: 11px; color: #cc5401; padding: 2px 15px;}' +
' div.gmbottombar form {display: inline;}'+
' div.gmbottombar a {color: blue; text-decoration: underline;}');
newElement = document.createElement('div');
newElement.innerHTML = '<div class="gmbottombar"><form name="gmbottomform" action=""><input type="checkbox" name="gmarticlesenable" id="gmbottomcheckbox" value="no" align="middle" /> Open articles inside this page <b>(Walla Enhancer)</b></form></div>';
document.body.appendChild(newElement);

//Checkbox code.
var locateCheckBox = $("gmbottomcheckbox");
locateCheckBox.addEventListener('click', function(event) {
			GM_setValue ("bIsItEnabled", this.checked);
			event.preventDefault();
			window.location.reload();
}, true); 

//## See whether "Is It Enabled"; change checkbox accordingly.
var bIsItEnabled =  GM_getValue("bIsItEnabled", true); //default - enabled.
locateCheckBox.checked = bIsItEnabled;
locateCheckBox = null;

//---------------- If feature is enabled ----------------
if (bIsItEnabled) {

//## Stop auto-refresh of the page.
//	Taken and modified from Pirateshark's http://userscripts.org/scripts/show/3587
//	who in turn took it from http://dunck.us/collab/DisableAutoRefresh
allElements = $x("//meta[@http-equiv='Refresh']|//meta[@http-equiv='refresh']|//meta[@http-equiv='REFRESH']");
allElements.forEach (function(e){
	var content = e.getAttribute("content");
	var stopTimer = window.setTimeout("window.stop();",(content-1)*1000); // in case load hasn't finished when the refresh fires
	window.addEventListener("load", function(){ try { window.clearTimeout(stopTimer); } catch(ex) {} window.stop(); }, true);
});

//## Create the necessary styles.
var imgLoadingAnimation   = "data:image/gif;base64,R0lGODlhCgAKAIABADo7VP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgABACwAAAAACgAKAAACEgSCaZuxj56c1DiqZLt2Xw8GBQAh+QQJCgABACwAAAAACgAKAAACEYyPmQDKj540strLAj52QVMAACH5BAkKAAEALAAAAAAKAAoAAAIQjI+pywignnRyhoqzfleHAgAh+QQJCgABACwAAAAACgAKAAACDoyPqcvtCYCKFNFrrtYFACH5BAUKAAEALAAAAAAKAAoAAAIMjI+py+0PDQBqWmQLADs=";
var imgBackgroundGradient = "data:image/gif;base64,R0lGODlhCgAPALMAAO7a/eLC/fjw/vXp/t+6/OrS/fv2//37/9Oh+9Wm++bK/dGd+/Hi/tuz/Nis/AAAACH5BAAAAAAALAAAAAAKAA8AAAQvcMlJkb046c2d/2AjjiRhnmigrqzivnAhzzRg3zij7/zg/0CBcEg0GI/Ig3LJjAAAOw==";
GM_addStyle("a.gmclosed {  background-color: #fdfcec ! important; " + //
		"border-bottom: #8f14d1 solid 1px ! important; "+
		"text-decoration: none ! important;}"+
		"a.gmopen {  background-color: #d19dfb ! important; " + //
		"border-bottom: 0 ! important; "+
		"text-decoration: none ! important;}"+
		"div.gmopenarticle {  background: white repeat-x top left url(" + imgBackgroundGradient + ");" + //
		" border-bottom: #d19dfb solid 2px }"+
		"div.gmloadingarticle {  background: no-repeat top left url("+ imgLoadingAnimation + ");" + //
		" padding: 0 0 0 20px; text-align: left; display: block; width: 17em; margin-left: auto; margin-right: auto;"+
		" font-size: 12px; color: #370f6e; }"+
		//.gmclosebutton (The 'Close' button)
		"a.gmclosebutton { background-color: #cdb1e1; display: block; padding: 2px; width: 5em; text-align: center;"+
		"font-size: 12px; font-weight: bold; color: white; margin: 5px 0;} "+
		"a.gmclosebutton:hover {background-color: #D88AFF;}"+
		"");
var contentErrorMessage = '<div style="padding: 5px; background-color: #f7c8c5; text-align: center; direction: ltr; font-size: 12px;">Sorry, there was a problem loading the article.<br />Please try again, or try another link. If you conclude the script has broken, report to me.<br /><br /><b>Note:</b> You can always middle-click the link to open it in a new tab!</div>';
var contentLoadingMessage = '<div class = "gmabsolutediv" style="padding: 10px; background-color: #e8e0fa; text-align: center; direction: ltr;"><div class="gmloadingarticle">Loading the article, please wait...</div></div>';




// ==== Start Site Customization Block ====

var siteMimeType = 'text/html; charset=windows-1255';

function processResponse (responseHTML) {
	// Highly modifiable function for different sites.
	// Return processed string, or <null> for error
	var s = responseHTML.trimUpTo('<div class="w5b"').trimFrom("function openEmail() {");
	if (s == "") return null;
	return '<div style="display:block; height:15px; width:15px;">.</div><div class="w5b"' + s + "</script>";
}

function generateLinkID(url){
// Produce unique ID based on URL
// (Essentially could be a random number generator! (take url as seed?))
	if (url) {
		var reMatches = /(\d{6,})/.exec(url);
		if (!reMatches) return null; //if no ID  -- open link as usual.
		return "GM" + reMatches[1];
	}
}
function processLink(element){
// PROCESS each link, and TEST if it's good (return false if not).
	if (!(/(\d{6,})/.exec(element.href))) return false;  //TEST: Is this a link to an article? (Xpath can't do this...)
	element.parentNode.style.fontWeight = "normal"; //Fix bold table cells in Walla
	return true;
}
function displayLoading (element){
	element.innerHTML =  contentLoadingMessage;
}
function displayError (element){
	element.innerHTML =  contentErrorMessage;
}
function displayArticle (element, processedHTML){
	element.innerHTML = processedHTML;
	addClass (element, "gmopenarticle")	
}

var myXPath = "//a[contains(@class,'w3b')]" //contains(@href,'/?w=/') and 
+"|//a[contains(@class,'w2b')]";

//make sure article images stay on top (aesthetics)
$x("//td[@width='82']|//img[@width=80]/parent::a/parent::td").forEach ( function (thisElement, i, c){ thisElement.vAlign = "top"; });

// ==== End Site Customization Block ====

allElements = $x(myXPath);
allElements.forEach ( function (thisElement, i, c){
	var _originalLink = thisElement; // (Remember this <A> node)
	var _originalDiv = null;
	var _isLinkOpen = false;

	function closeLink (){
		if (!_isLinkOpen) return false;
		_isLinkOpen = false;
		removeClass (_originalLink,"gmopen");
		addClass    (_originalLink,"gmclosed");
		removeNode  (_originalDiv);
		_originalDiv = null;
	}
	function event_clickClose (event) {
		event.preventDefault ();
		var divHeight = _originalDiv.clientHeight;
		var windowHeight = window.innerHeight;
		if (divHeight >= windowHeight) { 
			var linkID = generateLinkID(_originalLink.href);
			_originalLink.setAttribute("id", linkID);
			location.href = "#" + linkID;
		}
		closeLink ();
	}
	function event_clickLink (event) {
		// --- On Click function for each link. ---
		event.preventDefault();
		event.stopPropagation();
		if (!_isLinkOpen){
			_isLinkOpen = true;
			removeClass (_originalLink, "gmclosed");
			addClass    (_originalLink, "gmopen");

			// Create the content div, and display "Loading" message.
			_originalDiv = document.createElement('div'); //remember it!
			displayLoading (_originalDiv);
			addClass       (_originalDiv, "gmcontaineropenarticle");
			insertAfter    (_originalDiv, _originalLink);

			GM_xmlhttpRequest({
				method: 'GET',
				url: _originalLink.href,
				headers: {'User-agent': 'Mozilla/4.0 (compatible)', 'Accept': 'text/xml,application/xml,application/xhtml+xml,text/html',},
				overrideMimeType: siteMimeType,
				onerror: event_onerror,
				onload: event_onload
			});
	
		} else { 
			closeLink ();
		}
		return false;
	}
	function event_onerror (responseDetails) {
		if (!_isLinkOpen) return false;
		displayError (_originalDiv);
		return false;
	}
	function event_onload (responseDetails){
		if (!_isLinkOpen) return false;
		// If HTTP error, exit.
		if (responseDetails.status > 207) {
			displayError (_originalDiv);
			return false;
		}
		var responseHTML = responseDetails.responseText;
		var processedHTML = processResponse(responseHTML);
		if (processedHTML) {
			displayArticle (_originalDiv, processedHTML);
			// Create Close button.
			hebrewClose = String.fromCharCode(1505,1490,1497,1512,1492); //'Sgira'
			createEl( {n: 'a', a: {'@class': 'gmclosebutton', textContent: hebrewClose, href: '#' },
			             evl: {type: 'click', f: event_clickClose, bubble: true}} , _originalDiv);
		} else {
			displayError (_originalDiv);
		}
	}
	if (!processLink(_originalLink)) return true;
	addClass (_originalLink, "gmclosed");
	_originalLink.addEventListener('click', event_clickLink ,true);
});// End forEach <a>

}//End if (is it enabled)
} //end if (only main page + article pages)