/* Merged Plone Javascript file
 * This file is dynamically assembled from separate parts.
 * Some of these parts have 3rd party licenses or copyright information attached
 * Such information is valid for that section,
 * not for the entire composite file
 * originating files are separated by ----- filename.js -----
 */

/* ----- register_function.js ----- */
/* Essential javascripts, used a lot. 
 * These should be placed inline
 * We have to be certain they are loaded before anything that uses them 
 */

// check for ie5 mac
var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    &&
    navigator.userAgent.indexOf('Mac') != -1
)

// check for W3CDOM compatibility
var W3CDOM = (!bugRiddenCrashPronePieceOfJunk &&
               document.getElementsByTagName &&
               document.createElement);

// cross browser function for registering event handlers
function registerEventListener(elem, event, func) {
    if (elem.addEventListener) {
        elem.addEventListener(event, func, false);
        return true;
    } else if (elem.attachEvent) {
        var result = elem.attachEvent("on"+event, func);
        return result;
    }
    // maybe we could implement something with an array
    return false;
}

// cross browser function for unregistering event handlers
function unRegisterEventListener(elem, event, func) {
    if (elem.removeEventListener) {
        elem.removeEventListener(event, func, false);
        return true;
    } else if (elem.detachEvent) {
        var result = elem.detachEvent("on"+event, func);
        return result;
    }
    // maybe we could implement something with an array
    return false;
}

function registerPloneFunction(func) {
    // registers a function to fire onload.
    registerEventListener(window, "load", func);
}

function unRegisterPloneFunction(func) {
    // unregisters a function so it does not fire onload.
    unRegisterEventListener(window, "load", func);
}

function getContentArea() {
    // returns our content area element
    if (W3CDOM) {
        var node = document.getElementById('region-content');
        if (!node) {
            node = document.getElementById('content');
        }
        return node;
    }
} 


/* ----- plone_javascript_variables.js ----- */
// Global Plone variables that need to be accessible to the Javascripts
var portal_url = 'http://film.summacultura.de'
var form_modified_message = 'Your form has not been saved. All changes you have made will be lost'

/* ----- nodeutilities.js ----- */

function wrapNode(node, wrappertype, wrapperclass){
    /* utility function to wrap a node in an arbitrary element of type "wrappertype"
     * with a class of "wrapperclass" */
    wrapper = document.createElement(wrappertype)
    wrapper.className = wrapperclass;
    innerNode = node.parentNode.replaceChild(wrapper,node);
    wrapper.appendChild(innerNode)
}
function nodeContained(innernode, outernode){
    // check if innernode is contained in outernode
    var node
    node = innernode.parentNode;
    while (node != document){
        if (node == outernode){
            return true; 
            break
            }
        node=node.parentNode
        }
    return false
    }


/* ----- cookie_functions.js ----- */
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+"="+escape(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 unescape(c.substring(nameEQ.length,c.length));
        }
    }
    return null;
}

/* ----- livesearch.js ----- */
/*
// +----------------------------------------------------------------------+
// | Copyright (c) 2004 Bitflux GmbH                                      |
// +----------------------------------------------------------------------+
// | Licensed under the Apache License, Version 2.0 (the "License");      |
// | you may not use this file except in compliance with the License.     |
// | You may obtain a copy of the License at                              |
// | http://www.apache.org/licenses/LICENSE-2.0                           |
// | Unless required by applicable law or agreed to in writing, software  |
// | distributed under the License is distributed on an "AS IS" BASIS,    |
// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or      |
// | implied. See the License for the specific language governing         |
// | permissions and limitations under the License.                       |
// +----------------------------------------------------------------------+
// | Author: Bitflux GmbH <devel@bitflux.ch>                              |
// +----------------------------------------------------------------------+

*/
var liveSearchReq = false;
var t = null;
var liveSearchLast = "";
var queryTarget = "livesearch_reply?q=";

var searchForm = null;
var searchInput = null; 

var isIE = false;


var _cache = new Object();

var widthOffset=1;

function calculateWidth(){
}


function getElementDimensions(elemID) {
    var base = document.getElementById(elemID);
    var offsetTrail = base;
    var offsetLeft = 0;
    var offsetTop = 0;
    var width = 0;
    
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft;
        offsetTop += offsetTrail.offsetTop;
        offsetTrail = offsetTrail.offsetParent;
    }
    if (navigator.userAgent.indexOf("Mac") != -1 &&
        typeof document.body.leftMargin != "undefined") {
        offsetLeft += document.body.leftMargin;
        offsetTop += document.body.topMargin;
    }

    if(!isIE){
	width =  searchInput.offsetWidth-widthOffset*2;
    }
    else {
	width = searchInput.offsetWidth;
    }

    return { left:offsetLeft, 
	     top:offsetTop, 
	     width: width, 
             height: base.offsetHeight,
	     bottom: offsetTop + base.offsetHeight, 
	     right : offsetLeft + width};
}

function liveSearchInit() {
	searchInput = document.getElementById('searchGadget');
	if (searchInput == null || searchInput == undefined) return;
	
	if (navigator.userAgent.indexOf("Safari") > 0) {
		searchInput.addEventListener("keydown",liveSearchKeyPress,false);
		searchInput.addEventListener("focus",liveSearchDoSearch,false);
		searchInput.addEventListener("keydown",liveSearchStart, false); 
//		searchInput.addEventListener("blur",liveSearchHide,false);
	} else if (navigator.product == "Gecko") {
		searchInput.addEventListener("keypress",liveSearchKeyPress,false);
		searchInput.addEventListener("blur",liveSearchHideDelayed,false);
		searchInput.addEventListener("keypress",liveSearchStart, false); 
	} else {
		searchInput.attachEvent('onkeydown',liveSearchKeyPress);
		searchInput.attachEvent("onkeydown",liveSearchStart); 
//		searchInput.attachEvent("onblur",liveSearchHide);
		isIE = true;
	}
		
    
	searchInput.setAttribute("autocomplete","off");

	var pos = getElementDimensions('searchGadget');	
	result = document.getElementById('LSResult');
	pos.left = pos.left - result.offsetParent.offsetLeft + pos.width;
	result.style.display='none';
}


function liveSearchHideDelayed() {
	window.setTimeout("liveSearchHide()",400);
}
	
function liveSearchHide() { 
	document.getElementById("LSResult").style.display = "none";
	var highlight = document.getElementById("LSHighlight");
	if (highlight) {
		highlight.removeAttribute("id");
	}
}

function getFirstHighlight() {
    var set = getHits();
    return set[0];
}

function getLastHighlight() {
    var set = getHits();
    return set[set.length-1];
}

function getHits() {
    var res = document.getElementById("LSShadow");
    var set = res.getElementsByTagName('li');
    return set
}

function findChild(object, specifier) {
    var cur = object.firstChild;
    try {
	while (cur != undefined) {
	    cur = cur.nextSibling;
	    if (specifier(cur) == true) return cur;
	}
    } catch(e) {};
    return null;
    
}

function findNext(object, specifier) {
 var cur = object;
 try {
 while (cur != undefined) {

	cur = cur.nextSibling;
	if (cur.nodeType==3) cur=cur.nextSibling;
	
	if (cur != undefined) {
	    if (specifier(cur) == true) return cur;
    } else { break }
 }
 } catch(e) {};
 return null;
}

function findPrev(object, specifier) {
 var cur = object;
 try {
        cur = cur.previousSibling;
        if (cur.nodeType==3) cur=cur.previousSibling;
        if (cur!=undefined) {
            if (specifier(cur) == true) 
                return cur;
        } 
 } catch(e) {};
 return null;
}


function liveSearchKeyPress(event) {
	if (event.keyCode == 40 )
	//KEY DOWN
	{
		highlight = document.getElementById("LSHighlight");
		if (!highlight) {
		    highlight = getFirstHighlight();
		} else {
			highlight.removeAttribute("id");
			highlight = findNext(highlight, function (o) {return o.className =="LSRow";});

		}
		if (highlight) {
			highlight.setAttribute("id","LSHighlight");
		} 
		if (!isIE) { event.preventDefault(); }
	} 
	//KEY UP
	else if (event.keyCode == 38 ) {
		highlight = document.getElementById("LSHighlight");
		if (!highlight) {
		    highlight = getLastHighlight();
		} 
		else {
			highlight.removeAttribute("id");
			highlight = findPrev(highlight, function (o) {return o.className=='LSRow';});
		}
		if (highlight) {
				highlight.setAttribute("id","LSHighlight");
		}
		if (!isIE) { event.preventDefault(); }
	} 
	//ESC
	else if (event.keyCode == 27) {
		highlight = document.getElementById("LSHighlight");
		if (highlight) {
			highlight.removeAttribute("id");
		}
		document.getElementById("LSResult").style.display = "none";
	} 
}
function liveSearchStart(event) {
	if (t) {
		window.clearTimeout(t);
	}
	code = event.keyCode;
	if (code!=40 && code!=38 && code!=27 && code!=37 && code!=39) {
		t = window.setTimeout("liveSearchDoSearch()",200);
	} 
}

function liveSearchDoSearch() {

	if (typeof liveSearchRoot == "undefined") {
		liveSearchRoot = "";
	}
	if (typeof liveSearchRootSubDir == "undefined") {
		liveSearchRootSubDir = "";
	}

	if (liveSearchLast != searchInput.value) {
	if (liveSearchReq && liveSearchReq.readyState < 4) {
		liveSearchReq.abort();
	}
	if ( searchInput.value == "") {
		liveSearchHide();
		return false;
	}

	// Do we have cached results
	var result = _cache[searchInput.value];
	if (result) {
		showResult(result);	
		return;
	}
	liveSearchReq = new XMLHttpRequest();
	liveSearchReq.onreadystatechange= liveSearchProcessReqChange;
	liveSearchReq.open("GET", liveSearchRoot + queryTarget + searchInput.value );
	liveSearchLast = searchInput.value;
	liveSearchReq.send(null);
	}
}

function showResult(result) {
  var  res = document.getElementById("LSResult");
  res.style.display = "block";
  var  sh = document.getElementById("LSShadow");
  sh.innerHTML = result;
}

function liveSearchProcessReqChange() {
	if (liveSearchReq.readyState == 4) {
		if (liveSearchReq.status > 299 || liveSearchReq.status < 200  ||
			liveSearchReq.responseText.length < 10) return;	
	showResult(liveSearchReq.responseText);
	_cache[liveSearchLast] = liveSearchReq.responseText;
	}
}

function liveSearchSubmit() {
	var highlight = document.getElementById("LSHighlight");
	
	if (highlight){
		target = highlight.getElementsByTagName('a')[0];
		window.location = liveSearchRoot + liveSearchRootSubDir + target;
		return false;
	} 
	else {
		return true;
	}
}



if (window.addEventListener) window.addEventListener("load",liveSearchInit,false);
else if (window.attachEvent) window.attachEvent("onload", liveSearchInit);



/* ----- fullscreenmode.js ----- */

function setDisplayMode(item, state) {
// change the display prop of a div to none/block if the div exists
    if (document.getElementById(item) != null) {
        document.getElementById(item).style.display = state;
    }
}
function toggleFullScreenMode() {
    // toggle the display prop of the columns    
    if (document.getElementById('portal-column-one').style.display == 'none') {
        try {
            setDisplayMode('portal-logo', 'block');
            setDisplayMode('portal-siteactions', 'block');
            setDisplayMode('portal-column-one', 'table-cell');
            setDisplayMode('portal-column-two', 'table-cell');
        } catch (e) {
            // silly IE does not understand display:table-cell, so we must workaround
            // alert(e);
            if (e == "[object Error]") {
                setDisplayMode('portal-logo', 'block');
                setDisplayMode('portal-siteactions', 'block');
                setDisplayMode('portal-column-one', 'block');
                setDisplayMode('portal-column-two', 'block');
            } else {
                throw e;
            }
        }
        // set cookie
        createCookie('fullscreenMode', '');
    } else {
        setDisplayMode('portal-logo', 'none');
        setDisplayMode('portal-siteactions', 'none');
        setDisplayMode('portal-column-one', 'none');
        setDisplayMode('portal-column-two', 'none');
        createCookie('fullscreenMode', '1');
    }
}

function fullscreenModeLoad() {
// based on cookie hide div
        if (readCookie('fullscreenMode') == '1') {        
        setDisplayMode('portal-logo', 'none');
        setDisplayMode('portal-siteactions', 'none');
        setDisplayMode('portal-column-one', 'none');
        setDisplayMode('portal-column-two', 'none');    
        }
}
registerPloneFunction(fullscreenModeLoad)

/* ----- select_all.js ----- */
// Functions for selecting all checkboxes in folder_contents/search_form view
function selectAll(id, formName) {
    // Get the elements. if formName is provided, get the elements inside the form
    if (formName==null) {
        checkboxes = document.getElementsByName(id)
        for (i = 0; i < checkboxes.length; i++){
            checkboxes[i].checked = true ;
            }
    } else {
        for (i=0; i<document.forms[formName].elements.length;i++){
            if (document.forms[formName].elements[i].name==id){
                document.forms[formName].elements[i].checked=true; 
                }
            }
        }
    }
function deselectAll(id, formName) {
    if (formName==null) {
        checkboxes = document.getElementsByName(id)
        for (i = 0; i < checkboxes.length; i++){
            checkboxes[i].checked = false ;}
    } else {
        for (i=0; i<document.forms[formName].elements.length;i++){
            if (document.forms[formName].elements[i].name==id){
                document.forms[formName].elements[i].checked=false;
                }
            }
        }
    }
function toggleSelect(selectbutton, id, initialState, formName) {
    /* required selectbutton: you can pass any object that will function as a toggle
     * optional id: id of the the group of checkboxes that needs to be toggled (default=ids:list
     * optional initialState: initial state of the group. (default=false)
     * e.g. folder_contents is false, search_form=true because the item boxes
     * are checked initially.
     * optional formName: name of the form in which the boxes reside, use this if there are more
     * forms on the page with boxes with the same name
     */
    id=id || 'ids:list'  // defaults to ids:list, this is the most common usage

    if (selectbutton.isSelected==null){
        initialState=initialState || false;
        selectbutton.isSelected=initialState;
        }
    /* create and use a property on the button itself so you don't have to 
     * use a global variable and we can have as much groups on a page as we like.
     */
    if (selectbutton.isSelected == false) {
        selectbutton.setAttribute('src', portal_url + '/select_none_icon.gif');
        selectbutton.isSelected=true;
        return selectAll(id, formName);
    } else {
        selectbutton.setAttribute('src',portal_url + '/select_all_icon.gif');
        selectbutton.isSelected=false;
        return deselectAll(id, formName);
        }
    } 

/* ----- plone_menu.js ----- */
// Do *NOT* depend on this menu code, it *will* be rewritten in later versions
// of Plone. This is a quick fix that will be replaced with something more
// elegant later.

/* <!-- compression status: disabled --> (this is for http compression) */

/*




*/
// Code to determine the browser and version.

function Browser() {
    var ua, s, i;
    
    this.isIE = false; // Internet Explorer
    this.isNS = false; // Netscape
    this.version = null;
    
    ua = navigator.userAgent;
    
    s = "MSIE";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isIE = true;
        this.version = parseFloat(ua.substr(i + s.length));
        return;
    }  
    s = "Netscape6/";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isNS = true;
        this.version = parseFloat(ua.substr(i + s.length));
        return;
    }
    
    // Treat any other "Gecko" browser as NS 6.1.
    
    s = "Gecko";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isNS = true;
        this.version = 6.1;
        return;
    }
}
var browser = new Browser();

// Code for handling the menu bar and active button.
var activeButton = null;

// Capture mouse clicks on the page so any active button can be
// deactivated.

if (browser.isIE){
    document.onmousedown = pageMousedown;
}else{
    document.addEventListener("mousedown", pageMousedown, true);
}

function pageMousedown(event) {
    
    var el;
    
    // If there is no active button, exit.
    
    if (activeButton == null){
        return;
        }
    
    // Find the element that was clicked on.
    
    if (browser.isIE){
        el = window.event.srcElement;
    }else{
        el = (event.target.tagName ? event.target : event.target.parentNode);
    }
    // If the active button was clicked on, exit.
    
    if (el == activeButton){
        return
        };
    
    // If the element is not part of a menu, reset and clear the active
    // button.
    
    if (getContainerWith(el, "UL", "actionMenu") == null) {
        resetButton(activeButton);
        activeButton = null;
    }
}

function buttonClick(event, menuId) {
    
    var button;
    
    // Get the target button element.
    
    if (browser.isIE){
        button = window.event.srcElement;
    }else{
        if (event)
          button = event.currentTarget;
        else
          return false;
    }
    // Blur focus from the link to remove that annoying outline.
    
    button.blur();
    
    // Associate the named menu to this button if not already done.
    // Additionally, initialize menu display.
    
    if (button.menu == null) {
        button.menu = document.getElementById(menuId);
        if (button.menu.isInitialized == null) {
            menuInit(button.menu);
        }
    }
    
    // Reset the currently active button, if any.
    
    if (activeButton != null){
        resetButton(activeButton);
        }
    // Activate this button, unless it was the currently active one.
    
    if (button != activeButton) {
        depressButton(button);
        activeButton = button;
    }else{
        activeButton = null;
    }
    return false;
}

function buttonMouseover(event, menuId) {

    var button;
    
    // Find the target button element.
    
    if (browser.isIE){
        button = window.event.srcElement;
    }else{
        button = event.currentTarget;
    }
    // If any other button menu is active, make this one active instead.
    
    if (activeButton != null && activeButton != button){
        buttonClick(event, menuId);
        }
}

function depressButton(button) {

    var x, y;
    
    // Update the button's style class to make it look like it's
    // depressed.
    
    button.className += " menuButtonActive";
    
    // Make the associated drop down menu visible
    
    vis = button.menu.style.visibility;
    button.menu.style.visibility = (vis == "hidden" || vis == '') ? "visible" : "hidden";
}

function resetButton(button) {

    // Restore the button's style class.
    
    removeClassName(button, "menuButtonActive");
    
    // Hide the button's menu, first closing any sub menus.
    
    if (button.menu != null) {
        closeSubMenu(button.menu);
        button.menu.style.visibility = "hidden";
    }
}

// Code to handle the menus and sub menus.

function menuMouseover(event) {
    
    var menu;
    
    // Find the target menu element.
    
    if (browser.isIE){
        menu = getContainerWith(window.event.srcElement, "UL", "actionMenu");
    }else{
        menu = event.currentTarget;
    }
    
    // Close any active sub menu.
    
    if (menu.activeItem != null){
        closeSubMenu(menu);
        }
}

function menuItemMouseover(event, menuId) {

    var item, menu, x, y;
    
    // Find the target item element and its parent menu element.
    
    if (browser.isIE){
        item = getContainerWith(window.event.srcElement, "LI", "menuItem");
    }else{
        item = event.currentTarget;
        menu = getContainerWith(item, "UL", "menu");
    }
    // Close any active sub menu and mark this one as active.
    
    if (menu.activeItem != null){
        closeSubMenu(menu);
        menu.activeItem = item;
    }
    
    // Highlight the item element.
    
    item.className += " menuItemHighlight";
    
    // Initialize the sub menu, if not already done.
    
    if (item.subMenu == null) {
        item.subMenu = document.getElementById(menuId);
        if (item.subMenu.isInitialized == null){
            menuInit(item.subMenu);
            }
    }
    
    // Get position for submenu based on the menu item.
    
    x = getPageOffsetLeft(item) + item.offsetWidth;
    y = getPageOffsetTop(item);
    
    // Adjust position to fit in view.
    
    var maxX, maxY;
    
    if (browser.isNS) {
        maxX = window.scrollX + window.innerWidth;
        maxY = window.scrollY + window.innerHeight;
    }
    else if (browser.isIE) {
        maxX = (document.documentElement.scrollLeft != 0 ? document.documentElement.scrollLeft : document.body.scrollLeft)
        + (document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
        maxY = (document.documentElement.scrollTop != 0 ? document.documentElement.scrollTop : document.body.scrollTop)
        + (document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
    }
    maxX -= item.subMenu.offsetWidth;
    maxY -= item.subMenu.offsetHeight;
    
    if (x > maxX){
        x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth  + (menu.offsetWidth - item.offsetWidth));
        y = Math.max(0, Math.min(y, maxY));
    }
    // Position and show it.
    
    item.subMenu.style.left = x + "px";
    item.subMenu.style.top = y + "px";
    item.subMenu.style.visibility = "visible";
    
    // Stop the event from bubbling.
    
    if (browser.isIE){
        window.event.cancelBubble = true;
    }else{
        event.stopPropagation();
    }
}

function closeSubMenu(menu) {
    
    if (menu == null || menu.activeItem == null)
    return;
    
    // Recursively close any sub menus.
    
    if (menu.activeItem.subMenu != null) {
    closeSubMenu(menu.activeItem.subMenu);
    menu.activeItem.subMenu.style.visibility = "hidden";
    menu.activeItem.subMenu = null;
    }
    removeClassName(menu.activeItem, "menuItemHighlight");
    menu.activeItem = null;
}

// Code to initialize menus.

function menuInit(menu) {
    
    var itemList, spanList;
    var textEl, arrowEl;
    var itemWidth;
    var w, dw;
    var i, j;
    
    // For IE, replace arrow characters.
    
    if (browser.isIE) {
        menu.style.lineHeight = "2.5ex";
        spanList = menu.getElementsByTagName("SPAN");
        for (i = 0; i < spanList.length; i++)
        if (hasClassName(spanList[i], "menuItemArrow")) {
        spanList[i].style.fontFamily = "Webdings";
        spanList[i].firstChild.nodeValue = "4";
    }
}

// Find the width of a menu item.

itemList = menu.getElementsByTagName("A");
if (itemList.length > 0){
    itemWidth = itemList[0].offsetWidth;
}else{
    return;
}
// For items with arrows, add padding to item text to make the
// arrows flush right.

for (i = 0; i < itemList.length; i++) {
    spanList = itemList[i].getElementsByTagName("A");
    textEl = null;
    arrowEl = null;
    for (j = 0; j < spanList.length; j++) {
    if (hasClassName(spanList[j], "menuItemText")){
        textEl = spanList[j];
        }
    if (hasClassName(spanList[j], "menuItemArrow")){
        arrowEl = spanList[j];
        }
    }
    if (textEl != null && arrowEl != null){
    textEl.style.paddingRight = (itemWidth - (textEl.offsetWidth + arrowEl.offsetWidth)) + "px";
    }
}

// Fix IE hover problem by setting an explicit width on first item of
// the menu.

if (browser.isIE) {
    w = itemList[0].offsetWidth;
    itemList[0].style.width = w + "px";
    dw = itemList[0].offsetWidth - w;
    w -= dw;
    itemList[0].style.width = w + "px";
}

// Mark menu as initialized.

menu.isInitialized = true;
}

// General utility functions.

    function getContainerWith(node, tagName, className) {
    
    // Starting with the given node, find the nearest containing element
    // with the specified tag name and style class.
    
    while (node != null) {
        if (node.tagName != null && node.tagName == tagName && hasClassName(node, className)){
            return node;
    }
    node = node.parentNode;
    }
    return node;
}

    function hasClassName(el, name) {
    
    var i, list;
    
    // Return true if the given element currently has the given class
    // name.
    
    list = el.className.split(" ");
    for (i = 0; i < list.length; i++)
    if (list[i] == name){
        return true;
        }
    return false;
}

function removeClassName(el, name) {
    
    var i, curList, newList;
    
    if (el.className == null){
        return;
        }
    // Remove the given class name from the element's className property.
    
    newList = new Array();
    curList = el.className.split(" ");
    for (i = 0; i < curList.length; i++){
        if (curList[i] != name){
            newList.push(curList[i]);
            el.className = newList.join(" ");
        }
    }
}
function getPageOffsetLeft(el) {

var x;

// Return the x coordinate of an element relative to the page.

x = el.offsetLeft;
if (el.offsetParent != null)
x += getPageOffsetLeft(el.offsetParent);

return x;
}

function getPageOffsetTop(el) {
    
    var y;
    
    // Return the x coordinate of an element relative to the page.
    
    y = el.offsetTop;
    if (el.offsetParent != null){
        y += getPageOffsetTop(el.offsetParent);
    }
    return y;
}


/* ----- collapsiblesections.js ----- */
function activateCollapsibles(){
    /*
     * a script that searches for sections that can be (or are already) collapsed
     * - and enables the collapse-behavior

     * usage : give the class "collapsible" to a fieldset
     * also , give it a <legend> with some descriptive text.
     * you can also add the class "collapsed" amounting to a total of <fieldset class="collapsible collapsed">
     * to make the section pre-collapsed
     */

    // terminate if we hit a non-compliant DOM implementation
    if (! document.getElementsByTagName){return false};
    if (! document.getElementById){return false};

    // only search in the content-area
    contentarea = getContentArea()
    if (! contentarea){return false}

    // gather all objects that are to be collapsed
    // we only do fieldsets for now. perhaps DIVs later is it is needed...
    collapsibles = contentarea.getElementsByTagName('fieldset');

    for (i=0; i < collapsibles.length; i++) {
        if (collapsibles[i].className.indexOf('collapsible')== -1 ) {
            continue;
        }
        
        fieldset = collapsibles[i]
        legends = fieldset.getElementsByTagName('LEGEND')
        /*
         * get the legend
         * if there is no legend, we do not touch the fieldset at all.
         * we assume that if there is a legend, there is only one.
         * nothing else makes any sense
         */
        if (! legends.length) {
            continue;
        }
        legend = legends[0]

        // add the icon/button with its functionality to the legend
        icon = document.createElement('img');
        icon.setAttribute('src','treeExpanded.gif')
        icon.setAttribute('class','collapseIcon')
        icon.setAttribute('height','9')
        icon.setAttribute('width','9')

        
        // insert the icon icon at the start of the legend
        legend.insertBefore(icon,legend.firstChild)

        /*
         * create a DOM fragment to represent the collapsed fieldset
         * it's a div + span, very similar to fieldset + legend, but I couldn't
         * make fieldset collapse to a single line no matter what I tried. -- NeilK.
         */
        
        cFieldset = document.createElement('div');
        cFieldset.setAttribute('class','collapsedFieldset');
        
        cLegend = document.createElement('span');
        cLegend.setAttribute('class', 'collapsedLegend');
        var legendChildren = legend.childNodes;
        for (i = 0; i < legendChildren.length; i++) {
            elm = legendChildren[i].cloneNode(true);
            if (i == 0 && elm.nodeName == 'IMG') { // it's the icon
                elm.setAttribute('src','treeCollapsed.gif');
            }    
            cLegend.appendChild(elm);
        }
        
        cFieldset.appendChild(cLegend)
     
        new Collapsible();  // hack for some old browsers to wake it up.
        c = new Collapsible(fieldset, cFieldset, legend, cLegend);
        c.init();
    }
}
    
registerPloneFunction(activateCollapsibles)

function addHandler(target,eventName,obj,handlerName) { 
    fn = function(e){obj[handlerName](e)};
    if ( window.addEventListener ) { 
         target.addEventListener(eventName, fn, false);
    } else if ( window.attachEvent ) { 
         target.attachEvent("on" + eventName, fn);
    } 
}


// defines two nodes that are siblings, clicking on one hides itself
// and reveals the other.
function Collapsible(expanded, collapsed, collapseButton, expandButton) {
    this.expanded = expanded;
    this.collapsed = collapsed;
    this.expandButton = expandButton;
    this.collapseButton = collapseButton;
}



Collapsible.prototype.init = function() {
    
    // add handlers to collapse/expand. 
    addHandler(this.collapseButton, "click", this, "collapse")
    addHandler(this.expandButton, "click", this, "expand")
    
//    addListener(this.collapseButton, closure(this.collapse) );
//  addListener(this.expandButton, closure(this.expand) );
    
    /* by default, show expanded, 
     * unless expanded class name also has 
     * 'collapsed' in it, i.e. <fieldset class="collapsible collapsed">
     */
    if (this.expanded.className.indexOf('collapsed') == -1 ) {
        this.collapse();
    } else {
        this.expand();
    }
+
    // assumption: expanded is already in document, has parent node.
    this.expanded.parentNode.insertBefore( this.collapsed, this.expanded );
}

Collapsible.prototype.collapse = function() {
    this.expanded.style.display = 'none';
    this.collapsed.style.display = 'block';
}    

Collapsible.prototype.expand = function() {
    this.expanded.style.display = 'block';
    this.collapsed.style.display = 'none';
}    


/* ----- highlightsearchterms.js ----- */
function climb(node, word){
     // traverse childnodes
    if (! node){return false}
    if (node.hasChildNodes) {
        var i;
        for (i=0;i<node.childNodes.length;i++) {
            climb(node.childNodes[i],word);
        }
        if (node.nodeType == 3){
            checkforhighlight(node, word);
           // check all textnodes. Feels inefficient, but works
        }
    }
}

function checkforhighlight(node,word) {
    ind = node.nodeValue.toLowerCase().indexOf(word.toLowerCase())
    if (ind != -1) {
        if (node.parentNode.className != "highlightedSearchTerm"){
            par = node.parentNode;
            contents = node.nodeValue;
        
            // make 3 shiny new nodes
            hiword = document.createElement("span");
            hiword.className = "highlightedSearchTerm";
            hiword.appendChild(document.createTextNode(contents.substr(ind,word.length)));
            par.insertBefore(document.createTextNode(contents.substr(0,ind)),node);
            par.insertBefore(hiword,node);
            par.insertBefore(document.createTextNode(contents.substr(ind+word.length)),node);
            par.removeChild(node);
        }
    } 
}  
function highlightSearchTerm() {
    // search-term-highlighter function --  Geir Bækholt
    query = window.location.search
    // _robert_ ie 5 does not have decodeURI 
    if (typeof decodeURI != 'undefined'){
        query = unescape(decodeURI(query)) // thanks, Casper 
    }
    else {
        return false
    }
    if (query){
        var qfinder = new RegExp()
        qfinder.compile("searchterm=([^&]*)","gi")
        qq = qfinder.exec(query)
        if (qq && qq[1]){
            query = qq[1]
            if (!query){return false}
            queries = query.replace(/\+/g,' ').split(/\s+/)            
            // make sure we start the right place so we don't higlight menuitems or breadcrumb
            contentarea = getContentArea();
            for (q=0;q<queries.length;q++) {
                // don't highlight reserved catalog search terms
                if (queries[q].toLowerCase() != 'not'
                    && queries[q].toLowerCase() != 'and'
                    && queries[q].toLowerCase() != 'or') {
                    climb(contentarea,queries[q]);
                }
            }
        }
    }
}
registerPloneFunction(highlightSearchTerm);


/* ----- first_input_focus.js ----- */
// Focus on error 
function setFocus(){
    var xre = new RegExp(/\berror\b/);
    // Search only forms to avoid spending time on regular text
    for (var f = 0; (formnode = document.getElementsByTagName('form').item(f)); f++){
        // Search for errors first, focus on first error if found
        for (var i = 0; (node = formnode.getElementsByTagName('div').item(i)); i++) {
            if (xre.exec(node.className)){
                for (var j = 0; (inputnode = node.getElementsByTagName('input').item(j)); j++) {
                    try {
                        if (inputnode.focus) { // check availability first
                            inputnode.focus();
                            return;
                        }
                    } catch(e) {
                        // try next one, this can happen with a hidden or
                        // invisible input field
                    }
                }
            }
        }
    }
}
registerPloneFunction(setFocus)


/* ----- folder_contents_filter.js ----- */
// Actions used in the folder_contents view
function submitFolderAction(folderAction) {
    document.folderContentsForm.action = document.folderContentsForm.action+'/'+folderAction;
    document.folderContentsForm.submit();
}

function submitFilterAction() {
    document.folderContentsForm.action = document.folderContentsForm.action+'/folder_contents';
    filter_selection=document.getElementById('filter_selection');
    for (var i =0; i < filter_selection.length; i++){
        if (filter_selection.options[i].selected) {
            if (filter_selection.options[i].value=='#') {
                document.folderContentsForm.filter_state.value='clear_view_filter';
            }
            else {
                document.folderContentsForm.filter_state.value='set_view_filter';
            }
        }
    }
    document.folderContentsForm.submit();
}



/* ----- folder_contents_hideAddItems.js ----- */
// function to hide the traditional add items pull down menu.

function hideTraditionalAddItemPullDown() {
    // Get the old style Add Item pulldown. We already have
    // such a menu. This is only for system that don't have javascript
    // so we can savely remove it.
    pullDown = document.getElementById('traditional-add-item-pulldown');
    if (pullDown) { 
        pullDown.style.display='none';
    }
}

registerPloneFunction(hideTraditionalAddItemPullDown)

/* ----- styleswitcher.js ----- */
// StyleSwitcher functions written by Paul Sowden
function setActiveStyleSheet(title, reset) {
    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;
        }
    }
    if (reset == 1) {
    createCookie("wstyle", title, 365);
    }
}

function setStyle() {
    var style = readCookie("wstyle");
    if (style != null) {
        setActiveStyleSheet(style, 0);
    }
}
registerPloneFunction(setStyle);




/* ----- table_sorter.js ----- */

/********* Table sorter script *************/
// Table sorter script, thanks to Geir Bækholt for this.
// DOM table sorter originally made by Paul Sowden 

function compare(a,b)
{
    au = new String(a);
    bu = new String(b);

    if (au.charAt(4) != '-' && au.charAt(7) != '-')
    {
    var an = parseFloat(au)
    var bn = parseFloat(bu)
    }
    if (isNaN(an) || isNaN(bn))
        {as = au.toLowerCase()
         bs = bu.toLowerCase()
        if (as > bs)
            {return 1;}
        else
            {return -1;}
        }
    else {
    return an - bn;
    }
}
function getConcatenedTextContent(node) {
    var _result = "";
      if (node == null) {
            return _result;
      }
    var childrens = node.childNodes;
    var i = 0;
    while (i < childrens.length) {
        var child = childrens.item(i);
        switch (child.nodeType) {
            case 1: // ELEMENT_NODE
            case 5: // ENTITY_REFERENCE_NODE
                _result += getConcatenedTextContent(child);
                break;
            case 3: // TEXT_NODE
            case 2: // ATTRIBUTE_NODE
            case 4: // CDATA_SECTION_NODE
                _result += child.nodeValue;
                break;
            case 6: // ENTITY_NODE
            case 7: // PROCESSING_INSTRUCTION_NODE
            case 8: // COMMENT_NODE
            case 9: // DOCUMENT_NODE
            case 10: // DOCUMENT_TYPE_NODE
            case 11: // DOCUMENT_FRAGMENT_NODE
            case 12: // NOTATION_NODE
                // skip
                break;
        }
        i ++;
    }
    return _result;
}

function sort(e) {
    var el = window.event ? window.event.srcElement : e.currentTarget;

    // a pretty ugly sort function, but it works nonetheless
    var a = new Array();
    // check if the image or the th is clicked. Proceed to parent id it is the image
    // NOTE THAT nodeName IS UPPERCASE
    if (el.nodeName == 'IMG') el = el.parentNode;
    //var name = el.firstChild.nodeValue;
    // This is not very robust, it assumes there is an image as first node then text
    var name = el.childNodes.item(1).nodeValue;
    var dad = el.parentNode;
    var node;
    
    // kill all arrows
    for (var im = 0; (node = dad.getElementsByTagName("th").item(im)); im++) {
        // NOTE THAT nodeName IS IN UPPERCASE
        if (node.lastChild.nodeName == 'IMG')
        {
            lastindex = node.getElementsByTagName('img').length - 1;
            node.getElementsByTagName('img').item(lastindex).setAttribute('src',portal_url + '/arrowBlank.gif');
        }
    }
    
    for (var i = 0; (node = dad.getElementsByTagName("th").item(i)); i++) {
        var xre = new RegExp(/\bnosort\b/);
        // Make sure we are not messing with nosortable columns, then check second node.
        if (!xre.exec(node.className) && node.childNodes.item(1).nodeValue == name) 
        {
            //window.alert(node.childNodes.item(1).nodeValue;
            lastindex = node.getElementsByTagName('img').length -1;
            node.getElementsByTagName('img').item(lastindex).setAttribute('src',portal_url + '/arrowUp.gif');
            break;
        }
    }

    var tbody = dad.parentNode.parentNode.getElementsByTagName("tbody").item(0);
    for (var j = 0; (node = tbody.getElementsByTagName("tr").item(j)); j++) {

        // crude way to sort by surname and name after first choice
        a[j] = new Array();
        a[j][0] = getConcatenedTextContent(node.getElementsByTagName("td").item(i));
        a[j][1] = getConcatenedTextContent(node.getElementsByTagName("td").item(1));
        a[j][2] = getConcatenedTextContent(node.getElementsByTagName("td").item(0));        
        a[j][3] = node;
    }

    if (a.length > 1) {
    
        a.sort(compare);

        // not a perfect way to check, but hell, it suits me fine
        if (a[0][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(0).getElementsByTagName("td").item(i))
           && a[1][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(1).getElementsByTagName("td").item(i))) 
        {
            a.reverse();
            lastindex = el.getElementsByTagName('img').length - 1;
            el.getElementsByTagName('img').item(lastindex).setAttribute('src', portal_url + '/arrowDown.gif');
        }

    }
    
    for (var j = 0; j < a.length; j++) {
        tbody.appendChild(a[j][3]);
    }
}
    
function initalizeTableSort(e) {
    var tbls = document.getElementsByTagName('table');
    for (var t = 0; t < tbls.length; t++)
        {
        // elements of class="listing" can be sorted
        var re = new RegExp(/\blisting\b/)
        // elements of class="nosort" should not be sorted
        var xre = new RegExp(/\bnosort\b/)
        if (re.exec(tbls[t].className) && !xre.exec(tbls[t].className))
        {
            try {
               var thead = tbls[t].getElementsByTagName("thead").item(0);
                var node;
                // set up blank spaceholder gifs
                blankarrow = document.createElement('img');
                blankarrow.setAttribute('src', portal_url + '/arrowBlank.gif');
                blankarrow.setAttribute('height',6);
                blankarrow.setAttribute('width',9);
                // the first sortable column should get an arrow initially.
                initialsort = false;
                for (var i = 0; (node = thead.getElementsByTagName("th").item(i)); i++) {
                    // check that the columns does not have class="nosort"
                    if (!xre.exec(node.className)) {
                        node.insertBefore(blankarrow.cloneNode(1), node.firstChild);
                        if (!initialsort) {
                            initialsort = true;
                            uparrow = document.createElement('img');
                            uparrow.setAttribute('src', portal_url + '/arrowUp.gif');
                            uparrow.setAttribute('height',6);
                            uparrow.setAttribute('width',9);
                            node.appendChild(uparrow);
                        } else {
                            node.appendChild(blankarrow.cloneNode(1));
                        }
    
                        if (node.addEventListener) node.addEventListener("click",sort,false);
                        else if (node.attachEvent) node.attachEvent("onclick",sort);
                    }
                }
            } catch(er) {}
        }
    }
}   
// **** End table sort script ***
registerPloneFunction(initalizeTableSort)   



/* ----- calendar_formfield.js ----- */
// jscalendar glue -- Leonard Norrgård <vinsci@*>
// This function gets called when the user clicks on some date.
function onJsCalendarDateUpdate(cal) {
    var year   = cal.params.input_id_year;
    var month  = cal.params.input_id_month;
    var day    = cal.params.input_id_day;
    // var hour   = cal.params.input_id_hour;
    // var minute = cal.params.input_id_minute;

    // cal.params.inputField.value = cal.date.print('%Y/%m/%d %H:%M'); // doesn't work in Opera, don't use time now
    //cal.params.inputField.value = cal.date.print('%Y/%m/%d'); // doesn't work in Opera
    var daystr = '' + cal.date.getDate();
    if (daystr.length == 1)
    	daystr = '0' + daystr;
    var monthstr = '' + (cal.date.getMonth()+1);
    if (monthstr.length == 1)
	monthstr = '0' + monthstr;
    cal.params.inputField.value = '' + cal.date.getFullYear() + '/' + monthstr + '/' + daystr

    year.value  = cal.params.inputField.value.substring(0,4);
    month.value = cal.params.inputField.value.substring(5,7);
    day.value   = cal.params.inputField.value.substring(8,10);
    // hour.value  = cal.params.inputField.value.substring(11,13);
    // minute.value= cal.params.inputField.value.substring(14,16);
}


function showJsCalendar(input_id_anchor, input_id, input_id_year, input_id_month, input_id_day, input_id_hour, input_id_minute, yearStart, yearEnd) {
    // do what jscalendar-x.y.z/calendar-setup.js:Calendar.setup would do
    var input_id_anchor = document.getElementById(input_id_anchor);
    var input_id = document.getElementById(input_id);
    var input_id_year = document.getElementById(input_id_year);
    var input_id_month = document.getElementById(input_id_month);
    var input_id_day = document.getElementById(input_id_day);
    // var input_id_hour = document.getElementById(input_id_hour);
    // var input_id_minute = document.getElementById(input_id_minute);
    var format = 'y/mm/dd';

    var dateEl = input_id;
    var mustCreate = false;
    var cal = window.calendar;

    var params = {
        'range' : [yearStart, yearEnd],
        inputField : input_id,
        input_id_year : input_id_year,
        input_id_month: input_id_month,
        input_id_day  : input_id_day
        // input_id_hour : input_id_hour,
        // input_id_minute: input_id_minute
    };

    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

    param_default("inputField",     null);
    param_default("displayArea",    null);
    param_default("button",         null);
    param_default("eventName",      "click");
    param_default("ifFormat",       "%Y/%m/%d");
    param_default("daFormat",       "%Y/%m/%d");
    param_default("singleClick",    true);
    param_default("disableFunc",    null);
    param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
    param_default("dateText",       null);
    param_default("firstDay",       1);
    param_default("align",          "Bl");
    param_default("range",          [1900, 2999]);
    param_default("weekNumbers",    true);
    param_default("flat",           null);
    param_default("flatCallback",   null);
    param_default("onSelect",       null);
    param_default("onClose",        null);
    param_default("onUpdate",       null);
    param_default("date",           null);
    param_default("showsTime",      false);
    param_default("timeFormat",     "24");
    param_default("electric",       true);
    param_default("step",           2);
    param_default("position",       null);
    param_default("cache",          false);
    param_default("showOthers",     false);
    param_default("multiple",       null);

    if (!(cal && params.cache)) {
	window.calendar = cal = new Calendar(params.firstDay,
	     null,
	     onJsCalendarDateUpdate,
	     function(cal) { cal.hide(); });
	cal.time24 = true;
	cal.weekNumbers = true;
	mustCreate = true;
    } else {
        cal.hide();
    }
    cal.showsOtherMonths = false;
    cal.yearStep = 2;
    cal.setRange(yearStart,yearEnd);
    cal.params = params;
    cal.setDateStatusHandler(null);
    cal.getDateText = null;
    cal.setDateFormat(format);
    if (mustCreate)
	cal.create();
    cal.refresh();
    if (!params.position)
        cal.showAtElement(input_id_anchor, null);
    else
        cal.showAt(params.position[0], params.position[1]);
    return false;
}


// This function updates a hidden date field with the current values of the widgets
function update_date_field(field, year, month, day, hour, minute, ampm)
{
    var field  = document.getElementById(field)
    var date   = document.getElementById(date)
    var year   = document.getElementById(year)
    var month  = document.getElementById(month)
    var day    = document.getElementById(day)
    var hour   = document.getElementById(hour)
    var minute = document.getElementById(minute)
    var ampm   = document.getElementById(ampm)

    if (0 < year.value)
    {
        // Return ISO date string
        // Note: This relies heavily on what date_components_support.py puts into the form.
        field.value = year.value + "-" + month.value + "-" + day.value + " " + hour.value + ":" + minute.value
        // Handle optional AM/PM
        if (ampm && ampm.value)
            field.value = field.value + " " + ampm.value
    } 
    else 
    {
        // Return empty string
        field.value = ''
        // Reset widgets
        month.options[0].selected = 1
        day.options[0].selected = 1
        hour.options[0].selected = 1
        minute.options[0].selected = 1
        if (ampm && ampm.options)
            ampm.options[0].selected = 1
    }
}




/* ----- calendarpopup.js ----- */

// The calendar popup show/hide:

    function showDay(date) {
        document.getElementById('day' + date).style.visibility = 'visible';
        return true;
    }    
    function hideDay(date) {
        document.getElementById('day' + date).style.visibility = 'hidden';
        return true;
    }


 




/* ----- ie5fixes.js ----- */
/* Mike Malloch's fixes for Internet Explorer 5 - 
 * We dont care too much about IE5,
 * But these stop if from spitting errormessages at the user 
 */
function hackPush(el){
    this[this.length] = el;
}

function hackPop(){
    var N = this.length - 1, el = this[N];
    this.length = N
    return el;
}

function hackShift(){
    var one = this[0], N = this.length;
    for (var i = 1; i < N; i++){
            this[i-1] = this[i];
    }
    this.length = N-1
    return one;
}

var testPushPop = new Array();
if (testPushPop.push){
}else{
    Array.prototype.push = hackPush
    Array.prototype.pop = hackPop
    Array.prototype.shift = hackShift;
}

/* ----- sarissa.js ----- */
/*****************************************************************************
 *
 * Sarissa XML library version 0.9.5
 * Copyright (c) 2003 Manos Batsis, mailto: mbatsis@netsmart.gr
 * This software is distributed under the Kupu License. See
 * LICENSE.txt for license text. See the Sarissa homepage at
 * http://sarissa.sourceforge.net for more information.
 *
 *****************************************************************************/

/**
 * <p>
 * Sarissa is a utility class. Provides factory methods for DOMDocument and XMLHTTP objects between other goodies.
 * </p>
 * 
 * @constructor
 */
function Sarissa(){};
/** @private */
Sarissa.PARSED_OK = "Document contains no parsing errors";
/**
 * Tells you whether transformNode and transformNodeToObject are available. This functionality
 * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations
 * use the XSLTProcessor
 * @deprecated
 * @type boolean
 */
Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
/**
 * tells you whether XMLHttpRequest (or equivalent) is available
 * @type boolean
 */
Sarissa.IS_ENABLED_XMLHTTP = false;
/**
 * <b>Deprecated, will be removed in 0.9.6</b>. Check for 
 * <code>window.XSLTProcessor</code> instead to see if 
 * XSLTProcessor is available.
 * @type boolean
 */
Sarissa.IS_ENABLED_XSLTPROC = false;
/**
 * tells you whether selectNodes/selectSingleNode is available
 * @type boolean
 */
Sarissa.IS_ENABLED_SELECT_NODES = false;
var _sarissa_iNsCounter = 0;
var _SARISSA_IEPREFIX4XSLPARAM = "";
var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
/** <b>Deprecated, will be removed in 0.9.6</b>. @deprecated */
var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
/** <b>Deprecated, will be removed in 0.9.6</b>. @deprecated */
var _SARISSA_IS_IE = document.all && window.ActiveXObject &&  (navigator.userAgent.toLowerCase().indexOf("msie") > -1);
//==========================================
// Implement Node constants if not available
//==========================================
if(!window.Node || !window.Node.ELEMENT_NODE){
    var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
};
// IE initialization
if(_SARISSA_IS_IE){
    // for XSLT parameter names, prefix needed by IE
    _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
    // used to store the most recent ProgID available out of the above
    var _SARISSA_DOM_PROGID = "";
    var _SARISSA_XMLHTTP_PROGID = "";
    /**
     * Called when the Sarissa_xx.js file is parsed, to pick most recent
     * ProgIDs for IE, then gets destroyed.
     * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
     * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
     */
    function pickRecentProgID(idList, enabledList){
        // found progID flag
        var bFound = false;
        for(var i=0; i < idList.length && !bFound; i++){
            try{
                var oDoc = new ActiveXObject(idList[i]);
                o2Store = idList[i];
                bFound = true;
                for(var j=0;j<enabledList.length;j++)
                    if(i <= enabledList[j][1])
                        Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;
            }catch (objException){
                // trap; try next progID
            };
        };
        if (!bFound)
            throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
        idList = null;
        return o2Store;
    };
    // pick best available MSXML progIDs
    _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
    _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);
    _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
    _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);
    // we dont need this anymore
    pickRecentProgID = null;
    //============================================
    // Factory methods (IE)
    //============================================
    // see non-IE version
    Sarissa.getDomDocument = function(sUri, sName){
        var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
        // if a root tag name was provided, we need to load it in the DOM
        // object
        if (sName){
            // if needed, create an artifical namespace prefix the way Moz
            // does
            if (sUri){
                oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");
                // don't use the same prefix again
                ++_sarissa_iNsCounter;
            }
            else
                oDoc.loadXML("<" + sName + "/>");
        };
        return oDoc;
    };
    if(!window.XMLHttpRequest){
        /**
         * Emulate XMLHttpRequest
         * @constructor
         */
        function XMLHttpRequest(){
            return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
        };
    };
    // see non-IE version   
    Sarissa.getParseErrorText = function (oDoc) {
        var parseErrorText = Sarissa.PARSED_OK;
        if(oDoc.parseError != 0){
            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 
                "\nLocation: " + oDoc.parseError.url + 
                "\nLine Number " + oDoc.parseError.line + ", Column " + 
                oDoc.parseError.linepos + 
                ":\n" + oDoc.parseError.srcText +
                "\n";
            for(var i = 0;  i < oDoc.parseError.linepos;i++){
                parseErrorText += "-";
            };
            parseErrorText +=  "^\n";
        };
        return parseErrorText;
    };
    // see non-IE version
    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
        oDoc.setProperty("SelectionLanguage", "XPath");
        oDoc.setProperty("SelectionNamespaces", sNsSet);
    };   
    /**
     * Basic implementation of Mozilla's XSLTProcessor for IE. 
     * Reuses the same XSLT stylesheet for multiple transforms
     * @constructor
     */
    function XSLTProcessor(){
        this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
        this.processor = null;
    };
    /**
     * Impoprts the given XSLT DOM and compiles it to a reusable transform
     * @argument xslDoc The XSLT DOMDocument to import
     */
    XSLTProcessor.prototype.importStylesheet = function(xslDoc){
        // convert stylesheet to free threaded
        var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); 
        converted.loadXML(xslDoc.xml);
        this.template.stylesheet = converted;
        this.processor = this.template.createProcessor();
        // (re)set default param values
        this.paramsSet = new Array();
    };
    /**
     * Transform the given XML DOM
     * @argument sourceDoc The XML DOMDocument to transform
     * @return The transformation result as a DOM Document
     */
    XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
        this.processor.input = sourceDoc;
        var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
        this.processor.output = outDoc; 
        this.processor.transform();
        return outDoc;
    };
    /**
     * Not sure if this works in IE. Maybe this will allow non-well-formed
     * transformation results (i.e. with no single root element)
     * @argument sourceDoc The XML DOMDocument to transform
     * @return The transformation result as a DOM Fragment
     */
    XSLTProcessor.prototype.transformToFragment = function(sourceDoc, ownerDocument){
        return this.transformToDocument(sourceDoc);
    };
    /**
     * Set global XSLT parameter of the imported stylesheet
     * @argument nsURI The parameter namespace URI
     * @argument name The parameter base name
     * @argument value The new parameter value
     */
    XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
        /* nsURI is optional but cannot be null */
        if(nsURI){
            this.processor.addParameter(name, value, nsURI);
        }else{
            this.processor.addParameter(name, value);
        };
        /* update updated params for getParameter */
        if(!this.paramsSet[""+nsURI]){
            this.paramsSet[""+nsURI] = new Array();
        };
        this.paramsSet[""+nsURI][name] = value;
    };
    /**
     * Gets a parameter if previously set by setParameter. Returns null
     * otherwise
     * @argument name The parameter base name
     * @argument value The new parameter value
     * @return The parameter value if reviously set by setParameter, null otherwise
     */
    XSLTProcessor.prototype.getParameter = function(nsURI, name){
        if(this.paramsSet[""+nsURI] && this.paramsSet[""+nsURI][name])
            return this.paramsSet[""+nsURI][name];
        else
            return null;
    };
}
else{ /* end IE initialization, try to deal with real browsers now ;-) */
   if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
        if(window.XMLDocument){
            /**
            * <p>Emulate IE's onreadystatechange attribute</p>
            */
            XMLDocument.prototype.onreadystatechange = null;
            /**
            * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
            * <ul><li>1 == LOADING,</li>
            * <li>2 == LOADED,</li>
            * <li>3 == INTERACTIVE,</li>
            * <li>4 == COMPLETED</li></ul>
            */
            XMLDocument.prototype.readyState = 0;
            /**
            * <p>Emulate IE's parseError attribute</p>
            */
            XMLDocument.prototype.parseError = 0;

            // NOTE: setting async to false will only work with documents
            // called over HTTP (meaning a server), not the local file system,
            // unless you are using Moz 1.4+.
            // BTW the try>catch block is for 1.4; I haven't found a way to check if
            // the property is implemented without
            // causing an error and I dont want to use user agent stuff for that...
            var _SARISSA_SYNC_NON_IMPLEMENTED = false;
            try{
                /**
                * <p>Emulates IE's async property for Moz versions prior to 1.4.
                * It controls whether loading of remote XML files works
                * synchronously or asynchronously.</p>
                */
                XMLDocument.prototype.async = true;
                _SARISSA_SYNC_NON_IMPLEMENTED = true;
            }catch(e){/* trap */};
            /**
            * <p>Keeps a handle to the original load() method. Internal use and only
            * if Mozilla version is lower than 1.4</p>
            * @private
            */
            XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;

            /**
            * <p>Overrides the original load method to provide synchronous loading for
            * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
            * async is set to false)</p>
            * @returns the DOM Object as it was before the load() call (may be  empty)
            */
            XMLDocument.prototype.load = function(sURI) {
                var oDoc = document.implementation.createDocument("", "", null);
                Sarissa.copyChildNodes(this, oDoc);
                this.parseError = 0;
                Sarissa.__setReadyState__(this, 1);
                try {
                    if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
                        var tmp = new XMLHttpRequest();
                        tmp.open("GET", sURI, false);
                        tmp.send(null);
                        Sarissa.__setReadyState__(this, 2);
                        Sarissa.copyChildNodes(tmp.responseXML, this);
                        Sarissa.__setReadyState__(this, 3);
                    }
                    else {
                        this._sarissa_load(sURI);
                    };
                }
                catch (objException) {
                    this.parseError = -1;
                }
                finally {
                    if(this.async == false){
                        Sarissa.__handleLoad__(this);
                    };
                };
                return oDoc;
            };

            if(window.DOMParser && !XMLDocument.loadXML){
                /**
                * <p>Parses the String given as parameter to build the document content
                * for the object, exactly like IE's loadXML()</p>
                * @argument strXML The XML String to load as the Document's childNodes
                * @returns the old Document structure serialized as an XML String
                */
                XMLDocument.prototype.loadXML = function(strXML){
                    Sarissa.__setReadyState__(this, 1);
                    var sOldXML = this.xml;
                    var oDoc = (new DOMParser()).parseFromString(strXML, "text/xml");
                    Sarissa.__setReadyState__(this, 2);
                    Sarissa.copyChildNodes(oDoc, this);
                    Sarissa.__setReadyState__(this, 3);
                    Sarissa.__handleLoad__(this);
                    return sOldXML;
                };
            };//if(window.DOMParser && !XMLDocument.loadXML)
        };//if(window.XMLDocument)

        /**
         * <p>Ensures the document was loaded correctly, otherwise sets the
         * parseError to -1 to indicate something went wrong. Internal use</p>
         * @private
         */
        Sarissa.__handleLoad__ = function(oDoc){
            if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")
                oDoc.parseError = -1;
            Sarissa.__setReadyState__(oDoc, 4);
        };
        /**
        * <p>Attached by an event handler to the load event. Internal use.</p>
        * @private
        */
        function _sarissa_XMLDocument_onload()        {
            Sarissa.__handleLoad__(this);
        };
        /**
         * <p>Sets the readyState property of the given DOM Document object.
         * Internal use.</p>
         * @private
         * @argument oDoc the DOM Document object to fire the
         *          readystatechange event
         * @argument iReadyState the number to change the readystate property to
         */
        Sarissa.__setReadyState__ = function(oDoc, iReadyState){
            oDoc.readyState = iReadyState;
            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
                oDoc.onreadystatechange();
        };
        /**
        * <p>Factory method to obtain a new DOM Document object</p>
        * @argument sUri the namespace of the root node (if any)
        * @argument sUri the local name of the root node (if any)
        * @returns a new DOM Document
        */
        Sarissa.getDomDocument = function(sUri, sName){
            var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
            return oDoc;
        };        
    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
};
//==========================================
// Common stuff
//==========================================
if(window.XMLHttpRequest){
    /**
    * <p><b>Deprecated, will be removed in 0.9.6</b>. Factory method to obtain a new XMLHTTP Request object</p>
    * @returns a new XMLHTTP Request object
    * @deprecated
    */
    Sarissa.getXmlHttpRequest = function()  {
        return new XMLHttpRequest();
    };
    Sarissa.IS_ENABLED_XMLHTTP = true;
};
if(!window.document.importNode){
    /**
     * Implements importNode for the current window document in IE using innerHTML.
     * Testing showed that DOM was multiple times slower than innerHTML for this,
     * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)
     * please gimme a call.
     * @param oNode the Node to import
     * @param bChildren whether to include the children of oNode
     * @returns the imported node for further use
     */
    window.document.importNode = function(oNode, bChildren){
        var importNode = document.createElement("div");
        if(bChildren)
            importNode.innerHTML = Sarissa.serialize(oNode);
        else
            importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));
        return importNode.firstChild;
    };
};
if(!Sarissa.getParseErrorText){
    /**
     * <p>Returns a human readable description of the parsing error. Usefull
     * for debugging. Tip: append the returned error string in a &lt;pre&gt;
     * element if you want to render it.</p>
     * <p>Many thanks to Christian Stocker for the initial patch.</p>
     * @argument oDoc The target DOM document
     * @returns The parsing error description of the target Document in
     *          human readable form (preformated text)
     */
    Sarissa.getParseErrorText = function (oDoc){
        var parseErrorText = Sarissa.PARSED_OK;
        if(oDoc.parseError != 0){
            /*moz*/
            if(oDoc.documentElement.tagName == "parsererror"){
                parseErrorText = oDoc.documentElement.firstChild.data;
                parseErrorText += "\n" +  oDoc.documentElement.firstChild.nextSibling.firstChild.data;
            }/*konq*/
            else if(oDoc.documentElement.tagName == "html"){
                parseErrorText = Sarissa.getText(oDoc.documentElement.getElementsByTagName("h1")[0], false) + "\n";
                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";
                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);
            };
        };
        return parseErrorText;
    };
};
Sarissa.getText = function(oNode, deep){
    var s = "";
    var nodes = oNode.childNodes;
    for(var i=0; i < nodes.length; i++){
        var node = nodes[i];
        if(node.nodeType == Node.TEXT_NODE){
            s += node.data;
        }else if(deep == true
                    && (node.nodeType == Node.ELEMENT_NODE
                        || node.nodeType == Node.DOCUMENT_NODE
                        || node.nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
        
            s += Sarissa.getText(node, true);
        };
    };
    return s;
};
if(window.XMLSerializer){
    /**
     * <p>Factory method to obtain the serialization of a DOM Node</p>
     * @returns the serialized Node as an XML string
     */
    Sarissa.serialize = function(oDoc){
        return (new XMLSerializer()).serializeToString(oDoc);
    };
}else{
    if((Sarissa.getDomDocument("","foo", null)).xml){
        // see non-IE version
        Sarissa.serialize = function(oDoc) {
            // TODO: check for HTML document and return innerHTML instead
            return oDoc.xml;
        };
        /**
         * Utility class to serialize DOM Node objects to XML strings
         * @constructor
         */
        XMLSerializer = function(){};
        /**
         * Serialize the given DOM Node to an XML string
         * @param oNode the DOM Node to serialize
         */
        XMLSerializer.prototype.serializeToString = function(oNode) {
            return oNode.xml;
        };
    };
};
if(window.XSLTProcessor){
    Sarissa.IS_ENABLED_XSLTPROC = true;
};
/**
 * strips tags from a markup string
 */
Sarissa.stripTags = function (s) {
    return s.replace(/<[^>]+>/g,"");
};
/**
 * <p>Deletes all child nodes of the given node</p>
 * @argument oNode the Node to empty
 */
Sarissa.clearChildNodes = function(oNode) {
    while(oNode.hasChildNodes()){
        oNode.removeChild(oNode.firstChild);
    };
};
/**
 * <p> Replaces the childNodes of the toDoc object with the childNodes of
 * the fromDoc object</p>
 * <p> <b>Note:</b> The second object's original content is deleted before the copy operation</p>
 * @argument nodeFrom the Node to copy the childNodes from
 * @argument nodeTo the Node to copy the childNodes to
 */
Sarissa.copyChildNodes = function(nodeFrom, nodeTo) {
    Sarissa.clearChildNodes(nodeTo);
    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
    var nodes = nodeFrom.childNodes;
    if(typeof(ownerDoc.importNode) == "function"){
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
        };
    }
    else{
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(nodes[i].cloneNode(true));
        };
    };
};

/** 
 * <p>Serialize any object to an XML string. All properties are serialized using the property name
 * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 
 * using their index/key as the value of the <code>key</code> attribute.</p>
 * @argument anyObject the object to serialize
 * @argument objectName a name for that object
 * @return the XML serializationj of the given object as a string
 */
Sarissa.xmlize = function(anyObject, objectName, indentSpace){
    indentSpace = indentSpace?indentSpace:'';
    var s = indentSpace  + '<' + objectName + '>';
    var isLeaf = false;
    if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 
        || anyObject instanceof Boolean || anyObject instanceof Date){
        s += Sarissa.escape(""+anyObject);
        isLeaf = true;
    }else{
        s += "\n";
        var itemKey = '';
        var isArrayItem = anyObject instanceof Array;
        for(var name in anyObject){
            s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");
        };
        s += indentSpace;
    };
    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
};

/** 
 * Escape the given string chacters that correspond to the five predefined XML entities
 * @param sXml the string to escape
 */
Sarissa.escape = function(sXml){
    return sXml.replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&apos;");
};

/** 
 * Unescape the given string. This turns the occurences of the predefined XML 
 * entities to become the characters they represent correspond to the five predefined XML entities
 * @param sXml the string to unescape
 */
Sarissa.unescape = function(sXml){
    return sXml.replace(/&apos;/g,"'")
        .replace(/&quot;/g,"\"")
        .replace(/&gt;/g,">")
        .replace(/&lt;/g,"<")
        .replace(/&amp;/g,"&");
};
//   EOF

