// See http://en.wiktionary.org/wiki/MediaWiki:Common.js

/**
 * Test if an element has a certain class
 *
 * Description: Uses regular expressions and caching for better performance.
 * Maintainers: [[User:Mike Dillon]], [[User:R. Koot]], [[User:SG]]
 */
var hasClass = (function()
		{
		    var reCache = {};
		    return function (element, className) {
			return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className);
		    };
		})();

/**
 * Add an event handler to an element
 *
 * @param Element element Element to add handler to
 * @param String attach Event to attach to
 * @param callable handler Event handler callback
 */
function addHandler(element, attach, handler) {
    if (window.addEventListener) {
	element.addEventListener(attach, handler, false);
    } else if (window.attachEvent) {
	element.attachEvent('on' + attach, handler);
    }
}

function changeText(el, newText) {
    // Safari work around
    if (el.innerText) {
	el.innerText = newText;
    } else if (el.firstChild && el.firstChild.nodeValue) {
	el.firstChild.nodeValue = newText;
    }
}

function killEvt(evt) {
    evt = evt || window.event || window.Event; // W3C, IE, Netscape
    if (typeof(evt.preventDefault) != 'undefined') {
	evt.preventDefault(); // Don't follow the link
	evt.stopPropagation();
    } else {
	evt.cancelBubble = true; // IE
    }
    return false; // Don't follow the link (IE)
}


/**
 * Add a click event handler to an element
 *
 * @param Element element Element to add handler to
 * @param callable handler Event handler callback
 */
function addClickHandler(element, handler) {
    addHandler(element, 'click', handler);
}

/** Dynamic Navigation Bars (experimental) **************************************/
 
// set up the words in your language
var NavigationBarHide = '[hide ▲]';
var NavigationBarShow = '[show ▼]';
 
// shows and hides content and picture (if available) of navigation bars
// Parameters:
//     indexNavigationBar: the index of navigation bar to be toggled
function toggleNavigationBar(indexNavigationBar)
{
    var NavToggle = document.getElementById("navtoggle" + indexNavigationBar);
    var NavFrame = document.getElementById("navframe" + indexNavigationBar);
    if (!NavFrame || !NavToggle) return false;
    // if shown now
    if (NavToggle.firstChild.data == NavigationBarHide) {
	for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
	    if (hasClass(NavChild, 'navcontent'))
		NavChild.style.display = 'none';
	}
	NavToggle.firstChild.data = NavigationBarShow;
	// if hidden now
    } else if (NavToggle.firstChild.data == NavigationBarShow) {
	for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
	    if (hasClass(NavChild, 'navcontent'))
		NavChild.style.display = 'block';
	}
	NavToggle.firstChild.data = NavigationBarHide;
    }
}
 
// adds show/hide-button to navigation bars
function createNavigationBarToggleButton()
{
    var indexNavigationBar = 0;
    // iterate over all <div>-elements 
    var divs = document.getElementsByTagName("div");
    for (var i = 0; NavFrame = divs[i]; i++) {
	// if found a navigation bar
	if (!hasClass(NavFrame, "navframe")) continue;
	indexNavigationBar++;
	var NavToggle = document.createElement("a");
	NavToggle.className = 'navtoggle';
	NavToggle.setAttribute('id', 'navtoggle' + indexNavigationBar);
	NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');');
	var isCollapsed = hasClass(NavFrame, "collapsed");
	/*
	 * Check if any children are already hidden.  This loop is
	 * here for backwards compatibility: the old way of making
	 * NavFrames start out collapsed was to manually add
	 * style="display:none" to all the NavPic/NavContent elements.
	 * Since this was bad for accessibility (no way to make the
	 * content visible without JavaScript support), the new
	 * recommended way is to add the class "collapsed" to the
	 * NavFrame itself, just like with collapsible tables.
	 */
	for (var NavChild = NavFrame.firstChild; NavChild != null && !isCollapsed; NavChild = NavChild.nextSibling) {
	    if (hasClass(NavChild, 'navpic') || hasClass(NavChild, 'navcontent')) {
		if (NavChild.style.display == 'none') 
		    isCollapsed = true;
	    }
	}
	if (isCollapsed) {
	    for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
		if (hasClass(NavChild, 'navcontent'))
		    NavChild.style.display = 'none';
	    }
	}
	var NavToggleText = document.createTextNode(isCollapsed ? NavigationBarShow : NavigationBarHide);
	NavToggle.appendChild(NavToggleText);

	function addToggleEvent(element, index) {
	    addClickHandler(element, function(evt) {
		toggleNavigationBar(index);
		return killEvt(evt);
	    });
	}

	// Find the NavHead and attach the toggle link (Must be this
	// complicated because Moz's firstChild handling is borked)
	for(var j=0; j < NavFrame.childNodes.length; j++) {
	    if (hasClass(NavFrame.childNodes[j], "navhead")) {
		var navhead = NavFrame.childNodes[j];
		addToggleEvent(navhead, indexNavigationBar);
		navhead.style.cursor = "pointer";
		navhead.appendChild(NavToggle);
	    }
	}
	NavFrame.setAttribute('id', 'navframe' + indexNavigationBar);
    }
}

/**************************************************************************
 * Table of contents
 */

// set up the words in your language
var tocHideText = 'hide ▲';
var tocShowText = 'show ▼';

function showTocToggle() {
    if (document.createTextNode) {
	// Uses DOM calls to avoid document.write + XHTML issues
	var linkHolder = document.getElementById('toctitle');
	var existingLink = document.getElementById('togglelink');
	if (!linkHolder || existingLink) {
	    // Don't add the toggle link twice
	    return;
	}

	var outerSpan = document.createElement('span');
	outerSpan.className = 'toctoggle';

	var toggleLink = document.createElement( 'a' );
	toggleLink.id = 'togglelink';
	toggleLink.className = 'internal';
	toggleLink.href = '#';
	addClickHandler(toggleLink, function(evt) { toggleToc(); return killEvt(evt); } );

	toggleLink.appendChild( document.createTextNode( tocHideText ) );

	outerSpan.appendChild( document.createTextNode( '[' ) );
	outerSpan.appendChild( toggleLink );
	outerSpan.appendChild( document.createTextNode( ']' ) );

	linkHolder.appendChild( document.createTextNode( ' ' ) );
	linkHolder.appendChild( outerSpan );

	var cookiePos = document.cookie.indexOf( "hidetoc=" );
	if ( cookiePos > -1 && document.cookie.charAt( cookiePos + 8 ) == 1 ) {
	    toggleToc();
	}
    }
}

function toggleToc() {
    var tocmain = document.getElementById('toc');
    var toc = document.getElementById('toc').getElementsByTagName('ul')[0];
    var toggleLink = document.getElementById('togglelink');

    if ( toc && toggleLink && toc.style.display == 'none') {
	changeText(toggleLink, tocHideText);
	toc.style.display = 'block';
	document.cookie = "hidetoc=0";
	tocmain.className = 'toc';
    } else {
	changeText(toggleLink, tocShowText);
	toc.style.display = 'none';
	document.cookie = "hidetoc=1";
	tocmain.className = 'toc tochidden';
    }
}

/***********************************************************************
 * Including scripts and stylesheets into HTML
 */

/* Prepend child */
prependChild = function(elem, child) {
    try {
	if (child instanceof Array) {
	    firstc = elem.firstChild
	    for (var c in child)
		elem.insertBefore(child[c], firstc);
	    return elem;
	}
	elem.insertBefore(child, elem.firstChild);
    } catch (e) {
	alert("Exception: " + e +
	      "\n\nElem: " + elem +
	      "\n\nChild: " + child +
	      "\n\nStack trace: " + stacktrace());
    }
    return elem;
}

/* Append child */
appendChild = function(elem, child) {
    try {
	if (child instanceof Array) {
	    for (var c in child)
	      elem.appendChild(child[c]);
	    return elem;
	}
	elem.appendChild(child);
    } catch (e) {
	alert("Exception: " + e +
	      "\n\nElem: " + elem +
	      "\n\nChild: " + child +
	      "\n\nStack trace: " + stacktrace());
    }
    return elem;
}

/* Set attribute. Returns elem. */
setAttribute = function(elem, key, value) { elem.setAttribute(key, value); return elem; }

/* Document head */
head = function() { return document.getElementsByTagName("head")[0] }

/* Create element */
newElement = function(name) { return document.createElement(name); }

/* Include a script. */
includeScript = function(fileName) {
    script = newElement("script")
    setAttribute(script, "type", "text/javascript")
    setAttribute(script, "src", fileName)
    prependChild(head(), script)
}

/* Include a stylesheet. */
includeStylesheet = function(fileName, media) {
    link = newElement("link");
    setAttribute(link, "rel", "stylesheet");
    setAttribute(link, "type", "text/css");
    setAttribute(link, "media", media);
    setAttribute(link, "href", fileName);
    appendChild(head(), link)
}

var shjspath = "/shjs/";
includeStylesheet(shjspath + "css/sh_acid.min.css", "screen, projection");
includeScript(shjspath + "sh_main.min.js");

["c", "cpp", "csharp", "css", "desktop", "diff", "html", "java", "javascript",
 "latex", "lisp", "makefile", "pascal", "perl", "php", "prolog", "properties", "python",
 "ruby", "sh", "spec", "sql", "tcl", "xml", "xorg"].forEach(function(item) {
     includeScript(shjspath + "lang/sh_" + item + ".min.js");
 });

// missing: Windows Registry (sh_winreg), Lua, Lisp, Scheme, Groovy,
// ELisp (emacs lisp), NSIS2

/***********************************************************************
 * Run code after the page is loaded.
 */

/* Append function to the window.onload list. */
runOnLoad = function(handler) {
    if (typeof window.onload == 'function') {
        var oldhandler = window.onload;
        window.onload = function() {
	    if (oldhandler)
		oldhandler();
	    handler();
	};
    } else
        window.onload = handler;
};

runOnLoad(function() {
    try {
	sh_highlightDocument()
    } catch (err) {}

    try {
	createNavigationBarToggleButton()
    } catch (err) {
	alert(err);
    }

    showTocToggle()

    // Decorate outgoing links.
    var links = document.getElementsByTagName('a');
    for (var i = 0; i < links.length; i++) {
	link = links[i]
	if (link.href.match(/^(https?|ftps?):\/\//)) {
	    // Ignore links pointing to our site.
	    if (link.href.match(/^https?:\/\/klic\.name/)) continue;
	    // Ignore empty links.
	    if (!link.hasChildNodes()) continue;
	    // Ignore image links.
	    if (link.firstChild.nodeType != 3) continue; // 3=TEXT_NODE
	    // Decorate.
	    link.firstChild.appendData("↗")
	}
    }
})
