User:Tyrok1/monobook.js: Difference between revisions

From Rosetta Code
Content added Content deleted
(Testing JS)
(Testing new version of language comparison script)
Line 1: Line 1:
/*========================================
/*========================================
This comparison script was written by
This comparison script was written by
Tyrok1.
Tyrok1, and has been tested on Fx 3.6.6,
Cr 5.0.375.99, Epiphany 2.30.2,
Midori 0.2.2
========================================*/
========================================*/
function GetElWidth(el)
var gadgetsAvailable = [
{
id: "LanguageComparison",
name: "Language comparison",
url: "http://rosettacode.org/mw/index.php" +
"?title=Rosetta_Code:Language_comparison_script" +
"&action=raw&ctype=text/javascript",
prefix: "Compare"
},
{
id: "UtilityButtonBar",
name: "Utility button bar",
url: "http://rosettacode.org/mw/index.php" +
"?title=Rosetta_Code:Per-Code_Example_Buttonbar" +
"&action=raw&ctype=text/javascript",
prefix: "ButtonBar"
}
];
function GadgetsAddHandler(el, handlerType, func)
{
{
return (el.clientWidth ? el.clientWidth : el.offsetWidth);
//add an event handler in a more cross-browser way
if(el.addEventListener)
{
el.addEventListener(handlerType, func, false);
}
else if(el.attachEvent)
{
el.attachEvent("on" + handlerType, func);
}
else
{
eval("el.on" + handlerType + " = func;");
}
}
}

function GadgetsScriptLoad(g)
function ToCMulticolumn()
{
{
var gutter = 10;
//see if we need to load it
//if we don't, there's not much point in loading it again
//split the ToC into multiple columns
if(!document.getElementById("GadgetScript" + g))
var tocEl = document.getElementById("toc");
var ulElsNodeList = tocEl.getElementsByTagName("ul");
if(tocEl && ulElsNodeList.length > 0)
{
{
//limit what we're looking at to only what's directly in
var scriptEl = document.createElement("script");
//the main list, and move from NodeList objects to Arrays
scriptEl.setAttribute("id", "GadgetScript" + g);
var ulEls = [ulElsNodeList[0]];
scriptEl.setAttribute("type", "text/javascript");
for(var u = 1; u < ulElsNodeList.length; ++u)
scriptEl.setAttribute("src", gadgetsAvailable[g].url);
{
document.documentElement.appendChild(scriptEl);
if(ulElsNodeList[u].parentNode == ulElsNodeList[0].parentNode)
{
ulEls[ulEls.length] = ulElsNodeList[u];
}
}
var liElsNodeList = tocEl.getElementsByTagName("li");
var liEls = new Array();
for(var l = 0; l < liElsNodeList.length; ++l)
{
for(u = 0; u < ulEls.length; ++u)
{
if(liElsNodeList[l].parentNode == ulEls[u])
{
liEls[liEls.length] = liElsNodeList[l];
break;
}
}
}
//show all of the <ul> tags so we can get their items' ideal widths
if(ulEls[0].style.display && ulEls[0].style.display == "none")
{
ulEls[0].oldDisplay = "none";
}
else
{
ulEls[0].oldDisplay = "inline-block";
}
for(u = 0; u < ulEls.length; ++u)
{
ulEls[u].style.display = "inline-block";
}
//find the widest item and use that to set up an ideal number of columns
var maxWidth = 0;
for(l = 0; l < liEls.length; ++l)
{
if(!liEls[l].initialWidth)
{
liEls[l].initialWidth = GetElWidth(liEls[l]);
}
maxWidth = Math.max(liEls[l].initialWidth, maxWidth);
if(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
navigator.appVersion.indexOf("MSIE 7.") >= 0)
{
liEls[l].style.display = "inline";
}
}
//add in the gutter
maxWidth += gutter;
//figure out the ideal number of columns
tocEl.style.width = "100%";
var idealColumns = Math.min(
Math.floor(GetElWidth(tocEl) / maxWidth),
Math.floor(liEls.length / 3) + 1);
if(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
navigator.appVersion.indexOf("MSIE 7.") >= 0)
{
idealColumns = 1;
}
//see if we've already got the ideal number of columns
//if so, we don't need to change anything
if(ulEls.length != idealColumns)
{
//split the list into multiple columns of width (95 / idealColumns)%
//first, make sure we have enough lists to split into
while(ulEls.length < idealColumns)
{
ulEls[ulEls.length] =
ulEls[ulEls.length - 1].parentNode.insertBefore(
document.createElement("ul"),
ulEls[ulEls.length - 1].nextSibling);
}
//style the lists
for(var c = 0; c < ulEls.length; ++c)
{
ulEls[c].style.display = "inline-block";
ulEls[c].style.cssFloat = "left";
ulEls[c].style.verticalAlign = "top";
ulEls[c].style.width = (95 / idealColumns) + "%";
}
//sort the items into the lists
for(l = 0; l < liEls.length; ++l)
{
liEls[l] = ulEls[
Math.floor(l / liEls.length * idealColumns)
].appendChild(liEls[l].parentNode.removeChild(liEls[l]));
}
//get rid of any unnecessary lists
for(l = idealColumns; l < ulEls.length; ++l)
{
ulEls[l].parentNode.removeChild(ulEls[l]);
}
}
//hide the instructions/lists if they're supposed to be hidden
var insEl = document.getElementById("tocinstructions");
if(insEl)
{
insEl.style.display =
(ulEls[0].oldDisplay.toLowerCase() == "none" ? "none" : "block");
}
for(u = 0; u < ulEls.length; ++u)
{
ulEls[u].style.display = ulEls[0].oldDisplay;
}
//if we're setting this up for the first time...
if(!window.toggleTocOld)
{
//change out the toggling function so it toggles all of the lists
window.toggleTocOld = window.toggleToc;
window.toggleUpdateVisibility = function() {
var tocEl = document.getElementById("toc");
var ulEls = tocEl.getElementsByTagName("ul");
for(var u = 0; u < ulEls.length; ++u)
{
if(ulEls[0].style.display &&
ulEls[0].style.display == "none")
{
ulEls[u].style.display = "none"
}
else
{
ulEls[u].style.display = "inline-block"
}
}
var el = document.getElementById("tocinstructions");
if(el)
{
if(ulEls[0].style.display &&
ulEls[0].style.display.toLowerCase() == "none")
{
el.style.display = "none";
}
else
{
el.style.display = "block";
}
}
};
window.toggleToc = function() {
toggleTocOld();
toggleUpdateVisibility();
};
//add an event handler so if the window's
//resized the number of columns can change
if(window.addEventListener)
{
window.addEventListener("resize", ToCMulticolumn, false);
}
else if(document.addEventListener)
{
document.addEventListener("resize", ToCMulticolumn, false);
}
else if(window.attachEvent)
{
window.attachEvent("onresize", ToCMulticolumn);
}
}
}
}
}
}

function GadgetsScriptActivate(g)
function CompareActivate()
{
{
//check to see if the script's finished loading
//check to see if we're looking at a task page
var catLinksEl = document.getElementById("catlinks");
if(eval("typeof " + gadgetsAvailable[g].prefix + "Activate") == "undefined")
var isTask = false;
if(catLinksEl)
{
{
var aEls = catLinksEl.getElementsByTagName("a");
//not finished yet - try reactivating in another 0.5s
for(var a = 0; a < aEls.length; ++a)
setTimeout(function() { GadgetsScriptActivate(g); }, 500);
{
if(aEls[a].getAttribute("title") == "Category:Programming Tasks")
{
//it's a task
isTask = true;
break;
}
}
}
}
if(!isTask)
else
{
{
return;
//run the activation function
eval(gadgetsAvailable[g].prefix + "Activate();");
}
}
}
//check to make sure we have a table of contents
var tocEl = document.getElementById("toc");
function GadgetsScriptDeactivate(g)
if(tocEl)
{
//check to see if the specified script has a deactivation function
if(eval("typeof " + gadgetsAvailable[g].prefix + "Deactivate") != "undefined")
{
{
//remove the extra show/hide button from the Contents area
//it does - run it
var tocTitleEl = document.getElementById("toctitle");
eval(gadgetsAvailable[g].prefix + "Deactivate();");
if(tocTitleEl)
}
{
else
var spanEls = tocTitleEl.getElementsByTagName("span");
{
var foundToggle = false;
//pop up a warning to the user to let them know
for(var s = 0; s < spanEls.length; ++s)
//the plugin will be disabled when they reload
{
alert("This script will be disabled on next page load");
if(spanEls[s].className &&
}
spanEls[s].className.toLowerCase() == "toctoggle")
}
function GadgetsCreateCheckboxClosure(el)
{
//create an onclick handler for the script checkboxes
return function() {
//save the checkboxes to the cookie for next page load
GadgetsSaveCheckboxes();
//check to see if we need to activate or deactivate
if(el.checked)
{
{
if(foundToggle)
//load and activate the script
{
GadgetsScriptLoad(el.value);
spanEls[s].parentNode.removeChild(spanEls[s]);
GadgetsScriptActivate(el.value);
}
foundToggle = true;
}
}
else
}
{
}
//deactivate the script
//find all of the links to language sections and add checkboxes
GadgetsScriptDeactivate(el.value);
var liEls = tocEl.getElementsByTagName("li");
}
for(var l = 0; l < liEls.length; ++l)
};
}
function GadgetsMouseOver()
{
//show the scripts dropdown
document.getElementById("pt-jsgadgets-list").style.display = "block";
}
function GadgetsMouseOut()
{
//hide the scripts dropdown
document.getElementById("pt-jsgadgets-list").style.display = "none";
}
function GadgetsSaveCheckboxes()
{
var checkedBoxes = "", checkboxEl = null;
//build a string representation of all of the checked boxes to save to the cookie
for(var c = 0; checkboxEl = document.getElementById("pt-jsgadgets-gadget" + c); ++c)
{
if(checkboxEl.checked)
{
{
//add a checkbox with the language section's anchor name attribute
if(checkedBoxes != "")
//as its value for easier lookup in the refresh function
var checkboxEl = document.createElement("input");
checkboxEl.setAttribute("type", "checkbox");
checkboxEl.setAttribute("name", "CompareLanguage" + l);
checkboxEl.setAttribute("id", "CompareLanguage" + l);
var href = liEls[l].getElementsByTagName("a")[0].getAttribute("href");
checkboxEl.setAttribute("value",
href.substring(href.indexOf("#") + 1, href.length));
checkboxEl.onclick = CompareRefresh;
liEls[l].insertBefore(checkboxEl, liEls[l].firstChild);
}
//add some instructions
var toctitleEl = document.getElementById("toctitle");
var instructionsEl = toctitleEl.appendChild(document.createElement("p"));
instructionsEl.setAttribute("id", "tocinstructions");
instructionsEl.appendChild(
document.createTextNode("Check the boxes next to languages to compare them."));
instructionsEl.appendChild(document.createElement("br"));
instructionsEl.appendChild(
document.createTextNode("Uncheck all boxes to show all languages."));
//switch the ToC to multi-column mode
ToCMulticolumn();
//put all language sections inside of a <div>
var spanEls = document.getElementsByTagName("span");
var languages = CompareGetLanguages();
var divEl = null;
for(var s = 0; s < spanEls.length; ++s)
{
if(typeof spanEls[s].id != "undefined" &&
typeof languages[spanEls[s].id] != "undefined")
{
{
//we can assume that this is a language section
checkedBoxes += ",";
//make a list of all of the elements between this <span>
//tag and the next one that has a name attribute
divEl = spanEls[s].parentNode.parentNode.insertBefore(
document.createElement("div"), spanEls[s].parentNode);
var curEl = spanEls[s].parentNode.nextSibling;
divEl.appendChild(spanEls[s].parentNode.parentNode.removeChild(
spanEls[s].parentNode));
while(curEl && (!curEl.tagName || curEl.tagName.toLowerCase() != "h2"))
{
var newCurEl = curEl.nextSibling;
divEl.appendChild(curEl.parentNode.removeChild(curEl));
curEl = newCurEl;
};
}
}
}
checkedBoxes += gadgetsAvailable[c].id;
if(divEl)
{
//add a float clearing div
var clearEl = divEl.parentNode.insertBefore(
document.createElement("div"), divEl.nextSibling);
clearEl.style.clear = "both";
}
//and refresh the display for good measure (sometimes
//browsers like to save <input> states between reloads)
CompareRefresh();
//add an event listener for window resizing
if(window.addEventListener)
{
window.addEventListener("resize", CompareRefresh, false);
}
else if(document.addEventListener)
{
document.addEventListener("resize", CompareRefresh, false);
}
else if(window.attachEvent)
{
window.attachEvent("onresize", CompareRefresh);
}
}
}
}
//set an expiry date 1000 years into the future
var expireDate = new Date();
expireDate.setFullYear(expireDate.getFullYear() + 1000);
//store the cookie
document.cookie = "jsGadgets=" + escape(checkedBoxes) +
"; expires=" + expireDate.toUTCString();
}
}

function GadgetsGetCheckboxes()
function CompareGetLanguages()
{
{
var tocEl = document.getElementById("toc");
//pull in the cookie and look for the jsGadgets key
var fullCookie = document.cookie;
var languages = new Array();
if(tocEl)
var gadgetsPos = fullCookie.indexOf("jsGadgets=");
if(gadgetsPos < 0)
{
{
//no gadgets in the cookie
//find all of the checkboxes within the ToC
var inputEls = tocEl.getElementsByTagName("input");
return new Array();
for(var i = 0; i < inputEls.length; ++i)
}
var endPos = fullCookie.indexOf(";", gadgetsPos);
//split the gadget IDs by comma
var jsGadgets = fullCookie.substring(gadgetsPos + ("jsGadgets=").length,
(endPos > 0 ? endPos : fullCookie.length));
var checkIDs = unescape(jsGadgets).split(",");
//translate the list of IDs to a list of array indices,
//in keeping with the way the rest of this module works
var checkIndices = new Array();
for(var g = 0; g < gadgetsAvailable.length; ++g)
{
for(var c = 0; c < checkIDs.length; ++c)
{
{
//if it's one of the ones we added earlier, log the
if(gadgetsAvailable[g].id == checkIDs[c])
//checked status to the languages array for later use
if(inputEls[i].getAttribute("name").substring(0,
("CompareLanguage").length) == "CompareLanguage")
{
{
languages[inputEls[i].value] = inputEls[i].checked;
checkIndices[checkIndices.length] = g;
break;
}
}
}
}
}
}
return checkIndices;
return languages;
}
}

function GadgetsActivate()
function CompareRefresh()
{
{
//refresh the display of the language sections displayed under the ToC
//find the user preferences button and add a new list item to the right of it
//first, check to see if we're looking at a task page
var prefsEl = document.getElementById("pt-preferences");
var codeMargin = 20;
if(!prefsEl)
var tocEl = document.getElementById("toc");
var languages = new Array();
var numChecked = 0;
if(tocEl)
{
{
//count how many languages are checked
var personalEl = document.getElementById("p-personal");
languages = CompareGetLanguages();
if(!personalEl)
for(var l in languages)
{
{
if(languages[l])
return;
{
++numChecked;
}
}
}
var liEls = personalEl.getElementsByTagName("li");
//now, find all <a> tags with name attributes
if(!liEls || liEls.length < 2)
var spanEls = document.getElementsByTagName("span");
for(var s = 0; s < spanEls.length; ++s)
{
{
if(typeof spanEls[s].className != "undefined" &&
return;
spanEls[s].className.indexOf("mw-headline") >= 0 &&
typeof spanEls[s].id != "undefined" &&
typeof languages[spanEls[s].id] != "undefined")
{
var anchorName = spanEls[s].id;
var parentDiv = spanEls[s].parentNode.parentNode;
//we can assume that this is a language section
//check to see if we're displaying in side-by-side mode,
//regular mode, or not at all
if(numChecked < 1 || (languages[anchorName] &&
(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
navigator.appVersion.indexOf("MSIE 7.") >= 0)))
{
//enable full-width mode
parentDiv.style.display = "block";
parentDiv.style.cssFloat = "none";
parentDiv.style.width = "auto";
parentDiv.style.marginRight = 0;
}
else if(languages[anchorName])
{
//enable side-by-side mode
parentDiv.style.display = "inline-block";
parentDiv.style.verticalAlign = "top";
parentDiv.style.marginRight = "20px";
//find the width for this language
var preEls = parentDiv.getElementsByTagName("pre");
var maxWidth = 0;
for(var p = 0; p < preEls.length; ++p)
{
var oldWidth = GetElWidth(preEls[p]);
preEls[p].style.cssFloat = "left";
if(GetElWidth(preEls[p]) == oldWidth)
{
//assume it's either wider than the
//window or IE where they don't shrink
//arbitrarily set to 45% width
maxWidth = Math.max(
GetElWidth(parentDiv.parentNode) * 0.45,
maxWidth);
}
else
{
maxWidth = Math.max(GetElWidth(preEls[p]),
maxWidth);
}
preEls[p].style.cssFloat = "none";
}
//if there are no code blocks, base it off of the <h2>
if(!maxWidth)
{
var h2Els = parentDiv.getElementsByTagName("h2");
if(h2Els.length > 0)
{
//we have at least one h2
//use its width
var oldWidth = GetElWidth(h2Els[p]);
h2Els[0].style.cssFloat = "left";
if(GetElWidth(h2Els[p]) == oldWidth)
{
//assume it's either wider than the
//window or IE where they don't shrink
//arbitrarily set to 45% width
maxWidth = Math.max(
GetElWidth(parentDiv.parentNode) * 0.45,
maxWidth);
}
else
{
maxWidth = GetElWidth(h2Els[0]);
}
h2Els[0].style.cssFloat = "none";
}
else
{
//no clue what it should be
//arbitrarily set it to 200
maxWidth = 200;
}
}
//set the container <div> to a size just a little bit larger
parentDiv.style.width = (maxWidth + codeMargin) + "px";
}
else
{
//hide it entirely
parentDiv.style.display = "none";
}
}
}
}
prefsEl = liEls[liEls.length - 2];
}
var jsMenuEl = prefsEl.parentNode.insertBefore(
document.createElement("li"), prefsEl.nextSibling);
jsMenuEl.setAttribute("id", "pt-jsgadgets");
//add a new link named "My scripts" in the new list item
//from a semantics point of view, this is not great,
//but this way the styling kicks in to keep it consistent with its siblings
var jsLinkEl = jsMenuEl.appendChild(document.createElement("a"));
jsLinkEl.appendChild(document.createTextNode("My scripts"));
jsLinkEl.setAttribute("href", "javascript: void(0);");
jsLinkEl.style.position = "relative";
//add handlers for showing on mouseover and hiding on mouseout
GadgetsAddHandler(jsLinkEl, "mouseover", GadgetsMouseOver);
GadgetsAddHandler(jsLinkEl, "mouseout", GadgetsMouseOut);
//build a list for showing available JS gadgets
var modulesListEl = jsLinkEl.appendChild(document.createElement("ol"));
modulesListEl.setAttribute("id", "pt-jsgadgets-list");
modulesListEl.style.listStyle = "none";
modulesListEl.style.margin = 0;
modulesListEl.style.padding = 0;
modulesListEl.style.position = "absolute";
modulesListEl.style.top = "100%";
modulesListEl.style.left = 0;
modulesListEl.style.backgroundColor = "#fff";
modulesListEl.style.border = "1px solid #69c";
modulesListEl.style.padding = "0.5em";
modulesListEl.style.display = "none";
//raise the zIndex of the new button (as well as
//a few parents) so the menu overlaps the page
var zEl = modulesListEl;
for(var z = 0; z < 6 && zEl && zEl.style; ++z, zEl = zEl.parentNode)
{
zEl.style.zIndex = 100;
}
//add each of the gadgets to the list
for(var m = 0; m < gadgetsAvailable.length; ++m)
{
//add the list item element
var liEl = modulesListEl.appendChild(document.createElement("li"));
liEl.style.display = "block";
liEl.style.cssFloat = "none";
liEl.style.right = "auto";
liEl.style.left = 0;
liEl.style.textAlign = "left";
liEl.style.margin = 0;
liEl.style.padding = 0;
//add the checkbox
var inputEl = document.createElement("input");
var checkboxId = "pt-jsgadgets-gadget" + m;
inputEl.setAttribute("type", "checkbox");
inputEl.setAttribute("id", checkboxId);
inputEl.setAttribute("value", m);
GadgetsAddHandler(inputEl, "click", GadgetsCreateCheckboxClosure(inputEl));
liEl.appendChild(inputEl);
//add the label
var labelEl = document.createElement("label");
labelEl.setAttribute("for", checkboxId);
labelEl.appendChild(document.createTextNode(gadgetsAvailable[m].name));
labelEl.style.paddingLeft = "1em";
liEl.appendChild(labelEl);
}
//fetch the saved checkboxes from the cookie
var checks = GadgetsGetCheckboxes();
for(var c = 0; c < checks.length; ++c)
{
//for each one that should be checked on page load,
//check the box, load, and activate it
document.getElementById("pt-jsgadgets-gadget" + checks[c]).checked = true;
GadgetsScriptLoad(checks[c]);
GadgetsScriptActivate(checks[c]);
}
}
}
}

//register the comparison script with the window's load event
//register the comparison script with the window's load event
if(window.addEventListener)
GadgetsAddHandler(window, "load", GadgetsActivate);
{
//
window.addEventListener("load", CompareActivate, false);
}
else if(window.attachEvent)
{
window.attachEvent("onload", CompareActivate);
}
else if(document.addEventListener)
{
document.addEventListener("load", CompareActivate, false);
}
else
{
window.onload = CompareActivate;
}

Revision as of 05:20, 14 November 2010

/*========================================
This comparison script was written by
Tyrok1.
========================================*/
function GetElWidth(el)
{
	return (el.clientWidth ? el.clientWidth : el.offsetWidth);
}

function ToCMulticolumn()
{
	var gutter = 10;
	
	//split the ToC into multiple columns
	var tocEl = document.getElementById("toc");
	var ulElsNodeList = tocEl.getElementsByTagName("ul");
	if(tocEl && ulElsNodeList.length > 0)
	{
		//limit what we're looking at to only what's directly in
		//the main list, and move from NodeList objects to Arrays
		var ulEls = [ulElsNodeList[0]];
		for(var u = 1; u < ulElsNodeList.length; ++u)
		{
			if(ulElsNodeList[u].parentNode == ulElsNodeList[0].parentNode)
			{
				ulEls[ulEls.length] = ulElsNodeList[u];
			}
		}
		var liElsNodeList = tocEl.getElementsByTagName("li");
		var liEls = new Array();
		for(var l = 0; l < liElsNodeList.length; ++l)
		{
			for(u = 0; u < ulEls.length; ++u)
			{
				if(liElsNodeList[l].parentNode == ulEls[u])
				{
					liEls[liEls.length] = liElsNodeList[l];
					break;
				}
			}
		}
		
		//show all of the <ul> tags so we can get their items' ideal widths
		if(ulEls[0].style.display && ulEls[0].style.display == "none")
		{
			ulEls[0].oldDisplay = "none";
		}
		else
		{
			ulEls[0].oldDisplay = "inline-block";
		}
		for(u = 0; u < ulEls.length; ++u)
		{
			ulEls[u].style.display = "inline-block";
		}
		
		//find the widest item and use that to set up an ideal number of columns
		var maxWidth = 0;
		for(l = 0; l < liEls.length; ++l)
		{
			if(!liEls[l].initialWidth)
			{
				liEls[l].initialWidth = GetElWidth(liEls[l]);
			}
			maxWidth = Math.max(liEls[l].initialWidth, maxWidth);
			if(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
				navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
				navigator.appVersion.indexOf("MSIE 7.") >= 0)
			{
				liEls[l].style.display = "inline";
			}
		}
		
		//add in the gutter
		maxWidth += gutter;
		
		//figure out the ideal number of columns
		tocEl.style.width = "100%";
		var idealColumns = Math.min(
			Math.floor(GetElWidth(tocEl) / maxWidth),
			Math.floor(liEls.length / 3) + 1);
		if(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
			navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
			navigator.appVersion.indexOf("MSIE 7.") >= 0)
		{
			idealColumns = 1;
		}
		
		//see if we've already got the ideal number of columns
		//if so, we don't need to change anything
		if(ulEls.length != idealColumns)
		{
			//split the list into multiple columns of width (95 / idealColumns)%
			//first, make sure we have enough lists to split into
			while(ulEls.length < idealColumns)
			{
				ulEls[ulEls.length] =
					ulEls[ulEls.length - 1].parentNode.insertBefore(
						document.createElement("ul"),
						ulEls[ulEls.length - 1].nextSibling);
			}
			
			//style the lists
			for(var c = 0; c < ulEls.length; ++c)
			{
				ulEls[c].style.display = "inline-block";
				ulEls[c].style.cssFloat = "left";
				ulEls[c].style.verticalAlign = "top";
				ulEls[c].style.width = (95 / idealColumns) + "%";
			}
			
			//sort the items into the lists
			for(l = 0; l < liEls.length; ++l)
			{
				liEls[l] = ulEls[
						Math.floor(l / liEls.length * idealColumns)
					].appendChild(liEls[l].parentNode.removeChild(liEls[l]));
			}
			
			//get rid of any unnecessary lists
			for(l = idealColumns; l < ulEls.length; ++l)
			{
				ulEls[l].parentNode.removeChild(ulEls[l]);
			}
		}
		
		//hide the instructions/lists if they're supposed to be hidden
		var insEl = document.getElementById("tocinstructions");
		if(insEl)
		{
			insEl.style.display =
				(ulEls[0].oldDisplay.toLowerCase() == "none" ? "none" : "block");
		}
		for(u = 0; u < ulEls.length; ++u)
		{
			ulEls[u].style.display = ulEls[0].oldDisplay;
		}
		
		//if we're setting this up for the first time...
		if(!window.toggleTocOld)
		{
			//change out the toggling function so it toggles all of the lists
			window.toggleTocOld = window.toggleToc;
			window.toggleUpdateVisibility = function() {
							var tocEl = document.getElementById("toc");
							var ulEls = tocEl.getElementsByTagName("ul");
							for(var u = 0; u < ulEls.length; ++u)
							{
								if(ulEls[0].style.display &&
									ulEls[0].style.display == "none")
								{
									ulEls[u].style.display = "none"
								}
								else
								{
									ulEls[u].style.display = "inline-block"
								}
							}
							var el = document.getElementById("tocinstructions");
							if(el)
							{
								if(ulEls[0].style.display &&
									ulEls[0].style.display.toLowerCase() == "none")
								{
									el.style.display = "none";
								}
								else
								{
									el.style.display = "block";
								}
							}
						};
			window.toggleToc = function() {
							toggleTocOld();
							toggleUpdateVisibility();
						};
			
			//add an event handler so if the window's
			//resized the number of columns can change
			if(window.addEventListener)
			{
				window.addEventListener("resize", ToCMulticolumn, false);
			}
			else if(document.addEventListener)
			{
				document.addEventListener("resize", ToCMulticolumn, false);
			}
			else if(window.attachEvent)
			{
				window.attachEvent("onresize", ToCMulticolumn);
			}
		}
	}
}

function CompareActivate()
{
	//check to see if we're looking at a task page
	var catLinksEl = document.getElementById("catlinks");
	var isTask = false;
	if(catLinksEl)
	{
		var aEls = catLinksEl.getElementsByTagName("a");
		for(var a = 0; a < aEls.length; ++a)
		{
			if(aEls[a].getAttribute("title") == "Category:Programming Tasks")
			{
				//it's a task
				isTask = true;
				break;
			}
		}
	}
	if(!isTask)
	{
		return;
	}
	
	//check to make sure we have a table of contents
	var tocEl = document.getElementById("toc");
	if(tocEl)
	{
		//remove the extra show/hide button from the Contents area
		var tocTitleEl = document.getElementById("toctitle");
		if(tocTitleEl)
		{
			var spanEls = tocTitleEl.getElementsByTagName("span");
			var foundToggle = false;
			for(var s = 0; s < spanEls.length; ++s)
			{
				if(spanEls[s].className &&
					spanEls[s].className.toLowerCase() == "toctoggle")
				{
					if(foundToggle)
					{
						spanEls[s].parentNode.removeChild(spanEls[s]);
					}
					foundToggle = true;
				}
			}
		}
		
		//find all of the links to language sections and add checkboxes
		var liEls = tocEl.getElementsByTagName("li");
		for(var l  = 0; l < liEls.length; ++l)
		{
			//add a checkbox with the language section's anchor name attribute
			//as its value for easier lookup in the refresh function
			var checkboxEl = document.createElement("input");
			checkboxEl.setAttribute("type", "checkbox");
			checkboxEl.setAttribute("name", "CompareLanguage" + l);
			checkboxEl.setAttribute("id", "CompareLanguage" + l);
			var href = liEls[l].getElementsByTagName("a")[0].getAttribute("href");
			checkboxEl.setAttribute("value",
				href.substring(href.indexOf("#") + 1, href.length));
			checkboxEl.onclick = CompareRefresh;
			liEls[l].insertBefore(checkboxEl, liEls[l].firstChild);
		}
		
		//add some instructions
		var toctitleEl = document.getElementById("toctitle");
		var instructionsEl = toctitleEl.appendChild(document.createElement("p"));
		instructionsEl.setAttribute("id", "tocinstructions");
		instructionsEl.appendChild(
			document.createTextNode("Check the boxes next to languages to compare them."));
		instructionsEl.appendChild(document.createElement("br"));
		instructionsEl.appendChild(
			document.createTextNode("Uncheck all boxes to show all languages."));
		
		//switch the ToC to multi-column mode
		ToCMulticolumn();
		
		//put all language sections inside of a <div>
		var spanEls = document.getElementsByTagName("span");
		var languages = CompareGetLanguages();
		var divEl = null;
		for(var s = 0; s < spanEls.length; ++s)
		{
			if(typeof spanEls[s].id != "undefined" &&
				typeof languages[spanEls[s].id] != "undefined")
			{
				//we can assume that this is a language section
				//make a list of all of the elements between this <span>
				//tag and the next one that has a name attribute
				divEl = spanEls[s].parentNode.parentNode.insertBefore(
					document.createElement("div"), spanEls[s].parentNode);
				var curEl = spanEls[s].parentNode.nextSibling;
				divEl.appendChild(spanEls[s].parentNode.parentNode.removeChild(
					spanEls[s].parentNode));
				while(curEl && (!curEl.tagName || curEl.tagName.toLowerCase() != "h2"))
				{
					var newCurEl = curEl.nextSibling;
					divEl.appendChild(curEl.parentNode.removeChild(curEl));
					curEl = newCurEl;
				};
			}
		}
		if(divEl)
		{
			//add a float clearing div
			var clearEl = divEl.parentNode.insertBefore(
				document.createElement("div"), divEl.nextSibling);
			clearEl.style.clear = "both";
		}
		
		//and refresh the display for good measure (sometimes
		//browsers like to save <input> states between reloads)
		CompareRefresh();
		
		//add an event listener for window resizing
		if(window.addEventListener)
		{
			window.addEventListener("resize", CompareRefresh, false);
		}
		else if(document.addEventListener)
		{
			document.addEventListener("resize", CompareRefresh, false);
		}
		else if(window.attachEvent)
		{
			window.attachEvent("onresize", CompareRefresh);
		}
	}
}

function CompareGetLanguages()
{
	var tocEl = document.getElementById("toc");
	var languages = new Array();
	if(tocEl)
	{
		//find all of the checkboxes within the ToC
		var inputEls = tocEl.getElementsByTagName("input");
		for(var i = 0; i < inputEls.length; ++i)
		{
			//if it's one of the ones we added earlier, log the
			//checked status to the languages array for later use
			if(inputEls[i].getAttribute("name").substring(0,
				("CompareLanguage").length) == "CompareLanguage")
			{
				languages[inputEls[i].value] = inputEls[i].checked;
			}
		}
	}
	return languages;
}

function CompareRefresh()
{
	//refresh the display of the language sections displayed under the ToC
	//first, check to see if we're looking at a task page
	var codeMargin = 20;
	var tocEl = document.getElementById("toc");
	var languages = new Array();
	var numChecked = 0;
	if(tocEl)
	{
		//count how many languages are checked
		languages = CompareGetLanguages();
		for(var l in languages)
		{
			if(languages[l])
			{
				++numChecked;
			}
		}
		
		//now, find all <a> tags with name attributes
		var spanEls = document.getElementsByTagName("span");
		for(var s = 0; s < spanEls.length; ++s)
		{
			if(typeof spanEls[s].className != "undefined" &&
				spanEls[s].className.indexOf("mw-headline") >= 0 &&
				typeof spanEls[s].id != "undefined" &&
				typeof languages[spanEls[s].id] != "undefined")
			{
				var anchorName = spanEls[s].id;
				var parentDiv = spanEls[s].parentNode.parentNode;
				
				//we can assume that this is a language section
				//check to see if we're displaying in side-by-side mode,
				//regular mode, or not at all
				if(numChecked < 1 || (languages[anchorName] &&
					(navigator.appVersion.indexOf("MSIE 5.") >= 0 ||
					navigator.appVersion.indexOf("MSIE 6.") >= 0 ||
					navigator.appVersion.indexOf("MSIE 7.") >= 0)))
				{
					//enable full-width mode
					parentDiv.style.display = "block";
					parentDiv.style.cssFloat = "none";
					parentDiv.style.width = "auto";
					parentDiv.style.marginRight = 0;
				}
				else if(languages[anchorName])
				{
					//enable side-by-side mode
					parentDiv.style.display = "inline-block";
					parentDiv.style.verticalAlign = "top";
					parentDiv.style.marginRight = "20px";
					
					//find the width for this language
					var preEls = parentDiv.getElementsByTagName("pre");
					var maxWidth = 0;
					for(var p = 0; p < preEls.length; ++p)
					{
						var oldWidth = GetElWidth(preEls[p]);
						preEls[p].style.cssFloat = "left";
						if(GetElWidth(preEls[p]) == oldWidth)
						{
							//assume it's either wider than the
							//window or IE where they don't shrink
							//arbitrarily set to 45% width
							maxWidth = Math.max(
								GetElWidth(parentDiv.parentNode) * 0.45,
								maxWidth);
						}
						else
						{
							maxWidth = Math.max(GetElWidth(preEls[p]),
								maxWidth);
						}
						preEls[p].style.cssFloat = "none";
					}
					
					//if there are no code blocks, base it off of the <h2>
					if(!maxWidth)
					{
						var h2Els = parentDiv.getElementsByTagName("h2");
						if(h2Els.length > 0)
						{
							//we have at least one h2
							//use its width
							var oldWidth = GetElWidth(h2Els[p]);
							h2Els[0].style.cssFloat = "left";
							if(GetElWidth(h2Els[p]) == oldWidth)
							{
								//assume it's either wider than the
								//window or IE where they don't shrink
								//arbitrarily set to 45% width
								maxWidth = Math.max(
									GetElWidth(parentDiv.parentNode) * 0.45,
									maxWidth);
							}
							else
							{
								maxWidth = GetElWidth(h2Els[0]);
							}
							h2Els[0].style.cssFloat = "none";
						}
						else
						{
							//no clue what it should be
							//arbitrarily set it to 200
							maxWidth = 200;
						}
					}
					
					//set the container <div> to a size just a little bit larger
					parentDiv.style.width = (maxWidth + codeMargin) + "px";
				}
				else
				{
					//hide it entirely
					parentDiv.style.display = "none";
				}
			}
		}
	}
}

//register the comparison script with the window's load event
if(window.addEventListener)
{
	window.addEventListener("load", CompareActivate, false);
}
else if(window.attachEvent)
{
	window.attachEvent("onload", CompareActivate);
}
else if(document.addEventListener)
{
	document.addEventListener("load", CompareActivate, false);
}
else
{
	window.onload = CompareActivate;
}