Wiki sidebar tweak

By Jordi De Groof Last update Apr 30, 2009 — Installed 2,285 times. Daily Installs: 3, 5, 3, 6, 3, 4, 4, 3, 4, 3, 2, 5, 4, 3, 4, 3, 4, 4, 4, 2, 6, 4, 3, 4, 4, 3, 2, 6, 2, 5, 3, 3

There are 6 previous versions of this script.

// ==UserScript==
// @name           Wiki sidebar tweak
// @description    Keep the sidebar of Wiki's always visible and keep the languages you know on top in the 'other languages'-box
// @namespace      http://www.netvibes.com/jordi
// @author         Jordi De Groof
// @version        1.4.1
// @include        *wiki*
// ==/UserScript==

/**
* Known bugs: language adjustment not working on wikisource (http://en.wikisource.org)
* Opera only: language adjustment can't be stored
**/

/**
 CHANGELOG:
**
1.4 (April 25, 2009)
Implemented moving of the elements in the sidebar
**
1.3.1
Fixed invisible search suggestions
**
1.3 (April 21, 2009)
Placed links on top of the page in the sidebar
**
1.2 (March 18, 2009)
Improved displaying of sidebar  with limited screen estate available
Persistent hiding of sidebar items
**
1.1.1 (November 8, 2008)
Fixed bug concerning featured articles in the language highlight function
**
1.1 (June 13, 2008)
Added compatibility with opera (when a slightly modified version of  'Emulate Greasemonkey functions' (http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js) is installed)
**
1.0.1 (February 8, 2007)
Bug Fixes:
 - Fixed when no favourite languages were selected, sidebar tweak would crash and exit
 - When Firefox bug 235441 (https://bugzilla.mozilla.org/show_bug.cgi?id=235441) is fixed, the script will continue to work normally (changed useCapture to false in addEventListener calls)
 - When the window is to small to show all the languages, the non-referred languages are shown completely, without scrollbar, like in the previous version could happen
 - When there is more space then languages, the language box has the height of the languages it contains, no longer of the window height
**
1.0 (February 3, 2007)
Initial release, a merge of two of my previous scripts
**/

(function()
{
	var arrowOpened= "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%06%00%00%00%1F%F3%FFa%00%00%00%04sBIT%08%08%08%08%7C%08d%88%00%00%00%19tEXtSoftware%00www.inkscape.org%9B%EE%3C%1A%00%00%00%AFIDAT8%8D%C5%D3!%0E%C20%14%87%F1%AF%08B0s%3B%00%1E%B0(%14%9A%EC%0AX%3CG%E0%04X%0C'%E0%26%04MP%18%E4%1CA%10%FE%98%07%81n%2B%AC%134%A9%EA%FB~%E2%25u%92hrZ%8Dj%C0%01s%20%8D%EC%CF%00%19%A0%88%7B%03%C6%D8%0E6%11%C0B%12O%20%01N5%E2%AD%24%5E%80!%13%E0%FEC%7C%04%92%02%60%C8%EAK%7C%01%86%1F%8D%07t%81C%00%98%BD%CF%17%00CF%B6a%3F%5E%FB%B3%A5%80!K%2F%DE%01%9D%3A%40%1B%D8%5B%9C%03%BD%B2%B9J%C0%90%3Ep%05%A6U3A%C0%90A%E8%5D%12%EE%EF%BF%F1%01%92%7BFe%8CK8%EE%00%00%00%00IEND%AEB%60%82";
	var arrowClosed= "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%06%00%00%00%1F%F3%FFa%00%00%00%04sBIT%08%08%08%08%7C%08d%88%00%00%00%19tEXtSoftware%00www.inkscape.org%9B%EE%3C%1A%00%00%00%8DIDAT8%8D%A5%D3%AD%0E%81a%18%06%E0k%23%086%9B%A4%3B%04%DD%01(NF%D6m%8E%C0%A6%9A%E4%18%9C%81%A4%8A_%D6%8D%5B%FA6%E9%C3%FB%86%3B%3C%E1%B9%C2%F3%23%89%24%B0%C7%A0%AD%7F%8D%0F%20%B8%60Z%03%04w%2Ck%80%E0%85%0Dz%A5%40%9B3%265%40%D0%60%5E%03%04%0F%ACj%806'%8Cj%80%E0P%0A%3C%B0F%BF%04%B8bV2%83'%B6%5D'%DE%05%DC%BA%D6%F7%0D%D8aXr%CA%0D%16%A5%CFt%C4%F8%9F%E6%24%DE%2B%EC%1B%03fm%ECD%00%00%00%00IEND%AEB%60%82";
	
	// Define GM_addStyle for compatibility with opera (in combination with 'Emulate Greasemonkey functions' (http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js))
	if (typeof GM_addStyle == "undefined") {
		function GM_addStyle(css) {
			var heads = document.getElementsByTagName("head");
			if (heads.length > 0) {
				var node = document.createElement("style");
				node.type = "text/css";
				node.appendChild(document.createTextNode(css));
				heads[0].appendChild(node); 
			}
		}
	}
	
	function readCookie(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}
	
	function createCookie(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	}
	
	function adjustLangs()
	{
		//Adjust list of languages
		var langBox= document.getElementById("p-lang");
		if(!langBox) return;
		
		var container= document.getElementById("container");
		if(!container) return;
		
		var columnTop= document.getElementById("columnTop");
		
		var realHeight= parseFloat(window.getComputedStyle(columnTop, "").getPropertyValue("height"));
		var langHeight= parseFloat(window.getComputedStyle(langBox, "").getPropertyValue("height")) - parseFloat(window.getComputedStyle(container, "").getPropertyValue("height"));
		var langBoxTop= langBox.offsetTop;
		var boxHeight= (realHeight - langBoxTop) - langHeight-10;
		
		var containerHeight= parseFloat(container.firstChild.scrollHeight);
		if(boxHeight < 35 || boxHeight >= containerHeight) boxHeight= containerHeight+10;
		container.style.height= boxHeight  + "px";
	}
	
	function toggleSide(e)
	{
		var content= e.target;
		while(content.tagName !== 'DIV') content= content.parentNode;
		
		content= content.getElementsByTagName('DIV')[0];
		var arrow= content.parentNode.getElementsByTagName('H5')[0].getElementsByTagName('A')[0].getElementsByTagName('IMG')[0];
		
		var collapsedBoxes= GM_getValue("collapsedBoxes", "").split(",");
		
		if(content.style.display === 'none')
		{
			content.style.display= 'block';
			arrow.src= arrowOpened;
			collapsedBoxes.splice(collapsedBoxes.indexOf(content.parentNode.id), 1);
		}
		else
		{
			content.style.display= 'none';
			arrow.src= arrowClosed;
			collapsedBoxes.push(content.parentNode.id);
		}
		
		GM_setValue("collapsedBoxes", collapsedBoxes.join(","));
		
		adjustLangs();
	}	
	
	function unFavLang(e)
	{
		var content= e.target.parentNode;
		
		var prefLangs= GM_getValue("langs", "");
		prefLangs= prefLangs.replace(" " + content.className, "");
		GM_setValue("langs", prefLangs);
		
		e.target.innerHTML= " [+]";
		e.target.removeEventListener("click", unFavLang, false);
		e.target.addEventListener("click", favLang, false);
		
		var container= document.getElementById("container").firstChild;
		container.insertBefore(content, container.lastChild);
		
		adjustLangs();
	}
	
	function favLang(e)
	{
		var content= e.target.parentNode;
		
		GM_setValue("langs", GM_getValue("langs", "") + " " + content.className);
		
		e.target.innerHTML= " [-]";
		e.target.removeEventListener("click", favLang, false);
		e.target.addEventListener("click", unFavLang, false);
		
		var lLang = document.getElementById("container").parentNode;
		lLang.parentNode.insertBefore(content, lLang.parentNode.firstChild);
		
		adjustLangs();
	}
	
	function adjustLangsStyle()
	{		
		var pLang = document.getElementById("p-lang");
		var lLang= pLang.getElementsByTagName('LI');
		var state;
		var a;
		for(a= 0; a < lLang[0].childNodes.length; a++)
		{
			if(lLang[0].childNodes[a].className === "langFav")
			{
				if(lLang[0].childNodes[a].style.display === "none") state= "inline";
					else state= "none";
				break;	
			}
		}
		for(var b= 0; b < lLang.length; b++)
		{
			lLang[b].childNodes[a].style.display= state;
		}
	}
	
	function sidebarOnTop()
	{		
		// Begin code to keep sidebar on top
		var sidebar = document.getElementById("column-one");
		if(!sidebar) return; 	// Quit when the sidebar isn't found
		var sideList= sidebar.childNodes;
		var style= "";
		var rtl= (document.getElementsByTagName("html")[0].dir === "rtl");
				
		var place= 0;
		
		style+= '#p-navigation a {display: inline; padding-top: 0px;}';	// Ensure that arrow of navigation element is next to the text
		style+= '.portlet { margin: 0; margin-right: 20px;}';
		style+= '#p-logo { display:none; }'; // Hide logo
		style+= '#content { margin-top: 1em !important; }';
		
		var columnTop= document.createElement("div");
		columnTop.style.position= "fixed";
		columnTop.id= "columnTop";
		columnTop.style.height= "100%";
		columnTop.style.zIndex="3";
		if(rtl === true)
		{
			columnTop.style.float= "right";
			columnTop.style.width= "12.2em";
		}
		columnTop.innerHTML= "   ";
		columnTop.style.overflow= "auto";
		columnTop= sidebar.insertBefore(columnTop, sidebar.lastChild);
		columnTop.style.top= "0px";
		
		for(var a= 0; a < sideList.length; a++)
		{
			if(sideList[a].tagName === 'DIV')
			{
				if(sideList[a].id === 'p-cactions' || sideList[a].id === 'p-personal') {
				    // Give the items another id so the custom css isn't applied
				    sideList[a].id+= '1';
				}
				
				var title= sideList[a].getElementsByTagName('H5')[0];
				if(!title) continue;
				var link = document.createElement("a");
		  		link.href= "javascript:void(null)";
		  		link.innerHTML= "<img src=" + arrowOpened + " width=8 height=8> ";
				title.insertBefore(link, title.firstChild);
				title.style.cursor= "pointer";
				link.parentNode.addEventListener("click", toggleSide, false);
				
				columnTop.insertBefore(sideList[a], columnTop.lastChild);
			}
		}
		document.getElementsByTagName("label")[0].style.cursor= "pointer";	// Label with the searchbox
		
		document.body.style.backgroundAttachment= 'fixed'; // fixed background
		
		// Reorder the sidebar
		var order= readCookie("sidebarOrder");
		if(order != null) {
			createCookie("sidebarOrder", order, 365);	// Refresh expiration date
			order= order.split(",");
			for(var i= order.length-1; i >= 0; i--) {
				// Move item to the top of the list
				var item= document.getElementById(order[i]);
				if(item !== null) {
				    var parentItem= item.parentNode;
				    parentItem.removeChild(item);
				    parentItem.insertBefore(item, parentItem.firstChild);
				}
			}
		}
		
		// Move footer to the side, because else it is overlapped by the sidebar
		if(rtl === true) style+="#footer { border:1px solid #fabd23; margin-right:13.56em;}";
		else style+="#footer { border:1px solid #fabd23; margin-left:13.56em;}";
		
		GM_addStyle("@media screen { " + style + " }");
		
		// Hide the elements that where being hidden on a previous visit
		var collapsedBoxes= GM_getValue("collapsedBoxes", "");
		collapsedBoxes= collapsedBoxes.split(",");
		collapsedBoxes.forEach(function(id){
			var parent= document.getElementById(id);
			if(parent === null)
				return;
			var content= parent.getElementsByTagName("div")[0];
			var arrow= parent.getElementsByTagName('H5')[0].getElementsByTagName('A')[0].getElementsByTagName('IMG')[0];
			content.style.display= 'none';
			arrow.src= arrowClosed;
		});
	}
	
	function langHighlight()
	{
		var pLang = document.getElementById("p-lang");
		if(!pLang) { return; }
		var lLang = pLang.getElementsByTagName("li");
		
		var scrollBox= document.createElement("div");
		scrollBox.innerHTML = '<div id="container" style="overflow-x: hidden;overflow-y:auto"><ul> </ul></div>';
		scrollBox.innerHTML+= '<a href="javascript:void(null)" id="adjust" title="Add/remove prefered languages">Adjust pref. langs</a>';
		scrollBox= pLang.getElementsByTagName("ul")[0].appendChild(scrollBox);
		scrollBox= scrollBox.parentNode.insertBefore(scrollBox, scrollBox.parentNode.firstChild);
		
		document.getElementById("adjust").addEventListener("click", adjustLangsStyle, false);
		
		// Adjust languages when window is resized
		window.addEventListener("resize", adjustLangs, false);
		window.addEventListener("zoom", adjustLangs, false);
		
		var container= document.getElementById("container").firstChild;
		var languages= GM_getValue("langs", " ");
		
		// Remove current language from list with languages
		var currentLang= " interwiki-" + location.href.split("/")[2].split(".")[0];
		languages= languages.replace(currentLang, "");
		
		languages= languages.split(" ");
		languages.splice(0, 1);	//Remove first (blanco) element
		for (var i = 0; i < lLang.length; i++)
		{
			if(lLang[i].tagName === 'LI')
			{
				var langFound= false;
				for(var j= 0; j < languages.length; j++)
				{
					var wpClass = lLang[i].getAttribute("class");
					if(wpClass === null)
						continue;
					if(wpClass.indexOf(languages[j]) === 0)
					{	
						lLang[i].innerHTML= lLang[i].innerHTML + ' <a href="javascript:void(null)" style="display:none" class="langFav">[-]</a>';
						lLang[i].getElementsByTagName('A')[1].addEventListener("click", unFavLang, false);
						lLang[i].parentNode.insertBefore(lLang[i], lLang[i].parentNode.firstChild);
						langFound= true;
						languages.splice(j, 1);
						break;
					}
				}
				if(!langFound)
				{
					lLang[i].innerHTML= lLang[i].innerHTML + ' <a href="javascript:void(null)" style="display:none"  class="langFav">[+]</a>';
					lLang[i].getElementsByTagName('A')[1].addEventListener("click", favLang, false);
					container.insertBefore(lLang[i], container.lastChild);
				}
			}
		}
		adjustLangs();
	}
	
	sidebarOnTop();
	langHighlight();
	
	// set up jQuery variable
	var $;

	// Add jQuery
	var GM_JQ = document.createElement("script");
	    GM_JQ.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js";
	    GM_JQ.type = "text/javascript";
	document.body.appendChild(GM_JQ);

	// Add jQuery UI
	// Add jQuery
	var GM_JQUI = document.createElement("script");
	    GM_JQUI.src = "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js";
	    GM_JQUI.type = "text/javascript";
	document.body.appendChild(GM_JQUI);

	// Check if jQuery's loaded
	var checker=setInterval(function(){
	if((typeof ($ = unsafeWindow.jQuery) != "undefined") && (unsafeWindow.jQuery().sortable)) {
		clearInterval(checker);
		letsJQuery();
	    }
	},100);

	// All your GM code must be inside this function
	function letsJQuery() {
	    $("#columnTop").sortable({
		cursor: "move",
		containment: "parent",
		stop: function(event, ui) {
		    var order= $("#columnTop").sortable("toArray");
		    createCookie("sidebarOrder", order.join(","), 365);
		}
	    });
	}
})();