/* * Expandable list implementation. * by David Lindquist <first name><at><last name><dot><net> * See: * http://www.gazingus.org/html/DOM-Scripted_Lists_Revisited.html * Modifies lists so that sublists can be hidden and shown by means of * a switch. The switch is a node inserted into the DOM tree as the * first child of the list item containing the sublist. */// The script will only be applied to lists containing this class name,// e.g.: <ul class="foo expandable">...</ul>.var CLASS_NAME = "expandable";// This value is the assumed initial display style for a sublist when it cannot// be determined by other means. See below.var DEFAULT_DISPLAY = "none";// The namespace to use when using this script in an XML context.var XMLNS = "http://www.w3.org/1999/xhtml";// The beginning of the title text for the switch when the sublist is collapsed.var CLOSED_PREFIX = "Expand list: ";// The beginning of the title text for the switch when the sublist is expanded.var OPENED_PREFIX = "Collapse list: ";/******************************************************************************/// Returns a copy of a string with leading and trailing whitespace removed.String.prototype.trim = function() {    return this.replace(/^\s+/, "").replace(/\s+$/, "");}// Walks the DOM tree starting at a given root element. Returns an// array of nodes of the specified type and conforming to the criteria// of the given filter function. The filter should return a boolean.function getNodesByType(root, type, filter) {    var node = root;    var nodes = [];    var next;    while (node != null) {        if (node.hasChildNodes())            node = node.firstChild;        else if (node != root && null != (next = node.nextSibling))            node = next;        else {            next = null;            for ( ; node != root; node = node.parentNode) {                next = node.nextSibling;                if (next != null) break;            }            node = next;        }        if (node != null && node.nodeType == type && filter(node))            nodes.push(node);    }    return nodes;}// Simulates the innerText property of IE and other browsers.// Mozilla/Firefox need this.function getInnerText(node) {    if (node == null || node.nodeType != 1)        return;    var text = "";    var textnodes = getNodesByType(node, 3, function() { return true; });    for (var i = 0; i < textnodes.length; i++)        text += textnodes[i].data;    return text;}function initExpandableLists() {    if (!document.getElementsByTagName) return;    // Top-level function to accommodate browsers that do not register    // a click event when a link is activated by the keyboard.    switchNode = function(id) {        var node = document.getElementById(id);        if (node && /^switch /.test(node.className)) node.onclick();    }    // Top-level function to be assigned as the event handler for the    // switch. This could have been bound to the handler as a closure,    // but closures are associated with memory leak problems in IE.    actuate = function() {        var sublist = this.parentNode.getElementsByTagName("ul")[0] ||                      this.parentNode.getElementsByTagName("ol")[0];        if (sublist.style.display == "block") {            sublist.style.display = "none";            this.firstChild.data = "[+]";            this.className = "switch off";            this.title = this.title.replace(OPENED_PREFIX, CLOSED_PREFIX);        } else {            sublist.style.display = "block";            this.firstChild.data = "[-]";            this.className = "switch on";            this.title = this.title.replace(CLOSED_PREFIX, OPENED_PREFIX);        }        return false;    }    // Create switch node from which the others will be cloned.    if (typeof document.createElementNS == "function")        var template = document.createElementNS(XMLNS, "a");    else        var template = document.createElement("a");    template.appendChild(document.createTextNode(" "));    var list, i = 0, j = 0;    var pattern = new RegExp("(^| )" + CLASS_NAME + "( |$)");    while ((list = document.getElementsByTagName("ul")[i++]) ||           (list = document.getElementsByTagName("ol")[j++]))    {        // Only lists with the given class name are processed.        if (pattern.test(list.className) == false) continue;        var item, k = 0;        while ((item = list.getElementsByTagName("li")[k++])) {            var sublist = item.getElementsByTagName("ul")[0] ||                          item.getElementsByTagName("ol")[0];            // No sublist under this list item. Skip it.            if (sublist == null) continue;            // Attempt to determine initial display style of the            // sublist so the proper symbol is used.            var symbol;            switch (sublist.style.display) {            case "none" : symbol = "[+]"; break;            case "block": symbol = "[-]"; break;            default:                var display = DEFAULT_DISPLAY;                if (sublist.currentStyle) {                    display = sublist.currentStyle.display;                } else if (document.defaultView &&                           document.defaultView.getComputedStyle &&                           document.defaultView.getComputedStyle(sublist, ""))                {                    var view = document.defaultView;                    var computed = view.getComputedStyle(sublist, "");                    display = computed.getPropertyValue("display");                }                symbol = (display == "none") ? "+" : "-";                // Explicitly set the display style to make sure it is                // set for the next read. If it is somehow the empty                // string, use the default value from the (X)HTML DTD.                sublist.style.display = display || "block";                break;            }            // This bit attempts to extract some text from the first            // child node of the list item to append to the title            // attribute of the switch.            var child = item.firstChild;            var text = "";            while (child) {                if (child.nodeType == 3 && "" != child.data.trim()) {                    text = child.data;                    break;                } else if (child.nodeType == 1 &&                           !/^[ou]l$/i.test(child.tagName))                {                    text = child.innerText || getInnerText(child);                    break;                }                child = child.nextSibling;            }            var actuator = template.cloneNode(true);            // a reasonably unique ID            var uid = "switch" + i + "-" + j + "-" + k;            actuator.id = uid;            actuator.href = "javascript:switchNode('" + uid + "')";            actuator.className = "switch " + ((symbol == "+") ? "off" : "on");            actuator.title = ((symbol == "+")                              ? CLOSED_PREFIX : OPENED_PREFIX) + text.trim();            actuator.firstChild.data = symbol;            actuator.onclick = actuate;            item.insertBefore(actuator, item.firstChild);        }    }}// FROM http://www.alistapart.com/articles/alternate/function setActiveStyleSheet(title) {  var i, a, main;  for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {    if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {      a.disabled = true;      if(a.getAttribute("title") == title) a.disabled = false;    }  }}function getActiveStyleSheet() {  var i, a;  for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {    if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title");  }  return null;}function getPreferredStyleSheet() {  var i, a;  for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {    if(a.getAttribute("rel").indexOf("style") != -1       && a.getAttribute("rel").indexOf("alt") == -1       && a.getAttribute("title")       ) return a.getAttribute("title");  }  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 expires = "";  document.cookie = name+"="+value+expires+"; path=/";}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;}//window.onload = function(e) {//  var cookie = readCookie("style");//  var title = cookie ? cookie : getPreferredStyleSheet();//  setActiveStyleSheet(title);//}window.onunload = function(e) {  var title = getActiveStyleSheet();  createCookie("style", title, 365);}// Props to Simon Willison:// http://simon.incutio.com/archive/2004/05/26/addLoadEventvar oldhandler = window.onload;window.onload = (typeof oldhandler == "function")    ? function() { oldhandler(); initExpandableLists(); } : initExpandableLists;var cookie = readCookie("style");var title = cookie ? cookie : getPreferredStyleSheet();setActiveStyleSheet(title);function ow(location) {	var load = window.open(location,'','width=450,scrollbars=1');}