// sortlistinhtml.js - version 1.03 2008-03-04
//
// A JavaScript class for sorting UL and OL lists on the browser
//
// base: http://www.webaware.com.au/free/sortlistinhtml/
//
// copyright © 2008 WebAware Pty Ltd
//---------------------------------------------------------------------
// Wikis and blogs sometimes generate lists without sorting them. This
// class allows such lists to be sorted on the browser, i.e. after the
// page has downloaded.
//
// To activate sorting of a list, wrap it in a div with a class of
// - sortListInHTML (case-sensitive sort)
// - sortListInHTMLi (case-insensitive sort)
//
// Mix-in classes are supported, e.g. class="container sortListInHTML"
//
// To merge adjacent lists within a div, add CSS class of listMerge
//
// example:
//   <div class="sortListInHTML">
//    <ol>
//     <li>Bread</li>
//     <li>Milk</li>
//     <li>Cheese</li>
//     <li>Apples</li>
//    </ol>
//   </div>
//---------------------------------------------------------------------
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// Full license: http://www.webaware.com.au/free/license.htm
//---------------------------------------------------------------------

// class constructor
function SortListInHTML() {
	if (window.addEventListener) window.addEventListener("load", SortListInHTML.Activate, false);
	else if (window.attachEvent) window.attachEvent("onload", SortListInHTML.Activate);
}

// activate the class - iterate over all divs looking for ones that need lists sorted
SortListInHTML.Activate = function() {
	var divs = document.getElementsByTagName('div');
	var matchDIV  = /\bsortListInHTML[i]?\b/;		// match CSS class sortListInHTML or sortListInHTMLi
	var matchDIVi = /\bsortListInHTMLi\b/;			// match CSS class sortListInHTMLi only
	var matchMergeList = /\blistMerge\b/;			// match CSS class listMerge
	var matchList = /^(ol|ul)$/i;					// match HTML tag ul/UL/ol/OL

	for (var i in divs) {
		var d = divs[i];
		if (d.className && matchDIV.test(d.className)) {
			var ignoreCase = matchDIVi.test(d.className);

			// if requested, merge the lists first into first list found
			if (matchMergeList.test(d.className)) {
				var lastList = null;
				for (var j = d.childNodes.length - 1; j >= 0; j--) {
					if (d.childNodes[j] && matchList.test(d.childNodes[j].tagName)) {
						var list = d.childNodes[j];
						if (lastList != null) {
							SortListInHTML.moveListElements(list, lastList);
							d.removeChild(lastList);
						}
						lastList = list;
					}
				}
			}

			// iterate over all lists directly under this div
			for (var j in d.childNodes) {
				if (d.childNodes[j] && matchList.test(d.childNodes[j].tagName)) {
					SortListInHTML.sortList(d.childNodes[j], ignoreCase);
				}
			}
		}
	}
}

// sort the elements in a list, ignoring case if requested
SortListInHTML.sortList = function(list, ignoreCase) {
	// remove all nodes to an array for sorting
	var nodes = new Array();
	while (list.firstChild) {
		var n = list.removeChild(list.firstChild);

		if (n.tagName == 'LI') {
			nodes[nodes.length] = n;
		}
	}

	// sort array
	nodes.sort(ignoreCase ? SortListInHTML.compareListElementsIgnore : SortListInHTML.compareListElements);

	// rebuild list
	for (var i = 0; i < nodes.length; i++) {
		list.appendChild(nodes[i]);
	}
	list.normalize();
}

// compare list elements - case-sensitive
SortListInHTML.compareListElements = function(el1, el2) {
	var val1 = el1.textContent || el1.innerText;
	var val2 = el2.textContent || el2.innerText;

	return (val1 == val2) ? 0 : ((val1 > val2) ? 1 : -1);
}

// compare list elements - case-insensitive
SortListInHTML.compareListElementsIgnore = function(el1, el2) {
	var val1 = el1.textContent || el1.innerText;
	var val2 = el2.textContent || el2.innerText;

	val1 = val1.toLowerCase();
	val2 = val2.toLowerCase();

	return (val1 == val2) ? 0 : ((val1 > val2) ? 1 : -1);
}

// move list elements from one list to another
SortListInHTML.moveListElements = function(target, source) {
	while (source.firstChild) {
		var n = source.removeChild(source.firstChild);

		if (n && n.tagName == 'LI') {
			target.appendChild(n);
		}
	}
}

// launch the object, it will activate when the page has loaded
var v_sortListInHTML = new SortListInHTML();
