[Zope-CVS] CVS: Products/Zelenium/selenium - domviewer.html:1.1 selenium-domviewer.js:1.1 selenium-executioncontext.js:1.1 selenium-logging.js:1.1 selenium-tableparser.js:1.1 xmlextras.js:1.1 htmlutils.js:1.2 selenium-api.js:1.2 selenium-browserbot.js:1.2 selenium-commandhandlers.js:1.2 selenium-executionloop.js:1.2 selenium-fitrunner.js:1.2 selenium.css:1.2

Tres Seaver tseaver at zope.com
Mon May 2 23:48:47 EDT 2005


Update of /cvs-repository/Products/Zelenium/selenium
In directory cvs.zope.org:/tmp/cvs-serv12572/selenium

Modified Files:
	htmlutils.js selenium-api.js selenium-browserbot.js 
	selenium-commandhandlers.js selenium-executionloop.js 
	selenium-fitrunner.js selenium.css 
Added Files:
	domviewer.html selenium-domviewer.js 
	selenium-executioncontext.js selenium-logging.js 
	selenium-tableparser.js xmlextras.js 
Log Message:
 - Pick up support files from Selenium 0.3.


=== Added File Products/Zelenium/selenium/domviewer.html ===
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
        <title>DOM Viewer</title>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
        <link href="/styles/default.css" rel="dom-styles/stylesheet" 
            type="text/css" />
        <script type="text/javascript" src="selenium-domviewer.js" />
    </head>
	<body onload="loadDomViewer();">
		<h3>DOM Viewer</h3>
		<p> This page is generated using JavaScript. If you see this text, your 
			browser doesn't support JavaScript.</p>
	</body>
	
</html>


=== Added File Products/Zelenium/selenium/selenium-domviewer.js ===
var HIDDEN="hidden";
var LEVEL = "level";
var PLUS_SRC="dom-images/butplus.gif"
var MIN_SRC="dom-images/butmin.gif"
var newRoot;
var maxColumns=1;

function loadDomViewer(){
	if(window.opener != null){
		//Open in a new window. 
		// Start with specified root object.
		// It should be defined as a "newRoot" variable 
		// in the tested page. Could be any element in 
		// the DOM structure of the page that opened it.
		// Default to document if no object is specified.
		newRoot  = window.opener.newRoot;
	
		if (newRoot==null)
			newRoot = window.opener.document;
	
		document.writeln(displayDOM(newRoot));
		document.close();
	}else{
		newRoot = parent.document.all['myiframe'].contentWindow.document;
		newRoot.writeln(displayDOM(newRoot));
		newRoot.close();
	}
}


function displayDOM(root){
	var str = "<html><head><title>DOM Viewerr</title><script type='text/javascript' src='domviewer.js'><!-- comments --> </script><link href='dom-styles/default.css' rel='stylesheet' type='text/css' /></head><body>";
	str+="<table>";
	str += treeTraversal(root,0);
	// to make table columns work well.
	str += "<tr>";
	for (var i=0; i < maxColumns; i++) {
	    str+= "<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>";
	}
	str += "</tr>";
	str += "</table></body></html>";
	return str;
}

function checkForChildren(element){
	if(!element.hasChildNodes())
		return false;
	
	var nodes = element.childNodes;
	var size = nodes.length;
	var count=0;
	
	for(var i=0; i< size; i++){
		var node = nodes.item(i);
		//if(node.toString()=="[object Text]"){
		//this is equalent to the above
		//but will work with more browsers
		if(node.nodeType!=1){
			count++;
		}
	}
	
	if(count == size)
		return false;
	else
		return true;
}

function treeTraversal(root, level){
	var str = "";
	var nodes= null;
	var size = null;
	//it is supposed to show the last node, 
	//but the last node is always nodeText type
	//and we don't show it
	if(!root.hasChildNodes())
		return "";//displayNode(root,level,false);

	nodes = root.childNodes;
	size = nodes.length;

	for(var i=0; i< size; i++){
		var element = nodes.item(i);
		//if the node is textNode, don't display
		if(element.nodeType==1){
			str+= displayNode(element,level,checkForChildren(element));
			str+=treeTraversal(element, level+1);	
		}
	}
	return str;
}


function displayNode(element, level, isLink){
        nodeContent = getNodeContent(element);
        columns = Math.round((nodeContent.length / 12) + 0.5);
        if (columns + level > maxColumns) {
            maxColumns = columns + level;
        }
		var str ="<tr class='"+LEVEL+level+"'>";
		for (var i=0; i < level; i++)
			str+= "<td> </td>";
		str+="<td colspan='"+ columns +"' class='box"+" boxlevel"+level+"' >";
		if(isLink){
			str+='<a onclick="hide(this);" href="javascript:void(this);">';
			str+='<img src="'+MIN_SRC+'" />';
		}
        str += nodeContent;
		if(isLink)
			str+="</a></td></tr>";
		return str;
}

function getNodeContent(element) {
        str = "";
		id ="";
		if (element.id != null && element.id != "") {
		    id = " ID(" + element.id +")";
		}
		name ="";
		if (element.name != null && element.name != "") {
		    name = " NAME(" + element.name + ")";
		}
		value ="";
		if (element.value != null && element.value != "") {
		    value = " VALUE(" + element.value + ")";
		}
		href ="";
		if (element.href != null && element.href != "") {
		    href = " HREF(" + element.href + ")";
		}
		text ="";
		if (element.text != null && element.text != "" && element.text != "undefined") {
		    text = " #TEXT(" + trim(element.text) +")";
		}
		str+=" <b>"+ element.nodeName + id + name + value + href + text + "</b>";	
		return str;

}

function trim(val) {
        val2 = val.substring(0,20) + "                   ";
        var spaceChr = String.fromCharCode(32);
        var length = val2.length;
        var retVal = "";
        var ix = length -1;

        while(ix > -1){
            if(val2.charAt(ix) == spaceChr) {
            } else {
                retVal = val2.substring(0, ix +1);
                break;
            }
            ix = ix-1;
        }
        if (val.length > 20) {
            retVal += "...";
        }
        return retVal;
}

function hide(hlink){
	var isHidden = false;
	var image = hlink.firstChild;
	if(image.src.toString().indexOf(MIN_SRC)!=-1){
		image.src=PLUS_SRC;
		isHidden=true;
	}else{
		image.src=MIN_SRC;
	}
	var rowObj= hlink.parentNode.parentNode;
	var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));
	
	var sibling = rowObj.nextSibling;
	var siblingLevel = sibling.className.substring(LEVEL.length);
	if(siblingLevel.indexOf(HIDDEN)!=-1){
		siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
	}
	siblingLevel=parseInt(siblingLevel);
	while(sibling!=null && rowLevel<siblingLevel){
		if(isHidden){
			sibling.className += " "+ HIDDEN;
		}else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
			var str = sibling.className;
			sibling.className=str.substring(0, str.length - HIDDEN.length-1);
		}
		sibling = sibling.nextSibling;
		siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
	}
}





=== Added File Products/Zelenium/selenium/selenium-executioncontext.js ===
/*
 * Copyright 2004 ThoughtWorks, Inc
 *
 *  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.
 *
 */

function IFrameExecutionContext() {

    this.loadFrame = function() {
        return document.getElementById('myiframe');
    };

    this.open = function(target,frame) {
        frame.src = target;
    };

    this.getContentWindow = function(frame) {
        return frame.contentWindow;
    };

    this.waitForPageLoad = function(testloop,selenium) {
        // Since we're waiting for page to reload, we can't continue command execution
        // directly, we need use a page load listener.

        // TODO there is a potential race condition by attaching a load listener after
        // the command has completed execution.
        selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay()");});
    };
}

function KonquerorIFrameExecutionContext() {

    this.loadFrame = function() {
        return document.getElementById('myiframe');
    };

    this.open = function(target, frame) {
        // Window doesn't fire onload event when setting src to the current value,
        // so we set it to blank first.
        frame.src = "about:blank";
        frame.src = target;
    };

    this.getContentWindow = function(frame) {
        return frames['myiframe'];
    };

    this.waitForPageLoad = function(testloop,selenium) {
        // Since we're waiting for page to reload, we can't continue command execution
        // directly, we need use a page load listener.

        // TODO there is a potential race condition by attaching a load listener after
        // the command has completed execution.
        selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay()");});
    };
}

var windowExecutionContext;

function getWindowExecutionContext() {
    if (windowExecutionContext == null) {
        windowExecutionContext = new WindowExecutionContext();
    }
    return windowExecutionContext;
}

function WindowExecutionContext() {
    this.externalWindow = null;

    this.loadFrame = function() {
        var newWindow = window.open("about:blank", "_blank", "toolbar=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=1024,height=740,left=250,top=250");
        newWindow.opener = window.frame;
        this.externalWindow = newWindow;
        return this.externalWindow;
    };

    this.open = function(target,frame) {
        frame.location = target;
    };

    this.getContentWindow = function(frame) {
        return frame;
    };

    this.waitForPageLoad = function(testloop,selenium) {
        if(window.addEventListener) {
            selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay();");});
        } else {
            if(this.externalWindow != null) {
                if(this.getValueWhenReady() != "complete" ) {
                    var localContext = this;
                    var localLoop = testloop;
                    var localSelenium = selenium;
                    window.setTimeout(function() {localContext.waitForPageLoad(localLoop, localSelenium); }, 100 );
                } else {
                    testloop.continueCommandExecutionWithDelay();
                }
            }
        }
    };

    // this function became necessary for IE in a NEW WINDOW. the document.readyState was not ready to be accessed.
    this.getValueWhenReady = function() {
        while (true) {
            try {
                return this.externalWindow.document.readyState;
            } catch (x) {
            }
        }
    };
}

=== Added File Products/Zelenium/selenium/selenium-logging.js ===
/*
* Copyright 2004 ThoughtWorks, Inc
*
*  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.
*/

var LEVEL_DEBUG = 0;
var LEVEL_INFO = 1;
var LEVEL_WARN = 2;
var LEVEL_ERROR = 3;

function Logger(logLevel) {
    this.level = logLevel;
    this.logConsole = document.getElementById('logging-console');
    this.logList = document.getElementById('log-list');
    this.hide();
}

Logger.prototype.show = function() {
   this.logConsole.style.display = "";
};

Logger.prototype.hide = function() {
   this.logConsole.style.display = "none";
};

Logger.prototype.clear = function() {
    while (this.logList.hasChildNodes()) {
        this.logList.removeChild(this.logList.firstChild);
    }
};

Logger.prototype.debug = function(message) {
    if (this.level <= LEVEL_DEBUG) {
        this.log(message, "debug");
    }
};

Logger.prototype.info = function(message) {
    if (this.level <= LEVEL_INFO) {
        this.log(message, "info");
    }
};

Logger.prototype.warn = function(message) {
    if (this.level <= LEVEL_WARN) {
        this.log(message, "warn");
    }
};

Logger.prototype.error = function(message) {
    if (this.level <= LEVEL_ERROR) {
        this.log(message, "error");
    }
};

Logger.prototype.log = function(message, className) {
    var loggingNode = document.createElement('li');
    loggingNode.className = className;
    loggingNode.appendChild(document.createTextNode(message));

    this.logList.appendChild(loggingNode);
    this.show();
};

=== Added File Products/Zelenium/selenium/selenium-tableparser.js ===
/*
 * Copyright 2004 ThoughtWorks, Inc
 *
 *  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.
 *
 */
 
TableParser = function(wikiTableRows) {
    this.wikiTableRows = wikiTableRows;
};

// Parses a Wiki table row into a SeleniumB Javascript expression
TableParser.prototype.createCommandFromWikiRow = function(wikiRow) {
    var tokens;
    if(tokens = wikiRow.trim().match(/^\|([^\|]*)\|([^\|]*)\|([^\|]*)\|$/m)) {
        var functionName = tokens[1].trim();
        var arg1 = tokens[2].trim();
        var arg2 = tokens[3].trim();
        return new SeleniumCommand(functionName, arg1, arg2);
    } else {
       throw new Error("Bad wiki row format:" + wikiRow);
    }
};

// Parses a HTML table row into a SeleniumB Javascript expression
TableParser.prototype.createCommandFromHtmlRow = function(row) {
    if(row.cells.length != 3) {
       throw new Error("Bad HTML row format. Rows must have 3 coumns, but had " + row.cells.length);
    }
    var functionName = getText(row.cells[0]);
    var arg1 = getText(row.cells[1]);
    var arg2 = getText(row.cells[2]);
    return new SeleniumCommand(functionName, arg1, arg2);
};

TableParser.prototype.loop = function() {
    row = this.wikiTableRows.getRow();
    if (row == null) return null;
    return this.createCommandForRow(row);
};

=== Added File Products/Zelenium/selenium/xmlextras.js ===
// This is a third party JavaScript library from
// http://webfx.eae.net/dhtml/xmlextras/xmlextras.html
// i.e. This has not been written by ThoughtWorks.

//<script>
//////////////////
// Helper Stuff //
//////////////////

// used to find the Automation server name
function getDomDocumentPrefix() {
	if (getDomDocumentPrefix.prefix)
		return getDomDocumentPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".DomDocument");
			return getDomDocumentPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XML parser");
}

function getXmlHttpPrefix() {
	if (getXmlHttpPrefix.prefix)
		return getXmlHttpPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".XmlHttp");
			return getXmlHttpPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XML parser");
}

//////////////////////////
// Start the Real stuff //
//////////////////////////


// XmlHttp factory
function XmlHttp() {}

XmlHttp.create = function () {
	try {
		if (window.XMLHttpRequest) {
			var req = new XMLHttpRequest();
			
			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (req.readyState == null) {
				req.readyState = 1;
				req.addEventListener("load", function () {
					req.readyState = 4;
					if (typeof req.onreadystatechange == "function")
						req.onreadystatechange();
				}, false);
			}
			
			return req;
		}
		if (window.ActiveXObject) {
			return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
		}
	}
	catch (ex) {}
	// fell through
	throw new Error("Your browser does not support XmlHttp objects");
};

// XmlDocument factory
function XmlDocument() {}

XmlDocument.create = function () {
	try {
		// DOM2
		if (document.implementation && document.implementation.createDocument) {
			var doc = document.implementation.createDocument("", "", null);
			
			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (doc.readyState == null) {
				doc.readyState = 1;
				doc.addEventListener("load", function () {
					doc.readyState = 4;
					if (typeof doc.onreadystatechange == "function")
						doc.onreadystatechange();
				}, false);
			}
			
			return doc;
		}
		if (window.ActiveXObject)
			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
	}
	catch (ex) {}
	throw new Error("Your browser does not support XmlDocument objects");
};

// Create the loadXML method and xml getter for Mozilla
if (window.DOMParser &&
	window.XMLSerializer &&
	window.Node && Node.prototype && Node.prototype.__defineGetter__) {

	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	//XMLDocument.prototype.loadXML = 
	Document.prototype.loadXML = function (s) {
		
		// parse the string to a new doc	
		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
		
		// remove all initial children
		while (this.hasChildNodes())
			this.removeChild(this.lastChild);
			
		// insert and import nodes
		for (var i = 0; i < doc2.childNodes.length; i++) {
			this.appendChild(this.importNode(doc2.childNodes[i], true));
		}
	};
	
	
	/*
	 * xml getter
	 *
	 * This serializes the DOM tree to an XML String
	 *
	 * Usage: var sXml = oNode.xml
	 *
	 */
	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	/*
	XMLDocument.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	*/
	Document.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
}

=== Products/Zelenium/selenium/htmlutils.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/htmlutils.js:1.1.1.1	Fri Apr 15 14:48:44 2005
+++ Products/Zelenium/selenium/htmlutils.js	Mon May  2 23:48:16 2005
@@ -1,122 +1,127 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- *
- */
- 
-// This script contains some HTML utility functions that
-// make it possible to handle elements in a way that is 
-// compatible with both IE-like and Mozilla-like browsers
-
-function trim() {
-  var result = this.replace( /^\s+/g, "" );// strip leading
-  return result.replace( /\s+$/g, "" );// strip trailing
-}
-String.prototype.trim = trim;
-
-function toCamelCase() {
-   return this.charAt(0).toLowerCase() + this.substr(1);
-}
-String.prototype.toCamelCase = toCamelCase;
-
-// Returns the text in this element
-function getText(element) {
-    text = "";
-
-    if(element.textContent) {
-        text = element.textContent;
-    } else if(element.innerText) {
-        text = element.innerText;
-    }
-    return text.trim();
-}
-
-// Sets the text in this element
-function setText(element, text) {
-    if(element.textContent) {
-        element.textContent = text;
-    } else if(element.innerText) {
-        element.innerText = text;
-    }
-}
-
-// Get the value of an <input> element
-function getInputValue(inputElement) {
-    if (inputElement.type.toUpperCase() == 'CHECKBOX' || 
-        inputElement.type.toUpperCase() == 'RADIO') 
-    {
-        return (inputElement.checked ? 'on' : 'off');
-    }
-    return inputElement.value;
-}
-
-/* Fire an event in a browser-compatible manner */
-function triggerEvent(element, eventType, canBubble) {
-    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
-    if (element.fireEvent) {
-        element.fireEvent('on' + eventType);
-    }
-    else {
-        var evt = document.createEvent('HTMLEvents');
-        evt.initEvent(eventType, canBubble, true);
-        element.dispatchEvent(evt);
-    }
-}
-
-/* Fire a mouse event in a browser-compatible manner */
-function triggerMouseEvent(element, eventType, canBubble) {
-    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
-    if (element.fireEvent) {
-        element.fireEvent('on' + eventType);
-    }
-    else {
-        var evt = document.createEvent('MouseEvents');
-        evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-        element.dispatchEvent(evt);
-    }
-}
-
-function removeLoadListener(element, command) {
-    if (window.removeEventListener)
-        element.removeEventListener("load", command, true);
-    else if (window.detachEvent)
-        element.detachEvent("onload", command);
-}
-
-function addLoadListener(element, command) {
-    if (window.addEventListener)
-        element.addEventListener("load",command, true);
-    else if (window.attachEvent)
-        element.attachEvent("onload",command);
-}
-
-/**
- * Override the broken getFunctionName() method from JsUnit
- * This file must be loaded _after_ the jsunitCore.js
- */
-function getFunctionName(aFunction) {
-  var regexpResult = aFunction.toString().match(/function (\w*)/);
-  if (regexpResult && regexpResult[1]) {
-      return regexpResult[1];
-  }
-  return 'anonymous';
-}
-
-function describe(object) {
-    var props = new Array();
-    for (var prop in object) {
-        props.push(prop);
-    }
-    return props.join('\n');
-}
+/*
+ * Copyright 2004 ThoughtWorks, Inc
+ *
+ *  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.
+ *
+ */
+ 
+// This script contains some HTML utility functions that
+// make it possible to handle elements in a way that is 
+// compatible with both IE-like and Mozilla-like browsers
+
+function trim() {
+  var result = this.replace( /^\s+/g, "" );// strip leading
+  return result.replace( /\s+$/g, "" );// strip trailing
+}
+String.prototype.trim = trim;
+
+function toCamelCase() {
+   return this.charAt(0).toLowerCase() + this.substr(1);
+}
+String.prototype.toCamelCase = toCamelCase;
+
+function startsWith(str) {
+    return this.indexOf(str) == 0;
+}
+String.prototype.startsWith = startsWith;
+
+// Returns the text in this element
+function getText(element) {
+    text = "";
+
+    if(element.textContent) {
+        text = element.textContent;
+    } else if(element.innerText) {
+        text = element.innerText;
+    }
+    return text.trim();
+}
+
+// Sets the text in this element
+function setText(element, text) {
+    if(element.textContent) {
+        element.textContent = text;
+    } else if(element.innerText) {
+        element.innerText = text;
+    }
+}
+
+// Get the value of an <input> element
+function getInputValue(inputElement) {
+    if (inputElement.type.toUpperCase() == 'CHECKBOX' || 
+        inputElement.type.toUpperCase() == 'RADIO') 
+    {
+        return (inputElement.checked ? 'on' : 'off');
+    }
+    return inputElement.value;
+}
+
+/* Fire an event in a browser-compatible manner */
+function triggerEvent(element, eventType, canBubble) {
+    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+    if (element.fireEvent) {
+        element.fireEvent('on' + eventType);
+    }
+    else {
+        var evt = document.createEvent('HTMLEvents');
+        evt.initEvent(eventType, canBubble, true);
+        element.dispatchEvent(evt);
+    }
+}
+
+/* Fire a mouse event in a browser-compatible manner */
+function triggerMouseEvent(element, eventType, canBubble) {
+    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+    if (element.fireEvent) {
+        element.fireEvent('on' + eventType);
+    }
+    else {
+        var evt = document.createEvent('MouseEvents');
+        evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+        element.dispatchEvent(evt);
+    }
+}
+
+function removeLoadListener(element, command) {
+    if (window.removeEventListener)
+        element.removeEventListener("load", command, true);
+    else if (window.detachEvent)
+        element.detachEvent("onload", command);
+}
+
+function addLoadListener(element, command) {
+    if (window.addEventListener)
+        element.addEventListener("load",command, true);
+    else if (window.attachEvent)
+        element.attachEvent("onload",command);
+}
+
+/**
+ * Override the broken getFunctionName() method from JsUnit
+ * This file must be loaded _after_ the jsunitCore.js
+ */
+function getFunctionName(aFunction) {
+  var regexpResult = aFunction.toString().match(/function (\w*)/);
+  if (regexpResult && regexpResult[1]) {
+      return regexpResult[1];
+  }
+  return 'anonymous';
+}
+
+function describe(object) {
+    var props = new Array();
+    for (var prop in object) {
+        props.push(prop + " -> " + object[prop]);
+    }
+    return props.join('\n');
+}


=== Products/Zelenium/selenium/selenium-api.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-api.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-api.js	Mon May  2 23:48:16 2005
@@ -1,265 +1,501 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- *
- */
-
-function Selenium(browserbot) {
-    this.browserbot = browserbot;
-    this.page = function() {return browserbot.getCurrentPage()};
-
-    var self = this;
-    this.callOnNextPageLoad = function(callback) {
-        if (callback) {
-            self.browserbot.callOnNextPageLoad(callback);
-        }
-    }
-}
-
-/*
- * Click on the located element, and attach a callback to notify
- * when the page is reloaded.
- */
-Selenium.prototype.doClick = function(locator) {
-    var element = this.page().findElement(locator);
-    this.page().clickElement(element);
-}
-
-/**
- * Overwrite the text in the located text element.
- * TODO fail if it can't be typed into.
- */
-Selenium.prototype.doType = function(locator, newText) {
-    var element = this.page().findElement(locator);
-    this.page().replaceText(element, newText);
-}
-
-/**
- * Select the option by label from the located select element.
- * TODO fail if it's not a select.
- */
-Selenium.prototype.doSelect = function(locator, optionText) {
-    var element = this.page().findElement(locator);
-    this.page().selectOptionWithLabel(element, optionText);
-}
-
-/*
- * Open the browser to a new location.
- */
-Selenium.prototype.doOpen = function(newLocation) {
-    this.browserbot.openLocation(newLocation);
-    return SELENIUM_PROCESS_WAIT;
-}
-
-/*
- * Select the named window to be the active window.
- */
-Selenium.prototype.doSelectWindow = function(windowName) {
-    this.browserbot.selectWindow(windowName);
-}
-
-/*
- * Instruct Selenium to click Cancel on the next confirm dialog it encounters
- */
-Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
-    this.browserbot.cancelNextConfirmation();
-}
-
-/*
- *  Asserts that the supplied message was received as an alert
- */
- Selenium.prototype.assertAlert = function(expectedAlert) {
-    if ( this.browserbot.hasAlerts()) {
-        
-        receivedAlert = this.browserbot.getNextAlert();
-        if ( receivedAlert != expectedAlert ) {
-           fail("The alert was [" + receivedAlert + "]");   
-        }
-                          
-    } else {
-        fail("There were no alerts"); 
-    }
- } 
-
-  /*
-  *  Asserts that the supplied message was received as a confirmation
-  */
-  Selenium.prototype.assertConfirmation = function(expectedConfirmation) {
-     if ( this.browserbot.hasConfirmations()) {
-         
-         receivedConfirmation = this.browserbot.getNextConfirmation();
-         if ( receivedConfirmation != expectedConfirmation ) {
-            fail("The confirmation message was [" + receivedConfirmation + "]");   
-         }
-                           
-     } else {
-         fail("There were no confirmations"); 
-     }
-  } 
- 
-/*
- * Verify the location of the current page.
- */
-Selenium.prototype.assertLocation = function(expectedLocation) {
-    assertEquals(expectedLocation, this.page().location);
-}
-
-/*
- * Verify the title of the current page.
- */
-Selenium.prototype.assertTitle = function(expectedTitle) {
-    assertEquals(expectedTitle, this.page().title());
-}
-
-/*
- * Verify the value of a form element.
- */
-Selenium.prototype.assertValue = function(locator, expectedValue) {
-    var element = this.page().findElement(locator);
-    var actualValue = getInputValue(element);
-    assertEquals(expectedValue, actualValue.trim());
-}
-
-/*
- * Verifies that the entire text of the page matches the expected content.
- */
-Selenium.prototype.assertText = function(locator, expectedContent) {
-    var element = this.page().findElement(locator);
-    var actualText = getText(element);
-    assertEquals(expectedContent, actualText.trim());
-}
-
-/*
- * Asserts that the text for a single cell within and HTML table matches the expected content.
- * The table locator syntax is table.row.column.
- */
-Selenium.prototype.assertTable = function(tableLocator, expectedContent) {
-    // This regular expression matches "tableName.row.column"
-    // For example, "mytable.3.4"
-    pattern = /(.*)\.(\d)+\.(\d+)/
-
-    if(!pattern.test(tableLocator)) {
-        error("Invalid target format. Correct format is tableName.rowNum.columnNum");
-    }
-
-    pieces = tableLocator.match(pattern);
-
-    tableName = pieces[1];
-    row = pieces[2];
-    col = pieces[3];
-
-    var table = this.page().findElement(tableName);
-    if (row > table.rows.length || col > table.rows[row].cells.length)
-        fail("No such row or column in table");
-    else {
-        actualContent = getText(table.rows[row].cells[col]);
-        assertEquals(expectedContent, actualContent.trim());
-    }
-}
-
-/**
- * Verify the label of the option that is selected.
- */
-Selenium.prototype.assertSelected = function(target, expectedLabel) {
-    var element = this.page().findElement(target);
-    var selectedLabel = element.options[element.selectedIndex].text;
-    assertEquals(expectedLabel, selectedLabel);
-}
-
-/**
- * Verify the label of all of the options in the drop=down.
- */
-Selenium.prototype.assertSelectOptions = function(target, options) {
-    // Handle escpaced commas, by substitutine newlines.
-    options = options.replace("\\,", "\n");
-	var expectedOptions = options.split(",");
-	var element = this.page().findElement(target);
-
-    assertEquals("wrong number of options", expectedOptions.length, element.options.length);
-
-    for (var i = 0; i < element.options.length; i++) {
-        var option = element.options[i];
-        // Put the escaped commas back in.
-        var expectedOption = expectedOptions[i].replace("\n", ",");
-        assertEquals(expectedOption, option.text);
-    }
-}
-
-/**
- * Verify the value of an element attribute. The syntax for returning an element attribute
- * is <element-locator>@attribute-name
- */
-Selenium.prototype.assertAttribute = function(target, expected) {
-    var attributeValue = this.page().findAttribute(target);
-    assertEquals(expected, attributeValue);
-}
-
-/*
- * Asserts that the specified text is present in the page content.
- */
-Selenium.prototype.assertTextPresent = function(expectedText) {
-    var allText = this.page().bodyText();
-
-    if(allText == "") {
-        error("Page text not found")
-    } else if(allText.indexOf(expectedText) == -1) {
-        fail("'" + expectedText + "' not found in page text.");
-    }
-}
-
-/*
- * Asserts that the specified element can be found.
- */
-Selenium.prototype.assertElementPresent = function(locator) {
-    try {
-        this.page().findElement(locator);
-    } catch (e) {
-        fail("Element " + locator + " not found.");
-    }
-}
-
-/*
- * Asserts that the specified element cannot be found.
- */
-Selenium.prototype.assertElementNotPresent = function(locator) {
-    try {
-        this.page().findElement(locator);
-    }
-    catch (e) {
-        return;
-    }
-    fail("Element " + locator + " found.");
-}
-
-
- /*
-  * Return all buttons on the screen.
-  */
-Selenium.prototype.getAllButtons = function() {
- 		return this.page().getAllButtons();
-}
-
- /*
-  * Return all links on the screen.
-  */
-Selenium.prototype.getAllLinks = function() {
- 		return this.page().getAllLinks();
-}
-
- /*
-  * Return all fields on the screen.
-  */
-Selenium.prototype.getAllFields = function() {
- 		return this.page().getAllFields();
-}
\ No newline at end of file
+/*
+ * Copyright 2004 ThoughtWorks, Inc
+ *
+ *  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.
+ *
+ */
+
+var nextExecution;
+function executeNext() {
+    LOG.debug("CODED - LOAD");
+    if (nextExecution) {
+        nextExecution();
+    }
+    nextExecution = null;
+}
+
+var assert = new Assert();
+function Selenium(browserbot) {
+    this.browserbot = browserbot;
+    this.page = function() {
+        return browserbot.getCurrentPage();
+    };
+
+    var self = this;
+
+    this.callOnNextPageLoad = function(callback) {
+        nextExecution = callback;
+        self.browserbot.callOnNextPageLoad(executeNext);
+    };
+}
+
+/*
+ * Click on the located element, and attach a callback to notify
+ * when the page is reloaded.
+ */
+Selenium.prototype.doModalDialogTest = function(returnValue) {
+    this.browserbot.doModalDialogTest(returnValue);
+};
+
+/*
+ * Click on the located element, and attach a callback to notify
+ * when the page is reloaded.
+ */
+Selenium.prototype.doClick = function(locator) {
+    var element = this.page().findElement(locator);
+    this.page().clickElement(element);
+};
+
+/**
+ * Overwrite the text in the located text element.
+ * TODO fail if it can't be typed into.
+ */
+Selenium.prototype.doType = function(locator, newText) {
+    var element = this.page().findElement(locator);
+    this.page().replaceText(element, newText);
+};
+
+/**
+ * Select the option by label from the located select element.
+ * TODO fail if it's not a select.
+ */
+Selenium.prototype.doSelect = function(locator, optionText) {
+    var element = this.page().findElement(locator);
+    this.page().selectOptionWithLabel(element, optionText);
+};
+
+/*
+ * Open the browser to a new location.
+ */
+Selenium.prototype.doOpen = function(newLocation) {
+    this.browserbot.openLocation(newLocation);
+    return SELENIUM_PROCESS_WAIT;
+};
+
+/*
+ * Select the named window to be the active window.
+ */
+Selenium.prototype.doSelectWindow = function(windowName) {
+    this.browserbot.selectWindow(windowName);
+};
+
+/*
+ * Instruct Selenium to click Cancel on the next confirm dialog it encounters
+ */
+Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
+    this.browserbot.cancelNextConfirmation();
+};
+
+/*
+ * Simulate the browser back button
+ */
+Selenium.prototype.doGoBack = function() {
+    this.page().goBack();
+};
+
+/*
+ *  Asserts that the supplied message was received as an alert
+ */
+ Selenium.prototype.assertAlert = function(expectedAlert) {
+    if ( this.browserbot.hasAlerts()) {
+        
+        receivedAlert = this.browserbot.getNextAlert();
+        if ( receivedAlert != expectedAlert ) {
+           assert.fail("The alert was [" + receivedAlert + "]");
+        }
+                          
+    } else {
+        assert.fail("There were no alerts");
+    }
+ };
+
+  /*
+  *  Asserts that the supplied message was received as a confirmation
+  */
+  Selenium.prototype.assertConfirmation = function(expectedConfirmation) {
+     if ( this.browserbot.hasConfirmations()) {
+         
+         receivedConfirmation = this.browserbot.getNextConfirmation();
+         if ( receivedConfirmation != expectedConfirmation ) {
+            assert.fail("The confirmation message was [" + receivedConfirmation + "]");
+         }
+                           
+     } else {
+         assert.fail("There were no confirmations");
+     }
+  };
+ 
+/*
+ * Verify the location of the current page.
+ */
+Selenium.prototype.assertAbsoluteLocation = function(expectedLocation) {
+    this.assertMatches(expectedLocation, this.page().location);
+};
+
+
+/*
+ * Verify the location of the current page ends with the expected location
+ */
+Selenium.prototype.assertLocation = function(expectedLocation) {
+    var docLocation = this.page().location.toString();
+    if (docLocation.length != docLocation.indexOf(expectedLocation) + expectedLocation.length)
+    {
+        assert.fail("Expected location to end with '" + expectedLocation
+             + "' but was '" + docLocation + "'");
+    }
+};
+
+/*
+ * Verify the title of the current page.
+ */
+Selenium.prototype.assertTitle = function(expectedTitle) {
+    this.assertMatches(expectedTitle, this.page().title());
+};
+
+/*
+ * Verify the value of a form element.
+ */
+Selenium.prototype.assertValue = function(locator, expectedValue) {
+    var element = this.page().findElement(locator);
+    var actualValue = getInputValue(element);
+    this.assertMatches(expectedValue, actualValue.trim());
+};
+
+/*
+ * Verifies that the text of the located element matches the expected content.
+ */
+Selenium.prototype.assertText = function(locator, expectedContent) {
+    var element = this.page().findElement(locator);
+    var actualText = getText(element);
+    this.assertMatches(expectedContent, actualText.trim());
+};
+
+/*
+ * Asserts that the text for a single cell within and HTML table matches the expected content.
+ * The table locator syntax is table.row.column.
+ */
+Selenium.prototype.assertTable = function(tableLocator, expectedContent) {
+    // This regular expression matches "tableName.row.column"
+    // For example, "mytable.3.4"
+    pattern = /(.*)\.(\d+)\.(\d+)/;
+
+    if(!pattern.test(tableLocator)) {
+        assert.fail("Invalid target format. Correct format is tableName.rowNum.columnNum");
+    }
+
+    pieces = tableLocator.match(pattern);
+
+    tableName = pieces[1];
+    row = pieces[2];
+    col = pieces[3];
+
+    var table = this.page().findElement(tableName);
+    if (row > table.rows.length) {
+        assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
+    }
+    else if (col > table.rows[row].cells.length) {
+        assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
+    }
+    else {
+        actualContent = getText(table.rows[row].cells[col]);
+        this.assertMatches(expectedContent, actualContent.trim());
+    }
+};
+
+/**
+ * Verify the label of the option that is selected.
+ */
+Selenium.prototype.assertSelected = function(target, expectedLabel) {
+    var element = this.page().findElement(target);
+    var selectedLabel = element.options[element.selectedIndex].text;
+    this.assertMatches(expectedLabel, selectedLabel);
+};
+
+/**
+ * Verify the label of all of the options in the drop=down.
+ */
+Selenium.prototype.assertSelectOptions = function(target, options) {
+    // Handle escpaced commas, by substitutine newlines.
+    options = options.replace("\\,", "\n");
+    var expectedOptions = options.split(",");
+    var element = this.page().findElement(target);
+
+    assert.equals("Wrong number of options.", expectedOptions.length, element.options.length);
+
+    for (var i = 0; i < element.options.length; i++) {
+        var option = element.options[i];
+        // Put the escaped commas back in.
+        var expectedOption = expectedOptions[i].replace("\n", ",");
+        this.assertMatches(expectedOption, option.text);
+    }
+};
+
+/**
+ * Verify the value of an element attribute. The syntax for returning an element attribute
+ * is <element-locator>@attribute-name
+ */
+Selenium.prototype.assertAttribute = function(target, expected) {
+    var attributeValue = this.page().findAttribute(target);
+    this.assertMatches(expected, attributeValue);
+};
+
+/*
+ * Asserts that the specified text is present in the page content.
+ */
+Selenium.prototype.assertTextPresent = function(expectedText) {
+    var allText = this.page().bodyText();
+
+    if(allText == "") {
+        assert.fail("Page text not found");
+    } else if(allText.indexOf(expectedText) == -1) {
+        assert.fail("'" + expectedText + "' not found in page text.");
+    }
+};
+
+/*
+ * Asserts that the specified text is NOT present in the page content.
+ */
+Selenium.prototype.assertTextNotPresent = function(unexpectedText) {
+    var allText = this.page().bodyText();
+
+    if(allText == "") {
+        assert.fail("Page text not found");
+    } else if(allText.indexOf(unexpectedText) != -1) {
+        assert.fail("'" + unexpectedText + "' was found in page text.");
+    }
+};
+
+/*
+ * Asserts that the specified element can be found.
+ */
+Selenium.prototype.assertElementPresent = function(locator) {
+    try {
+        this.page().findElement(locator);
+    } catch (e) {
+        assert.fail("Element " + locator + " not found.");
+    }
+};
+
+/*
+ * Asserts that the specified element cannot be found.
+ */
+Selenium.prototype.assertElementNotPresent = function(locator) {
+    try {
+        this.page().findElement(locator);
+    }
+    catch (e) {
+        return;
+    }
+    assert.fail("Element " + locator + " found.");
+};
+
+/*
+ * Asserts that the specified element is visible
+ */
+Selenium.prototype.assertVisible = function(locator) {
+    var element;
+    try {
+        element = this.page().findElement(locator);
+    } catch (e) {
+        assert.fail("Element " + locator + " not present.");
+    }
+    if (! this.isVisible(element)) {
+        assert.fail("Element " + locator + " not visible.");
+    }
+};
+
+/*
+ * Asserts that the specified element is visible
+ */
+Selenium.prototype.assertNotVisible = function(locator) {
+    var element;
+    try {
+        element = this.page().findElement(locator);
+    } catch (e) {
+        return;
+    }
+    if (this.isVisible(element)) {
+        assert.fail("Element " + locator + " is visible.");
+    }
+};
+
+Selenium.prototype.isVisible = function(element) {
+    var visibility = this.getEffectiveStyleProperty(element, "visibility");
+    var isDisplayed = this.isDisplayed(element);
+    return (visibility != "hidden" && isDisplayed);
+};
+
+Selenium.prototype.getEffectiveStyleProperty = function(element, property) {
+    var effectiveStyle = this.getEffectiveStyle(element);
+    var propertyValue = effectiveStyle[property];
+    if (propertyValue == 'inherit' && element.parentNode.style) {
+        return this.getEffectiveStyleProperty(element.parentNode, property);
+    }
+    return propertyValue;
+};
+
+Selenium.prototype.isDisplayed = function(element) {
+    var display = this.getEffectiveStyleProperty(element, "display");
+    if (display == "none") return false;
+    if (element.parentNode.style) {
+        return this.isDisplayed(element.parentNode);
+    }
+    return true;
+};
+
+Selenium.prototype.getEffectiveStyle = function(element) {
+    if (element.style == undefined) {
+        return undefined; // not a styled element
+    }
+    var window = this.browserbot.getContentWindow();
+    if (window.getComputedStyle) { 
+        // DOM-Level-2-CSS
+        return window.getComputedStyle(element, null);
+    }
+    if (element.currentStyle) {
+        // non-standard IE alternative
+        return element.currentStyle;
+        // TODO: this won't really work in a general sense, as
+        //   currentStyle is not identical to getComputedStyle()
+        //   ... but it's good enough for "visibility"
+    }
+    throw new Error("cannot determine effective stylesheet in this browser");
+};
+
+/**
+ * Asserts that the specified element accepts user input visible
+ */
+Selenium.prototype.assertEditable = function(locator) {
+    var element = this.page().findElement(locator);
+    if (element.value == undefined) {
+        assert.fail("Element " + locator + " is not an input.");
+    }
+    if (element.disabled) {
+        assert.fail("Element " + locator + " is disabled.");
+    }
+};
+
+/**
+ * Asserts that the specified element does not accept user input
+ */
+Selenium.prototype.assertNotEditable = function(locator) {
+    var element = this.page().findElement(locator);
+    if (element.value == undefined) {
+        return; // not an input
+    }
+    if (element.disabled == false) {
+        assert.fail("Element " + locator + " is editable.");
+    }
+};
+
+ /*
+  * Return all buttons on the screen.
+  */
+Selenium.prototype.getAllButtons = function() {
+        return this.page().getAllButtons();
+};
+
+ /*
+  * Return all links on the screen.
+  */
+Selenium.prototype.getAllLinks = function() {
+        return this.page().getAllLinks();
+};
+
+ /*
+  * Return all fields on the screen.
+  */
+Selenium.prototype.getAllFields = function() {
+        return this.page().getAllFields();
+};
+
+/*
+  * Set the context for the current Test
+  */
+Selenium.prototype.doContext = function(context) {
+        return this.page().setContext(context);
+};
+
+function Assert() {
+    this.equals = function()
+    {
+        if (arguments.length == 2)
+        {
+            var comment = "";
+            var expected = arguments[0];
+            var actual = arguments[1];
+        }
+        else {
+            var comment = arguments[0] + " ";
+            var expected = arguments[1];
+            var actual = arguments[2];
+        }
+
+        if (expected === actual) {
+            return;
+        }
+        var errorMessage = comment + "Expected '" + expected + "' but was '" + actual + "'";
+
+        throw new AssertionFailedError(errorMessage);
+    };
+
+    this.fail = function(message)
+    {
+        throw new AssertionFailedError(message);
+    };
+}
+
+function AssertionFailedError(message) {
+    this.isAssertionFailedError = true;
+    this.failureMessage = message;
+}
+
+/*
+ * assertMatches(comment?, pattern, actual)
+ */
+Selenium.prototype.assertMatches = function() {
+    if (arguments.length == 2)
+    {
+        var comment = "";
+        var pattern = arguments[0];
+        var actual = arguments[1];
+    }
+    else {
+        var comment = arguments[0] + "; ";
+        var pattern = arguments[1];
+        var actual = arguments[2];
+    }
+
+    if (this.matches(pattern, actual)) {
+        return;
+    }
+
+    var errorMessage = comment + 
+        "Actual value '" + actual + "' did not match '" + pattern + "'";
+    assert.fail(errorMessage);
+};
+
+Selenium.prototype.globToRegexp = function(glob) {
+    var pattern = glob;
+    pattern = pattern.replace(/([.^$+(){}[\]\\|])/g, "\\$1");
+    pattern = pattern.replace(/\?/g, ".");
+    pattern = pattern.replace(/\*/g, ".*");
+    return "^" + pattern + "$";
+};
+
+Selenium.prototype.matches = function(pattern, actual) {
+    var regexp = new RegExp(this.globToRegexp(pattern));
+    // Work around Konqueror bug when matching empty strings.
+    var testString = '' + actual;
+    return regexp.test(testString);
+};


=== Products/Zelenium/selenium/selenium-browserbot.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-browserbot.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-browserbot.js	Mon May  2 23:48:16 2005
@@ -1,429 +1,720 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- *
- */
- 
-/*
- * This script provides the Javascript API to drive the test application contained within
- * a Browser Window.
- * TODO:
- *    Add support for more events (keyboard and mouse)
- *    Allow to switch "user-entry" mode from mouse-based to keyboard-based, firing different
- *          events in different modes.
- */
-
-// The window to which the commands will be sent.  For example, to click on a
-// popup window, first select that window, and then do a normal click command.
-
-var browserName=navigator.appName;
-var isIE = (browserName =="Microsoft Internet Explorer");
-// Get the Gecko version as an 8 digit date. 
-var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
-var geckoVersion = geckoResult == null ? null : geckoResult[1];
-
-
-
-/*
- * The 'invoke' method will call the required function, and then
- * remove itself from the window object. This allows a calling app
- * to provide a callback listener for the window load event, without the
- * calling app needing to worry about cleaning up afterward.
- * TODO: This could be more generic, but suffices for now.
- */
-function SelfRemovingLoadListener(fn, frame) {
-    var self = this;
-
-    this.invoke=function () {
-        try {
-            // we've moved to a new page - clear the current one
-            browserbot.currentPage = null;
-            fn();
-        } finally {
-            removeLoadListener(frame, self.invoke);
-        }
-    }
-}
-
-BrowserBot = function(frame) {
-    this.frame = frame;
-    this.currentPage = null;
-    this.currentWindowName = null;
-    
-    this.recordedAlerts = new Array();
-    this.recordedConfirmations = new Array();
-    this.nextConfirmResult = true;
-
-}
-
-BrowserBot.prototype.cancelNextConfirmation = function() {
-    this.nextConfirmResult = false;
-}
-
-BrowserBot.prototype.hasAlerts = function() {
-   return (this.recordedAlerts.length > 0) ;
-}
-
-BrowserBot.prototype.getNextAlert = function() {
-   return this.recordedAlerts.shift();
-}
-
-BrowserBot.prototype.hasConfirmations = function() {
-    return (this.recordedConfirmations.length > 0) ;
-}
- 
-BrowserBot.prototype.getNextConfirmation = function() {
-    return this.recordedConfirmations.shift();
-}
-
-
-BrowserBot.prototype.getFrame = function() {
-    return this.frame;
-}
-
-BrowserBot.prototype.getContentWindow = function() {
-    return this.getFrame().contentWindow
-}
-
-BrowserBot.prototype.selectWindow = function(target) {
-    // we've moved to a new page - clear the current one
-    this.currentPage = null;
-    this.currentWindowName = null;
-    if (target != "null") {
-        // If window exists
-        if (this.getTargetWindow(target)) {
-            this.currentWindowName = target;
-        }
-    }
-}
-
-BrowserBot.prototype.openLocation = function(target, onloadCallback) {
-    // We're moving to a new page - clear the current one
-    this.currentPage = null;
-    this.callOnNextPageLoad(onloadCallback);
-    this.getFrame().src = target;
-}
-
-BrowserBot.prototype.getCurrentPage = function() {
-    if (this.currentPage == null) {
-        var testWindow = this.getContentWindow().window;
-        if (this.currentWindowName != null) {
-            testWindow = this.getTargetWindow(this.currentWindowName);
-        }
-        modifyWindowToRecordPopUpDialogs(testWindow, this);
-        modifyWindowToClearPageCache(testWindow, this);
-        this.currentPage =  new PageBot(testWindow);
-    }
-    
-    return this.currentPage;
-
-     // private functions below - is there a better way?
-    
-     function modifyWindowToRecordPopUpDialogs(window, browserBot) {   
-          window.alert = function(alert){browserBot.recordedAlerts.push(alert);};
-          window.confirm = function(message){
-                              browserBot.recordedConfirmations.push(message);
-                              var result = browserBot.nextConfirmResult;
-                              browserBot.nextConfirmResult = true;
-                              return result
-                           };
-     }
-     
-     function modifyWindowToClearPageCache(window, browserBot) {
-        //SPIKE factor this better via TDD
-        function clearPageCache() {
-          browserbot.currentPage = null;
-        }
-
-       if (window.addEventListener) {
-          testWindow.addEventListener("unload",clearPageCache, true);
-       }
-       else if (window.attachEvent) {
-          testWindow.attachEvent("onunload",clearPageCache);
-       }
-       // End SPIKE
-     }
-    
-
-}
-
-BrowserBot.prototype.getTargetWindow = function(windowName) {
-    var evalString = "this.getContentWindow().window." + windowName;
-    var targetWindow = eval(evalString);
-    if (!targetWindow) {
-        throw new Error("Window does not exist");
-    }
-    return targetWindow;
-}
-
-BrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
-    if (onloadCallback) {
-        var el = new SelfRemovingLoadListener(onloadCallback, this.frame);
-        addLoadListener(this.getFrame(), el.invoke);
-    }
-}
-
-
-PageBot = function(pageWindow) {
-    this.currentWindow = pageWindow;
-    this.currentDocument = pageWindow.document;
-    this.location = pageWindow.location.pathname;
-    this.title = function() {return this.currentDocument.title};
-
-    this.locators = new Array();
-    this.locators.push(this.findIdentifiedElement);
-    this.locators.push(this.findElementByDomTraversal);
-    this.locators.push(this.findElementByXPath);
-
-}
-
-/*
- * Finds an element on the current page, using various lookup protocols
- */
-PageBot.prototype.findElement = function(locator) {
-    // Try the locators one at a time.
-    for (var i = 0; i < this.locators.length; i++) {
-        var locatorFunction = this.locators[i];
-        var element = locatorFunction.call(this, locator);
-        if (element != null) {
-            return element;
-        }
-    }
-
-    // Element was not found by any locator function.
-    throw new Error("Element " + locator + " not found");
-}
-
-/*
- * In IE, getElementById() also searches by name.
- * To provied consistent functionality with Firefox, we
- * search by name attribute if an element with the id isn't found.
- */
-PageBot.prototype.findIdentifiedElement = function(identifier) {
-    // Since we try to get an id with _any_ string, we need to handle
-    // cases where this causes an exception.
-    try {
-        var element = this.currentDocument.getElementById(identifier);
-        if (element == null
-            && !isIE // IE checks this without asking
-            && document.evaluate )// DOM3 XPath
-        {
-             var xpath = "//*[@name='" + identifier + "']";
-             element = document.evaluate(xpath, this.currentDocument, null, 0, null).iterateNext();
-        }
-    } catch (e) {
-        return null;
-    }
-
-    return element;
-}
-
-/**
- * Finds an element using by evaluating the "document.*" string against the
- * current document object. Dom expressions must begin with "document."
- */
-PageBot.prototype.findElementByDomTraversal = function(domTraversal) {
-    if (domTraversal.indexOf("document.") != 0) {
-        return null;
-    }
-
-    // Trim the leading 'document'
-    domTraversal = domTraversal.substr(9);
-    var locatorScript = "this.currentDocument." + domTraversal;
-    var element = eval(locatorScript);
-
-    if (!element) {
-         return null;
-    }
-
-    return element;
-}
-
-/**
- * Finds an element identified by the xpath expression. Expressions _must_
- * begin with "//".
- */
-PageBot.prototype.findElementByXPath = function(xpath) {
-    if (xpath.indexOf("//") != 0) {
-        return null;
-    }
-
-    // If the document doesn't support XPath, mod it with html-xpath.
-    // This only works for IE.
-    if (!this.currentDocument.evaluate) {
-        addXPathSupport(this.currentDocument);
-    }
-
-    // If we still don't have XPath bail.
-    // TODO implement subset of XPath for browsers without native support.
-    if (!this.currentDocument.evaluate) {
-        throw new Error("XPath not supported");
-    }
-
-    // Trim any trailing "/": not valid xpath, and remains from attribute locator.
-    if (xpath.charAt(xpath.length - 1) == '/') {
-        xpath = xpath.slice(0, xpath.length - 1);
-    }
-
-    return this.currentDocument.evaluate(xpath, this.currentDocument, null, 0, null).iterateNext();
-}
-
-/**
- * Returns an attribute based on an attribute locator. This is made up of an element locator
- * suffixed with @attribute-name.
- */
-PageBot.prototype.findAttribute = function(locator) {
-    // Split into locator + attributeName
-    var attributePos = locator.lastIndexOf("@");
-    var elementLocator = locator.slice(0, attributePos);
-    var attributeName = locator.slice(attributePos + 1);
-
-    // Find the element.
-    var element = this.findElement(elementLocator);
-
-    // Handle missing "class" attribute in IE.
-    if (isIE && attributeName == "class") {
-        attributeName = "className";
-    }
-
-    // Get the attribute value.
-    var attributeValue = element.getAttribute(attributeName);
-
-    return attributeValue ? attributeValue.toString() : null;
-}
-
-/*
- * Selects the first option with a matching label from the select box element
- * provided. If no matching element is found, nothing happens.
- */
-PageBot.prototype.selectOptionWithLabel = function(element, stringValue) {
-    triggerEvent(element, 'focus', false);
-    for (var i = 0; i < element.options.length; i++) {
-        var option = element.options[i];
-        if (option.text == stringValue) {
-            if (!option.selected) {
-                option.selected = true;
-                triggerEvent(element, 'change', true);
-            }
-        }
-    }
-    triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.replaceText = function(element, stringValue) {
-    triggerEvent(element, 'focus', false);
-    triggerEvent(element, 'select', true);
-    element.value=stringValue;
-    if (isIE) {
-        triggerEvent(element, 'change', true);
-    }
-    triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.clickElement = function(element) {
-
-    triggerEvent(element, 'focus', false);
-
-    var wasChecked = element.checked;
-    if (isIE) {
-        element.click();
-    }
-    else {
-        // Add an event listener that detects if the default action has been prevented.
-        var preventDefault = false;
-        element.addEventListener("click", function(evt) {preventDefault = evt.getPreventDefault()}, false);
-
-        // Trigger the click event.
-        triggerMouseEvent(element, 'click', true);
-
-        // In FireFox < 1.0 Final, and Mozilla <= 1.7.3, just sending the click event is enough.
-        // But in newer versions, we need to do it ourselves.
-        var needsProgrammaticClick = (geckoVersion > '20041025');
-        // Perform the link action if preventDefault was set.
-        if (needsProgrammaticClick && element.href  && !preventDefault) {
-            this.currentWindow.location.href = element.href;
-        }
-    }
-
-    if (this.windowClosed()) {
-        return;
-    }
-    // Onchange event is not triggered automatically in IE.
-    if (isIE && isDefined(element.checked) && wasChecked != element.checked) {
-        triggerEvent(element, 'change', true);
-    }
-
-    triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.windowClosed = function(element) {
-    return this.currentWindow.closed;
-}
-
-PageBot.prototype.bodyText = function() {
-    return getText(this.currentDocument.body)
-}
-
-PageBot.prototype.getAllButtons = function() {
-    var elements = this.currentDocument.getElementsByTagName('input');
-    var result = '';
-
-    for (var i = 0; i < elements.length; i++) {
-    		if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {
-    				result += elements[i].id;
-
-    				result += ',';
-    		}
-    }
-
-    return result;
-}
-
-
-PageBot.prototype.getAllFields = function() {
-    var elements = this.currentDocument.getElementsByTagName('input');
-    var result = '';
-
-    for (var i = 0; i < elements.length; i++) {
-    		if (elements[i].type == 'text') {
-    				result += elements[i].id;
-
-    				result += ',';
-    		}
-    }
-
-    return result;
-}
-
-PageBot.prototype.getAllLinks = function() {
-    var elements = this.currentDocument.getElementsByTagName('a');
-    var result = '';
-
-    for (var i = 0; i < elements.length; i++) {
-    		result += elements[i].id;
-
-    		result += ',';
-    }
-
-    return result;
-}
-
-
-
-function isDefined(value) {
-    return typeof(value) != undefined;
-}
-
-
-
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+*  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.
+*
+*/
+
+/*
+* This script provides the Javascript API to drive the test application contained within
+* a Browser Window.
+* TODO:
+*    Add support for more events (keyboard and mouse)
+*    Allow to switch "user-entry" mode from mouse-based to keyboard-based, firing different
+*          events in different modes.
+*/
+
+// The window to which the commands will be sent.  For example, to click on a
+// popup window, first select that window, and then do a normal click command.
+
+
+// Although it's generally better web development practice not to use browser-detection
+// (feature detection is better), the subtle browser differences that Selenium has to
+// work around seem to make it necessary. Maybe as we learn more about what we need,
+// we can do this in a more "feature-centric" rather than "browser-centric" way.
+// TODO we should probably reuse an available browser-detection library
+var browserName=navigator.appName;
+var isIE = (browserName =="Microsoft Internet Explorer");
+var isKonqueror = (browserName == "Konqueror");
+var isSafari = (navigator.userAgent.indexOf('Safari') != -1);
+
+// Get the Gecko version as an 8 digit date.
+var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
+var geckoVersion = geckoResult == null ? null : geckoResult[1];
+
+function createBrowserBot(frame, executionContext) {
+    if (isIE) {
+        return new IEBrowserBot(frame, executionContext);
+    }
+    else if (isKonqueror) {
+        return new KonquerorBrowserBot(frame, executionContext);
+    }
+    else if (isSafari) {
+        return new SafariBrowserBot(frame, executionContext);
+    }
+    else {
+        // Use mozilla by default
+        return new MozillaBrowserBot(frame, executionContext);
+    }
+}
+
+function createPageBot(windowObject) {
+    if (isIE) {
+        return new IEPageBot(windowObject);
+    }
+    else if (isKonqueror) {
+        return new KonquerorPageBot(windowObject);
+    }
+    else if (isSafari) {
+        return new SafariPageBot(windowObject);
+    }
+    else {
+        // Use mozilla by default
+        return new MozillaPageBot(windowObject);
+    }
+}
+
+BrowserBot = function(frame, executionContext) {
+    this.frame = frame;
+    this.executionContext = executionContext;
+    this.currentPage = null;
+    this.currentWindowName = null;
+
+    this.modalDialogTest = null;
+    this.recordedAlerts = new Array();
+    this.recordedConfirmations = new Array();
+    this.nextConfirmResult = true;
+};
+
+BrowserBot.prototype.doModalDialogTest = function(test) {
+    this.modalDialogTest = test;
+};
+
+BrowserBot.prototype.cancelNextConfirmation = function() {
+    this.nextConfirmResult = false;
+};
+
+BrowserBot.prototype.hasAlerts = function() {
+    return (this.recordedAlerts.length > 0) ;
+};
+
+BrowserBot.prototype.getNextAlert = function() {
+    return this.recordedAlerts.shift();
+};
+
+BrowserBot.prototype.hasConfirmations = function() {
+    return (this.recordedConfirmations.length > 0) ;
+};
+
+BrowserBot.prototype.getNextConfirmation = function() {
+    return this.recordedConfirmations.shift();
+};
+
+
+BrowserBot.prototype.getFrame = function() {
+    return this.frame;
+};
+
+BrowserBot.prototype.getContentWindow = function() {
+    return this.executionContext.getContentWindow(this.getFrame());
+
+};
+
+BrowserBot.prototype.selectWindow = function(target) {
+    // we've moved to a new page - clear the current one
+    this.currentPage = null;
+    this.currentWindowName = null;
+    if (target != "null") {
+        // If window exists
+        if (this.getTargetWindow(target)) {
+            this.currentWindowName = target;
+        }
+    }
+};
+
+BrowserBot.prototype.openLocation = function(target, onloadCallback) {
+    // We're moving to a new page - clear the current one
+    this.currentPage = null;
+    this.executionContext.open(target,this.getFrame());
+};
+
+BrowserBot.prototype.getCurrentPage = function() {
+    if (this.currentPage == null) {
+        var testWindow = this.getContentWindow().window;
+        if (this.currentWindowName != null) {
+            testWindow = this.getTargetWindow(this.currentWindowName);
+        }
+        this.modifyWindowToRecordPopUpDialogs(testWindow, this);
+        this.modifyWindowToClearPageCache(testWindow, this);
+        this.currentPage = createPageBot(testWindow);
+    }
+
+    return this.currentPage;
+};
+
+BrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+    windowToModify.alert = function(alert) {
+        browserBot.recordedAlerts.push(alert);
+    };
+
+    windowToModify.confirm = function(message) {
+        browserBot.recordedConfirmations.push(message);
+        var result = browserBot.nextConfirmResult;
+        browserBot.nextConfirmResult = true;
+        return result;
+    };
+};
+
+BrowserBot.prototype.modifyWindowToClearPageCache = function(windowToModify, browserBot) {
+    var clearCachedPage = function() {
+        LOG.debug("UNLOAD: clearCachedPage()");
+        browserbot.currentPage = null;
+    };
+
+    if (window.addEventListener) {
+        windowToModify.addEventListener("unload", clearCachedPage, true);
+    } else if (window.attachEvent) {
+        windowToModify.attachEvent("onunload", clearCachedPage);
+    }
+};
+
+BrowserBot.prototype.getTargetWindow = function(windowName) {
+    var evalString = "this.getContentWindow().window." + windowName;
+    var targetWindow = eval(evalString);
+    if (!targetWindow) {
+        throw new Error("Window does not exist");
+    }
+    return targetWindow;
+};
+
+BrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
+    addLoadListener(this.frame, onloadCallback);
+};
+
+function MozillaBrowserBot(frame, executionContext) {
+    BrowserBot.call(this, frame, executionContext);
+}
+MozillaBrowserBot.prototype = new BrowserBot;
+
+function KonquerorBrowserBot(frame, executionContext) {
+    BrowserBot.call(this, frame, executionContext);
+}
+KonquerorBrowserBot.prototype = new BrowserBot;
+
+function SafariBrowserBot(frame, executionContext) {
+    BrowserBot.call(this, frame, executionContext);
+}
+SafariBrowserBot.prototype = new BrowserBot;
+
+/**
+ * Since Safari 1.3 doesn't trigger unload, we clear cached page as soon as
+ * we know that we're expecting a new page.
+ */
+SafariBrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
+    this.currentPage = null;
+
+    try {
+        addLoadListener(this.frame, onloadCallback);
+    } catch (e) {
+        LOG.debug("Got on error adding LoadListener in BrowserBot.prototype.callOnNextPageLoad." +
+                  "This occurs on the second and all subsequent calls in Safari");
+    }
+};
+
+function IEBrowserBot(frame, executionContext) {
+    BrowserBot.call(this, frame, executionContext);
+}
+IEBrowserBot.prototype = new BrowserBot;
+
+IEBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+    BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
+
+    // we will call the previous version of this method from within our own interception
+    oldShowModalDialog = windowToModify.showModalDialog;
+
+    windowToModify.showModalDialog = function(url, args, features) {
+        // Get relative directory to where TestRunner.html lives
+        // A risky assumption is that the user's TestRunner is named TestRunner.html
+        var doc_location = document.location.toString();
+        var end_of_base_ref = doc_location.indexOf('TestRunner.html');
+        var base_ref = doc_location.substring(0, end_of_base_ref);
+
+        var fullURL = base_ref + "TestRunner.html?singletest=" + escape(browserBot.modalDialogTest) + "&autoURL=" + escape(url) + "&runInterval=" + runInterval;
+        browserBot.modalDialogTest = null;
+
+        var returnValue = oldShowModalDialog(fullURL, args, features);
+        return returnValue;
+    };
+};
+
+SafariBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+    BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
+
+    var originalOpen = windowToModify.open;
+    /*
+     * Safari seems to be broken, so that when we manually trigger the onclick method
+     * of a button/href, any window.open calls aren't resolved relative to the app location.
+     * So here we replace the open() method with one that does resolve the url correctly.
+     */
+    windowToModify.open = function(url, windowName, windowFeatures, replaceFlag) {
+
+        if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")) {
+            return originalOpen(url, windowName, windowFeatures, replaceFlag);
+        }
+
+        // Reduce the current path to the directory
+        var currentPath = windowToModify.location.pathname || "/";
+        currentPath = currentPath.replace(/\/[^\/]*$/, "/");
+
+        // Remove any leading "./" from the new url.
+        url = url.replace(/^\.\//, "");
+
+        newUrl = currentPath + url;
+
+        return originalOpen(newUrl, windowName, windowFeatures, replaceFlag);
+    };
+};
+
+PageBot = function(pageWindow) {
+    if (pageWindow) {
+        this.currentWindow = pageWindow;
+        this.currentDocument = pageWindow.document;
+        this.location = pageWindow.location.pathname;
+        this.title = function() {return this.currentDocument.title;};
+
+        // Register all locate* functions
+        this.locatorFunctions = new Array();
+        for (var f in this) {
+            if (typeof(this[f]) == 'function' && f.match(/^locate/)) {
+                this.locatorFunctions.push(this[f]);
+            }
+        }
+    }
+};
+
+MozillaPageBot = function(pageWindow) {
+    PageBot.call(this, pageWindow);
+};
+MozillaPageBot.prototype = new PageBot();
+
+KonquerorPageBot = function(pageWindow) {
+    PageBot.call(this, pageWindow);
+};
+KonquerorPageBot.prototype = new PageBot();
+
+SafariPageBot = function(pageWindow) {
+    PageBot.call(this, pageWindow);
+};
+SafariPageBot.prototype = new PageBot();
+
+IEPageBot = function(pageWindow) {
+    PageBot.call(this, pageWindow);
+};
+IEPageBot.prototype = new PageBot();
+
+/*
+* Finds an element on the current page, using various lookup protocols
+*/
+PageBot.prototype.findElement = function(locator) {
+    var element = this.findElementInDocument(locator, this.currentDocument);
+
+    if (element != null) {
+        return element;
+    } else {
+        for (var i = 0; i < this.currentWindow.frames.length; i++) {
+            element = this.findElementInDocument(locator, this.currentWindow.frames[i].document);
+            if (element != null) {
+                return element;
+            }
+        }
+    }
+
+    // Element was not found by any locator function.
+    throw new Error("Element " + locator + " not found");
+};
+
+PageBot.prototype.findElementInDocument = function(locator, inDocument) {
+    // Try the locatorFunctions one at a time.
+    for (var i = 0; i < this.locatorFunctions.length; i++) {
+        var locatorFunction = this.locatorFunctions[i];
+        var element = locatorFunction.call(this, locator, inDocument);
+        if (element != null) {
+            return element;
+        }
+    }
+};
+
+/**
+ * In IE, getElementById() also searches by name.
+ */
+IEPageBot.prototype.locateElementById = function(identifier, inDocument) {
+    try {
+        return inDocument.getElementById(identifier);
+    } catch (e) {
+        return null;
+    }
+};
+
+/**
+ * In other browsers, getElementById() does not search by name.  To provide
+ * functionality consistent with IE, we search by @name if an element with
+ * the @id isn't found.
+ */
+PageBot.prototype.locateElementById = function(identifier, inDocument) {
+    try {
+        var element = inDocument.getElementById(identifier);
+        if (element == null)
+        {
+            if ( document.evaluate ) {// DOM3 XPath
+                var xpath = "//*[@name='" + identifier + "']";
+                element = document.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+            }
+            // Search through all elements for Konqueror/Safari
+            else {
+                var allElements = inDocument.getElementsByTagName("*");
+                for (var i = 0; i < allElements.length; i++) {
+                    var testElement = allElements[i];
+                    if (testElement.name && testElement.name === identifier) {
+                        element = testElement;
+                        break;
+                    }
+                }
+            }
+        }
+    } catch (e) {
+        return null;
+    }
+
+    return element;
+};
+
+/**
+* Finds an element using by evaluating the "document.*" string against the
+* current document object. Dom expressions must begin with "document."
+*/
+PageBot.prototype.locateElementByDomTraversal = function(domTraversal, inDocument) {
+    if (domTraversal.indexOf("document.") != 0) {
+        return null;
+    }
+
+    // Trim the leading 'document'
+    domTraversal = domTraversal.substr(9);
+    var locatorScript = "inDocument." + domTraversal;
+    var element = eval(locatorScript);
+
+    if (!element) {
+        return null;
+    }
+
+    return element;
+};
+
+/**
+* Finds an element identified by the xpath expression. Expressions _must_
+* begin with "//".
+*/
+PageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
+    if (xpath.indexOf("//") != 0) {
+        return null;
+    }
+
+    // If don't have XPath bail.
+    // TODO implement subset of XPath for browsers without native support.
+    if (!inDocument.evaluate) {
+        throw new Error("XPath not supported");
+    }
+
+    // Trim any trailing "/": not valid xpath, and remains from attribute locator.
+    if (xpath.charAt(xpath.length - 1) == '/') {
+        xpath = xpath.slice(0, xpath.length - 1);
+    }
+
+    return inDocument.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+};
+
+/**
+ * For IE, we implement XPath support using the html-xpath library.
+ */
+IEPageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
+    if (xpath.indexOf("//") != 0) {
+        return null;
+    }
+
+    if (!inDocument.evaluate) {
+        addXPathSupport(inDocument);
+    }
+
+    return PageBot.prototype.locateElementByXPath(xpath, inDocument);
+};
+
+/**
+* Finds a link element with text matching the expression supplied. Expressions must
+* begin with "link:".
+*/
+PageBot.prototype.locateLinkByText = function(linkDescription, inDocument) {
+    var prefix = "link:";
+    if (linkDescription.indexOf(prefix) != 0) {
+        return null;
+    }
+
+    var linkText = linkDescription.substring(prefix.length);
+    var links = inDocument.getElementsByTagName('a');
+    for (var i = 0; i < links.length; i++) {
+        var element = links[i];
+        if (getText(element) == linkText) {
+            return element;
+        }
+    }
+    return null;
+};
+
+/**
+* Returns an attribute based on an attribute locator. This is made up of an element locator
+* suffixed with @attribute-name.
+*/
+PageBot.prototype.findAttribute = function(locator) {
+    // Split into locator + attributeName
+    var attributePos = locator.lastIndexOf("@");
+    var elementLocator = locator.slice(0, attributePos);
+    var attributeName = locator.slice(attributePos + 1);
+
+    // Find the element.
+    var element = this.findElement(elementLocator);
+
+    // Handle missing "class" attribute in IE.
+    if (isIE && attributeName == "class") {
+        attributeName = "className";
+    }
+
+    // Get the attribute value.
+    var attributeValue = element.getAttribute(attributeName);
+
+    return attributeValue ? attributeValue.toString() : null;
+};
+
+/*
+* Selects the first option with a matching label from the select box element
+* provided. If no matching element is found, nothing happens.
+*/
+PageBot.prototype.selectOptionWithLabel = function(element, stringValue) {
+    triggerEvent(element, 'focus', false);
+    for (var i = 0; i < element.options.length; i++) {
+        var option = element.options[i];
+        if (option.text == stringValue) {
+            if (!option.selected) {
+                option.selected = true;
+                triggerEvent(element, 'change', true);
+            }
+            triggerEvent(element, 'blur', false);
+            return;
+        }
+    }
+    throw new Error("Option with label '" + stringValue + "' not found");
+};
+
+PageBot.prototype.replaceText = function(element, stringValue) {
+    triggerEvent(element, 'focus', false);
+    triggerEvent(element, 'select', true);
+    element.value=stringValue;
+    if (isIE || isKonqueror || isSafari) {
+        triggerEvent(element, 'change', true);
+    }
+    triggerEvent(element, 'blur', false);
+};
+
+MozillaPageBot.prototype.clickElement = function(element) {
+
+    triggerEvent(element, 'focus', false);
+
+    // Add an event listener that detects if the default action has been prevented.
+    // (This is caused by a javascript onclick handler returning false)
+    var preventDefault = false;
+    if (geckoVersion) {
+        element.addEventListener("click", function(evt) {preventDefault = evt.getPreventDefault();}, false);
+    }
+
+    // Trigger the click event.
+    triggerMouseEvent(element, 'click', true);
+
+    // In FireFox < 1.0 Final, and Mozilla <= 1.7.3, just sending the click event is enough.
+    // But in newer versions, we need to do it ourselves.
+    var needsProgrammaticClick = (geckoVersion > '20041025');
+    // Perform the link action if preventDefault was set.
+    if (needsProgrammaticClick && !preventDefault) {
+        // Try the element itself, as well as it's parent - this handles clicking images inside links.
+        if (element.href) {
+            this.currentWindow.location.href = element.href;
+        }
+        else if (element.parentNode.href) {
+            this.currentWindow.location.href = element.parentNode.href;
+        }
+    }
+
+    if (this.windowClosed()) {
+        return;
+    }
+
+    triggerEvent(element, 'blur', false);
+};
+
+KonquerorPageBot.prototype.clickElement = function(element) {
+
+    triggerEvent(element, 'focus', false);
+
+    if (element.click) {
+        element.click();
+    }
+    else {
+        triggerMouseEvent(element, 'click', true);
+    }
+
+    if (this.windowClosed()) {
+        return;
+    }
+
+    triggerEvent(element, 'blur', false);
+};
+
+SafariPageBot.prototype.clickElement = function(element) {
+
+    triggerEvent(element, 'focus', false);
+
+    var wasChecked = element.checked;
+    
+    // For form element it is simple.
+    if (element.click) {
+        element.click();
+    }
+    // For links and other elements, event emulation is required.
+    else {
+        triggerEvent(element, 'click', true);
+
+        // Unfortunately, triggering the event doesn't seem to activate onclick handlers.
+        // We currently call onclick for the link, but I'm guessing that the onclick for containing
+        // elements is not being called.
+        var success = true;
+        if (element.onclick) {
+            var evt = document.createEvent('HTMLEvents');
+            evt.initEvent('click', true, true);
+            var onclickResult = element.onclick(evt);
+            if (onclickResult === false) {
+                success = false;
+            }
+        }
+
+        if (success) {
+            // Try the element itself, as well as it's parent - this handles clicking images inside links.
+            if (element.href) {
+                this.currentWindow.location.href = element.href;
+            }
+            else if (element.parentNode.href) {
+                this.currentWindow.location.href = element.parentNode.href;
+            } else {
+                // This is true for buttons outside of forms, and maybe others.
+                LOG.warn("Ignoring 'click' call for button outside form, or link without href."
+                        + "Using buttons without an enclosing form can cause wierd problems with URL resolution in Safari." );
+                // I implemented special handling for window.open, but unfortunately this behaviour is also displayed
+                // when we have a button without an enclosing form that sets document.location in the onclick handler.
+                // The solution is to always use an enclosing form for a button.
+            }
+        }
+    }
+
+    // Onchange event is not triggered automatically in Safari.
+    if (isDefined(element.checked) && wasChecked != element.checked) {
+        triggerEvent(element, 'change', true);
+    }
+
+    if (this.windowClosed()) {
+        return;
+    }
+
+    triggerEvent(element, 'blur', false);
+};
+
+IEPageBot.prototype.clickElement = function(element) {
+
+    triggerEvent(element, 'focus', false);
+
+    var wasChecked = element.checked;
+    element.click();
+
+    if (this.windowClosed()) {
+        return;
+    }
+    // Onchange event is not triggered automatically in IE.
+    if (isDefined(element.checked) && wasChecked != element.checked) {
+        triggerEvent(element, 'change', true);
+    }
+
+    triggerEvent(element, 'blur', false);
+};
+
+PageBot.prototype.windowClosed = function(element) {
+    return this.currentWindow.closed;
+};
+
+PageBot.prototype.bodyText = function() {
+    return getText(this.currentDocument.body);
+};
+
+PageBot.prototype.getAllButtons = function() {
+    var elements = this.currentDocument.getElementsByTagName('input');
+    var result = '';
+
+    for (var i = 0; i < elements.length; i++) {
+        if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {
+            result += elements[i].id;
+
+            result += ',';
+        }
+    }
+
+    return result;
+};
+
+
+PageBot.prototype.getAllFields = function() {
+    var elements = this.currentDocument.getElementsByTagName('input');
+    var result = '';
+
+    for (var i = 0; i < elements.length; i++) {
+        if (elements[i].type == 'text') {
+            result += elements[i].id;
+
+            result += ',';
+        }
+    }
+
+    return result;
+};
+
+PageBot.prototype.getAllLinks = function() {
+    var elements = this.currentDocument.getElementsByTagName('a');
+    var result = '';
+
+    for (var i = 0; i < elements.length; i++) {
+        result += elements[i].id;
+
+        result += ',';
+    }
+
+    return result;
+};
+
+PageBot.prototype.setContext = function(strContext) {
+     //set the current test title
+    context.innerHTML=strContext;
+};
+
+function isDefined(value) {
+    return typeof(value) != undefined;
+}
+
+PageBot.prototype.goBack = function() {
+    this.currentWindow.history.back();
+};
+
+PageBot.prototype.goForward = function() {
+    this.currentWindow.history.forward();
+};


=== Products/Zelenium/selenium/selenium-commandhandlers.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-commandhandlers.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-commandhandlers.js	Mon May  2 23:48:16 2005
@@ -1,180 +1,177 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- *
- */
-function CommandHandlerFactory() {
-    this.actions = {};
-    this.asserts = {};
-    this.accessors = {};
-
-    var self = this;
-
-    this.registerAction = function(name, action, wait) {
-        var handler = new ActionHandler(action, wait);
-        this.actions[name] = handler;
-    }
-
-    this.registerAccessor = function(name, accessor) {
-        var handler = new AccessorHandler(accessor);
-        this.accessors[name] = handler;
-    }
-
-    this.registerAssert = function(name, assertion, haltOnFailure) {
-        var handler = new AssertHandler(assertion, haltOnFailure);
-        this.asserts[name] = handler;
-    }
-
-    this.getCommandHandler = function(name) {
-        return this.actions[name] || this.accessors[name] || this.asserts[name] || null;
-    }
-
-    this.registerAll = function(commandObject) {
-        registerAllActions(commandObject);
-        registerAllAsserts(commandObject);
-        registerAllAccessors(commandObject);
-    }
-
-    var registerAllActions = function(commandObject) {
-        for (var functionName in commandObject) {
-            var result = /^do([A-Z].+)$/.exec(functionName);
-            if (result != null) {
-                var actionName = toCamelCase(result[1]);
-
-                // Register the action without the wait flag.
-                var action = commandObject[functionName];
-                self.registerAction(actionName, action, false);
-
-                // Register actionName + "AndWait" with the wait flag;
-                var waitActionName = actionName + "AndWait";
-                self.registerAction(waitActionName, action, true);
-            }
-        }
-    }
-
-    var registerAllAsserts = function(commandObject) {
-        for (var functionName in commandObject) {
-            var result = /^assert([A-Z].+)$/.exec(functionName);
-            if (result != null) {
-                var assert = commandObject[functionName];
-
-                // Register the assert with the "assert" prefix, and halt on failure.
-                var assertName = functionName;
-                self.registerAssert(assertName, assert, true);
-
-                // Register the assert with the "verify" prefix, and do not halt on failure.
-                var verifyName = "verify" + result[1];
-                self.registerAssert(verifyName, assert, false);
-            }
-        }
-    }
-
-    var registerAllAccessors = function(commandObject) {
-        for (var functionName in commandObject) {
-            if (/^get[A-Z].+$/.exec(functionName) != null) {
-                var accessor = commandObject[functionName];
-                self.registerAccessor(functionName, accessor);
-            }
-        }
-    }
-
-    function toCamelCase(aString) {
-        return aString.charAt(0).toLowerCase() + aString.substr(1);
-    }
-}
-
-
-// NOTE: The CommandHandler is effectively an abstract base for ActionHandler,
-//      AccessorHandler and AssertHandler.
-function CommandHandler(type, haltOnFailure, executor) {
-    this.type = type;
-    this.haltOnFailure = haltOnFailure;
-    this.executor = executor;
-}
-
-CommandHandler.prototype.execute = function(seleniumApi, command) {
-    return new CommandResult(this.executor.call(seleniumApi, command.target, command.value));
-}
-
-function ActionHandler(action, wait) {
-    this.base = CommandHandler;
-    this.base("action", true, action);
-    if (wait) {
-        this.wait = true;
-    }
-}
-ActionHandler.prototype = new CommandHandler;
-ActionHandler.prototype.execute = function(seleniumApi, command) {
-    if ( seleniumApi.browserbot.hasAlerts() ) {
-       throw new Error("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
-    }
-    if ( seleniumApi.browserbot.hasConfirmations() ) {
-        throw new Error("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
-    }
-    var processState = this.executor.call(seleniumApi, command.target, command.value)
-    // If the handler didn't return a wait flag, check to see if the
-    // handler was registered with the wait flag.
-    if (processState == undefined && this.wait) {
-       processState = SELENIUM_PROCESS_WAIT;
-    }
-    return new CommandResult(processState);
-}
-
-function AccessorHandler(accessor) {
-    this.base = CommandHandler;
-    this.base("accessor", true, accessor);
-}
-AccessorHandler.prototype = new CommandHandler;
-
-AccessorHandler.prototype.execute = function(seleniumApi, command) {
-	var returnValue = this.executor.call(seleniumApi, command.target, command.value);
-    var result = new CommandResult();
-    result.result = returnValue;
-    return result;
-}
-
-function AssertHandler(assertion, haltOnFailure) {
-    this.base = CommandHandler;
-    this.base("assert", haltOnFailure || false, assertion);
-}
-AssertHandler.prototype = new CommandHandler;
-AssertHandler.prototype.execute = function(seleniumApi, command) {
-    var result = new CommandResult();
-    try {
-        var processState = this.executor.call(seleniumApi, command.target, command.value);
-        result.passed = true;
-    } catch (e) {
-        // If this is not a JsUnitException, or we should haltOnFailure, rethrow.
-        if (!e.isJsUnitException) {
-            throw e;
-        }
-        if (this.haltOnFailure) {
-            throw new Error(e.jsUnitMessage);
-        }
-        result.failed = true;
-        result.failureMessage = e.jsUnitMessage;
-    }
-    return result;
-}
-
-function CommandResult(processState) {
-    this.processState = processState;
-    this.result = "OK";
-}
-
-function SeleniumCommand(command, target, value) {
-    this.command = command;
-    this.target = target;
-    this.value = value;
-}
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+*  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.
+*
+*/
+function CommandHandlerFactory() {
+    this.actions = {};
+    this.asserts = {};
+    this.accessors = {};
+
+    var self = this;
+
+    this.registerAction = function(name, action, wait) {
+        var handler = new ActionHandler(action, wait);
+        this.actions[name] = handler;
+    };
+
+    this.registerAccessor = function(name, accessor) {
+        var handler = new AccessorHandler(accessor);
+        this.accessors[name] = handler;
+    };
+
+    this.registerAssert = function(name, assertion, haltOnFailure) {
+        var handler = new AssertHandler(assertion, haltOnFailure);
+        this.asserts[name] = handler;
+    };
+
+    this.getCommandHandler = function(name) {
+        return this.actions[name] || this.accessors[name] || this.asserts[name] || null;
+    };
+
+    this.registerAll = function(commandObject) {
+        registerAllActions(commandObject);
+        registerAllAsserts(commandObject);
+        registerAllAccessors(commandObject);
+    };
+
+    var registerAllActions = function(commandObject) {
+        for (var functionName in commandObject) {
+            var result = /^do([A-Z].+)$/.exec(functionName);
+            if (result != null) {
+                var actionName = toCamelCase(result[1]);
+
+                // Register the action without the wait flag.
+                var action = commandObject[functionName];
+                self.registerAction(actionName, action, false);
+
+                // Register actionName + "AndWait" with the wait flag;
+                var waitActionName = actionName + "AndWait";
+                self.registerAction(waitActionName, action, true);
+            }
+        }
+    };
+
+    var registerAllAsserts = function(commandObject) {
+        for (var functionName in commandObject) {
+            var result = /^assert([A-Z].+)$/.exec(functionName);
+            if (result != null) {
+                var assert = commandObject[functionName];
+
+                // Register the assert with the "assert" prefix, and halt on failure.
+                var assertName = functionName;
+                self.registerAssert(assertName, assert, true);
+
+                // Register the assert with the "verify" prefix, and do not halt on failure.
+                var verifyName = "verify" + result[1];
+                self.registerAssert(verifyName, assert, false);
+            }
+        }
+    };
+
+    var registerAllAccessors = function(commandObject) {
+        for (var functionName in commandObject) {
+            if (/^get[A-Z].+$/.exec(functionName) != null) {
+                var accessor = commandObject[functionName];
+                self.registerAccessor(functionName, accessor);
+            }
+        }
+    };
+
+    function toCamelCase(aString) {
+        return aString.charAt(0).toLowerCase() + aString.substr(1);
+    }
+}
+
+
+// NOTE: The CommandHandler is effectively an abstract base for ActionHandler,
+//      AccessorHandler and AssertHandler.
+function CommandHandler(type, haltOnFailure, executor) {
+    this.type = type;
+    this.haltOnFailure = haltOnFailure;
+    this.executor = executor;
+}
+CommandHandler.prototype.execute = function(seleniumApi, command) {
+    return new CommandResult(this.executor.call(seleniumApi, command.target, command.value));
+};
+
+function ActionHandler(action, wait) {
+    CommandHandler.call(this, "action", true, action);
+    if (wait) {
+        this.wait = true;
+    }
+}
+ActionHandler.prototype = new CommandHandler;
+ActionHandler.prototype.execute = function(seleniumApi, command) {
+    if ( seleniumApi.browserbot.hasAlerts() ) {
+        throw new Error("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
+    }
+    if ( seleniumApi.browserbot.hasConfirmations() ) {
+        throw new Error("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
+    }
+    var processState = this.executor.call(seleniumApi, command.target, command.value);
+    // If the handler didn't return a wait flag, check to see if the
+    // handler was registered with the wait flag.
+    if (processState == undefined && this.wait) {
+        processState = SELENIUM_PROCESS_WAIT;
+    }
+    return new CommandResult(processState);
+};
+
+function AccessorHandler(accessor) {
+    CommandHandler.call(this, "accessor", true, accessor);
+}
+AccessorHandler.prototype = new CommandHandler;
+AccessorHandler.prototype.execute = function(seleniumApi, command) {
+    var returnValue = this.executor.call(seleniumApi, command.target, command.value);
+    var result = new CommandResult();
+    result.result = returnValue;
+    return result;
+};
+
+function AssertHandler(assertion, haltOnFailure) {
+    CommandHandler.call(this, "assert", haltOnFailure || false, assertion);
+}
+AssertHandler.prototype = new CommandHandler;
+AssertHandler.prototype.execute = function(seleniumApi, command) {
+    var result = new CommandResult();
+    try {
+        var processState = this.executor.call(seleniumApi, command.target, command.value);
+        result.passed = true;
+    } catch (e) {
+        // If this is not a AssertionFailedError, or we should haltOnFailure, rethrow.
+        if (!e.isAssertionFailedError) {
+            throw e;
+        }
+        if (this.haltOnFailure) {
+            var error = new Error(e.failureMessage);
+            error.message = e.failureMessage;
+            throw error;
+        }
+        result.failed = true;
+        result.failureMessage = e.failureMessage;
+    }
+    return result;
+};
+
+function CommandResult(processState) {
+    this.processState = processState;
+    this.result = "OK";
+}
+
+function SeleniumCommand(command, target, value) {
+    this.command = command;
+    this.target = target;
+    this.value = value;
+}
\ No newline at end of file


=== Products/Zelenium/selenium/selenium-executionloop.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-executionloop.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-executionloop.js	Mon May  2 23:48:16 2005
@@ -1,129 +1,216 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- */
-
-SELENIUM_PROCESS_WAIT = "wait";
-
-starting_up  = true;
-TEST_FINISHED = true;
-TEST_CONTINUE = false;
-
-function TestLoop(commandFactory) {
-    this.commandFactory = commandFactory;
-
-    var self = this;
-
-    this.start = function() {
-        this.continueCurrentTest();
-    }
-
-    this.continueCurrentTest = function() {
-        var testStatus = this.kickoffNextCommandExecution();
-
-        if (testStatus == TEST_FINISHED) {
-            this.testComplete();
-        }
-    }
-
-    this.kickoffNextCommandExecution = function() {
-
-        var command;
-        if (starting_up == true) {
-            command = this.firstCommand();
-            starting_up = false;
-        } else {
-            command = this.nextCommand();
-        }
-
-        if (!command) return TEST_FINISHED;
-
-        // Make the current row blue
-        this.commandStarted(command);
-
-        var result;
-        try {
-            var handler = this.commandFactory.getCommandHandler(command.command);
-            if(handler == null) {
-                throw new Error("Unknown command");
-            }
-
-            result = handler.execute(selenium, command);
-        } catch (e) {
-            this.commandError(e.message);
-            return TEST_FINISHED;
-        }
-
-        // Record the result so that we can continue the execution using window.setTimeout()
-        this.lastCommandResult = result;
-        if (result.processState == SELENIUM_PROCESS_WAIT) {
-            // Since we're waiting for page to reload, we can't continue command execution
-            // directly, we need use a page load listener.
-
-            // TODO there is a potential race condition by attaching a load listener after
-            // the command has completed execution.
-            selenium.callOnNextPageLoad(
-                function() {eval("testLoop.continueCommandExecutionWithDelay()")}
-            );
-        } else {
-            // Continue processing
-            this.continueCommandExecutionWithDelay();
-        }
-
-        // Test is not finished.
-        return TEST_CONTINUE;
-    }
-
-    /**
-     * Continues the command execution, after waiting for the specified delay.
-     */
-    this.continueCommandExecutionWithDelay = function() {
-        // Get the interval to use for this command execution, using the pauseInterval is
-        // specified. Reset the pause interval, since it's a one-off thing.
-        var interval = this.pauseInterval || this.getCommandInterval();
-        this.pauseInterval = undefined;
-
-        // Continue processing
-        if (interval >= 0) {
-            window.setTimeout("testLoop.finishCommandExecution()", interval);
-        }
-    }
-
-    /**
-     * Finishes the execution of the previous command, and continues the test
-     */
-    this.finishCommandExecution = function() {
-        this.commandComplete(this.lastCommandResult);
-        this.continueCurrentTest();
-    }
-}
-
-/** The default is not to have any interval between commands. */
-TestLoop.prototype.getCommandInterval = function() {
-   return 0;
-}
-
-TestLoop.prototype.firstCommand = noop;
-
-TestLoop.prototype.nextCommand = noop;
-
-TestLoop.prototype.commandStarted = noop;
-
-TestLoop.prototype.commandError = noop;
-
-TestLoop.prototype.commandComplete = noop;
-
-TestLoop.prototype.testComplete = noop;
-
-function noop() {};
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+*  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.
+*/
+
+SELENIUM_PROCESS_WAIT = "wait";
+
+starting_up  = true;
+TEST_FINISHED = true;
+TEST_CONTINUE = false;
+
+function TestLoop(commandFactory, executionContext) {
+    this.commandFactory = commandFactory;
+
+    var self = this;
+
+    this.start = function() {
+        this.continueCurrentTest();
+    };
+
+    this.continueCurrentTest = function() {
+        var testStatus = this.kickoffNextCommandExecution();
+
+        if (testStatus == TEST_FINISHED) {
+            this.testComplete();
+        }
+        };
+
+    this.kickoffNextCommandExecution = function() {
+
+        var command;
+        if (starting_up == true) {
+            command = this.firstCommand();
+            starting_up = false;
+        } else {
+            command = this.nextCommand();
+        }
+
+        if (!command) return TEST_FINISHED;
+
+        // Make the current row blue
+        this.commandStarted(command);
+
+        LOG.debug("Executing: |" + command.command + " | " + command.target + " | " + command.value + " |");
+
+        var result;
+        try {
+            var handler = this.commandFactory.getCommandHandler(command.command);
+            if(handler == null) {
+                throw new Error("Unknown command");
+            }
+
+            result = handler.execute(selenium, command);
+        } catch (e) {
+            LOG.error(e);
+            // TODO: only throw typed errors from commands so that we can perform better error handling
+            // to differentiate between expected command errors and unexpected javascript errors.
+            if (e instanceof TypeError) {
+                // Not a command error.
+                throw e;
+            }
+            this.commandError(e.message);
+            return TEST_FINISHED;
+        }
+
+        // Record the result so that we can continue the execution using window.setTimeout()
+        this.lastCommandResult = result;
+        if (result.processState == SELENIUM_PROCESS_WAIT) {
+
+            executionContext.waitForPageLoad(this,selenium);
+
+        } else {
+            // Continue processing
+            this.continueCommandExecutionWithDelay();
+        }
+
+        // Test is not finished.
+        return TEST_CONTINUE;
+    };
+
+    /**
+    * Continues the command execution, after waiting for the specified delay.
+    */
+    this.continueCommandExecutionWithDelay = function() {
+        // Get the interval to use for this command execution, using the pauseInterval is
+        // specified. Reset the pause interval, since it's a one-off thing.
+        var interval = this.pauseInterval || this.getCommandInterval();
+        this.pauseInterval = undefined;
+
+        // Continue processing
+        if (interval >= 0) {
+            window.setTimeout("testLoop.finishCommandExecution()", interval);
+        }
+    };
+
+    /**
+    * Finishes the execution of the previous command, and continues the test
+    */
+    this.finishCommandExecution = function() {
+        this.commandComplete(this.lastCommandResult);
+        this.continueCurrentTest();
+    };
+}
+
+/** The default is not to have any interval between commands. */
+TestLoop.prototype.getCommandInterval = function() {
+    return 0;
+};
+
+TestLoop.prototype.firstCommand = noop;
+
+TestLoop.prototype.nextCommand = noop;
+
+TestLoop.prototype.commandStarted = noop;
+
+TestLoop.prototype.commandError = noop;
+
+TestLoop.prototype.commandComplete = noop;
+
+TestLoop.prototype.testComplete = noop;
+
+function noop() {
+
+};
+
+/**
+ * A selenium command that tells selenium to expect a failure on the next command
+ * execution. This command temporarily installs a new CommandFactory, that generates
+ * CommandHandlers that expect a failure.
+ */
+Selenium.prototype.assertFailureOnNext = function(message) {
+    if (!message) {
+        throw new Error("Message must be provided");
+    }
+
+    var expectFailureCommandFactory =
+        new ExpectFailureCommandFactory(testLoop.commandFactory, message);
+    expectFailureCommandFactory.baseExecutor = executeCommandAndReturnFailureMessage;
+    testLoop.commandFactory = expectFailureCommandFactory;
+};
+
+/**
+ * A selenium command that tells selenium to expect a failure on the next command
+ * execution. This command temporarily installs a new CommandFactory, that generates
+ * CommandHandlers that expect a failure.
+ */
+Selenium.prototype.assertErrorOnNext = function(message) {
+    if (!message) {
+        throw new Error("Message must be provided");
+    }
+
+    var expectFailureCommandFactory =
+        new ExpectFailureCommandFactory(testLoop.commandFactory, message);
+    expectFailureCommandFactory.baseExecutor = executeCommandAndReturnErrorMessage;
+    testLoop.commandFactory = expectFailureCommandFactory;
+};
+
+function ExpectFailureCommandFactory(originalCommandFactory, expectedErrorMessage) {
+    this.getCommandHandler = function(name) {
+        var baseHandler = originalCommandFactory.getCommandHandler(name);
+        var baseExecutor = this.baseExecutor;
+        var expectFailureCommand = {};
+        expectFailureCommand.execute = function() {
+            var baseFailureMessage = baseExecutor(baseHandler, arguments);
+            var result = new CommandResult();
+            if (!baseFailureMessage) {
+                result.failed = true;
+                result.failureMessage = "Command should have failed.";
+            }
+            else {
+                if (baseFailureMessage != expectedErrorMessage) {
+                    result.failed = true;
+                    result.failureMessage = "Expected failure message '" + expectedErrorMessage
+                                            + "' but was '" + baseFailureMessage + "'";
+                }
+                else {
+                    result.passed = true;
+                    result.result = baseFailureMessage;
+                }
+            }
+            testLoop.commandFactory = originalCommandFactory;
+            return result;
+        };
+        return expectFailureCommand;
+    };
+};
+
+function executeCommandAndReturnFailureMessage(baseHandler, originalArguments) {
+    var baseResult = baseHandler.execute.apply(baseHandler, originalArguments);
+    if (baseResult.passed) {
+        return null;
+    }
+    return baseResult.failureMessage;
+ };
+
+function executeCommandAndReturnErrorMessage(baseHandler, originalArguments) {
+    try {
+        baseHandler.execute.apply(baseHandler, originalArguments);
+        return null;
+    }
+    catch (expected) {
+        return expected.message;
+    }
+ };
+


=== Products/Zelenium/selenium/selenium-fitrunner.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-fitrunner.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-fitrunner.js	Mon May  2 23:48:16 2005
@@ -1,567 +1,656 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- *  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.
- *
- */
- 
-passColor = "#cfffcf";
-failColor = "#ffcfcf";
-workingColor = "#DEE7EC";
-
-// The current row in the list of commands (test script)
-currentCommandRow = 0;
-inputTableRows = null;
-
-// The current row in the list of tests (test suite)
-currentTestRow = 0;
-
-// Whether or not the jsFT should run all tests in the suite
-runAllTests = false;
-
-// Whether or not the current test has any errors;
-testFailed = false;
-suiteFailed = false;
-
-// Test Suite name got from query string
-testSuiteName = "";
-
-// Holds variables that are stored in a script
-storedVars = new Object();
-
-// Holds the handlers for each command.
-commandHandlers = null;
-
-// The number of tests run
-numTestPasses = 0;
-
-// The number of tests that have failed
-numTestFailures = 0;
-
-// The number of commands which have passed
-numCommandPasses = 0;
-
-// The number of commands which have failed
-numCommandFailures = 0;
-
-// The number of commands which have caused errors (element not found)
-numCommandErrors = 0;
-
-// The time that the test was started.
-startTime = null;
-
-// The current time.
-currentTime = null;
-
-// An simple enum for failureType
-ERROR = 0;
-FAILURE = 1;
-
-runInterval = 0;
-
-function setRunInterval() {
-    runInterval = this.value;
-}
-
-function continueCurrentTest() {
-    testLoop.finishCommandExecution()
-}
-
-function getSuiteFrame() {
-    return document.getElementById('testSuiteFrame');
-}
-
-function getTestFrame(){
-    return document.getElementById('testFrame');
-}
-
-function loadAndRunIfAuto() {
-    loadSuiteFrame();
-}
-
-function loadSuiteFrame() {
-    var testAppFrame = document.getElementById('myiframe');
-    browserbot = new BrowserBot(testAppFrame);
-    selenium = new Selenium(browserbot);
-    registerCommandHandlers()
-
-    document.getElementById("modeRun").onclick = setRunInterval;
-    document.getElementById('modeWalk').onclick = setRunInterval;
-    document.getElementById('modeStep').onclick = setRunInterval;
-    document.getElementById('continueTest').onclick = continueCurrentTest;
-
-    testSuiteName = getQueryStringTestName();
-
-    if( testSuiteName != "" ) {
-        addLoadListener(getSuiteFrame(), loadTestFrame);
-        getSuiteFrame().src = testSuiteName;
-    } else {
-        loadTestFrame();
-    }
-
-    //testAppFrame.src = "http://selenium.thoughtworks.com";
-}
-
-function loadTestFrame() {
-    removeLoadListener(getSuiteFrame(), loadTestFrame);
-    suiteTable = getSuiteFrame().contentWindow.document.getElementsByTagName("table")[0];
-
-    // Add an onclick function to each link in the suite table
-    for(rowNum = 1;rowNum < suiteTable.rows.length; rowNum++) {
-        addOnclick(suiteTable, rowNum);
-    }
-
-    if (isAutomatedRun())
-        startTestSuite();
-    else {
-        testLink = suiteTable.rows[currentTestRow+1].cells[0].getElementsByTagName("a")[0];
-        getTestFrame().src = testLink.href;
-    }
-}
-
-// Adds an onclick function to the link in the given row in suite table.
-// This function checks whether the test has already been run and the data is
-// stored. If the data is stored, it sets the test frame to be the stored data.
-// Otherwise, it loads the fresh page.
-function addOnclick(suiteTable, rowNum) {
-    aLink = suiteTable.rows[rowNum].cells[0].getElementsByTagName("a")[0];
-    aLink.onclick = function(eventObj) {
-        srcObj = null;
-
-        // For mozilla-like browsers
-        if(eventObj)
-            srcObj = eventObj.target;
-
-        // For IE-like browsers
-        else if (getSuiteFrame().contentWindow.event)
-            srcObj = getSuiteFrame().contentWindow.event.srcElement;
-
-        // The target row
-        row = srcObj.parentNode.parentNode.rowIndex;
-
-        // If the row has a stored results table, use that
-        if(suiteTable.rows[row].cells[1]) {
-            getTestFrame().contentWindow.document.body.innerHTML = getText(suiteTable.rows[row].cells[1]);
-        }
-        // Otherwise, just open up the fresh page.
-        else {
-            getTestFrame().src = suiteTable.rows[row].cells[0].getElementsByTagName("a")[0].href;
-        }
-
-        return false;
-    };
-}
-
-function getQueryStringTestName() {
-    testName = "";
-    myVars = location.search.substr(1).split('&');
-    for (var i =0;i < myVars.length; i++) {
-        nameVal = myVars[i].split('=')
-        if( nameVal[0] == "test" ) {
-            testName="/" + nameVal[1];
-        }
-    }
-    return testName;
-}
-
-function isAutomatedRun() {
-    myVars = location.search.substr(1).split('&');
-    for (var i =0;i < myVars.length; i++) {
-        nameVal = myVars[i].split('=')
-        if( nameVal[0] == "auto" && nameVal[1].toLowerCase() == "true" )
-            return true;
-    }
-
-    return false;
-}
-
-function resetMetrics() {
-    numTestPasses = 0;
-    numTestFailures = 0;
-    numCommandPasses = 0;
-    numCommandFailures = 0;
-    numCommandErrors = 0;
-    startTime = new Date().getTime();
-}
-
-function runSingleTest() {
-    runAllTests = false;
-    resetMetrics();
-    startTest();
-}
-
-function startTest() {
-    removeLoadListener(getTestFrame(), startTest);
-    getTestFrame().contentWindow.scrollTo(0,0);
-    inputTable = (getTestFrame().contentWindow.document.getElementsByTagName("table"))[0];
-    inputTableRows = inputTable.rows;
-    currentCommandRow = 0;
-    testFailed = false;
-    storedVars = new Object();
-
-    clearRowColours();
-
-    testLoop = initialiseTestLoop();
-    testLoop.start();
-}
-
-function clearRowColours() {
-    for (var i = 0; i <= inputTableRows.length - 1; i++) {
-        inputTableRows[i].bgColor = "white";
-    }
-}
-
-function startTestSuite() {
-    resetMetrics();
-    currentTestRow = 0;
-    runAllTests = true;
-    suiteFailed = false;
-
-    runNextTest();
-}
-
-function runNextTest() {
-    if (!runAllTests)
-        return;
-
-    // Scroll the suite frame down by 25 pixels once we get past the first cell.
-    if(currentTestRow >= 1)
-        getSuiteFrame().contentWindow.scrollBy(0,25);
-
-    suiteTable = (getSuiteFrame().contentWindow.document.getElementsByTagName("table"))[0];
-
-    // Do not change the row color of the first row
-    if(currentTestRow > 0) {
-        // Make the previous row green or red depending if the test passed or failed
-        if(testFailed)
-            setCellColor(suiteTable.rows, currentTestRow, 0, failColor);
-        else
-            setCellColor(suiteTable.rows, currentTestRow, 0, passColor);
-
-        // Set the results from the previous test run
-        setResultsData(suiteTable, currentTestRow);
-    }
-
-    currentTestRow++;
-
-    // If we are done with all of the tests, set the title bar as pass or fail
-    if(currentTestRow >= suiteTable.rows.length) {
-        if(suiteFailed)
-            setCellColor(suiteTable.rows, 0, 0, failColor);
-        else
-            setCellColor(suiteTable.rows, 0, 0, passColor);
-
-        // If this is an automated run (i.e., build script), then submit
-        // the test results by posting to a form
-        if (isAutomatedRun())
-            postTestResults(suiteFailed, suiteTable);
-    }
-
-    else {
-        // Make the current row blue
-        setCellColor(suiteTable.rows, currentTestRow, 0, workingColor);
-
-        testLink = suiteTable.rows[currentTestRow].cells[0].getElementsByTagName("a")[0];
-
-        addLoadListener(getTestFrame(), startTest);
-        getTestFrame().src = testLink.href;
-    }
-}
-
-function setCellColor(tableRows, row, col, colorStr) {
-    tableRows[row].cells[col].bgColor = colorStr;
-}
-
-// Sets the results from a test into a hidden column on the suite table.  So,
-// for each tests, the second column is set to the HTML from the test table.
-function setResultsData(suiteTable, row) {
-    // Create a text node of the test table
-    tableContents = suiteTable.ownerDocument.createTextNode(getTestFrame().contentWindow.document.body.innerHTML);
-
-    new_column = suiteTable.ownerDocument.createElement("td");
-    new_column.appendChild(tableContents);
-
-    // Set the column to be invisible
-    new_column.style.cssText = "display: none;";
-
-    // Add the invisible column
-    suiteTable.rows[row].appendChild(new_column);
-}
-
-// Post the results to /postResults.  The parameters are:
-//      result:         passed/failed depending on whether the suite passed or failed
-//      totalTime:      the total running time in seconds for the suite.
-//
-//      numTestPasses:  the total number of tests which passed.
-//      numTestFailures: the total number of tests which failed.
-//
-//      numCommandPasses: the total number of commands which passed.
-//      numCommandFailures: the total number of commands which failed.
-//      numCommandErrors: the total number of commands which errored.
-//
-//      suite:      the suite table, including the hidden column of test results
-//      testTable.1 to testTable.N: the individual test tables
-function postTestResults(suiteFailed, suiteTable) {
-    form = document.createElement("form");
-    form.id = "resultsForm";
-    form.action = "/postResults"
-    form.method="post";
-    form.enctype="multipart/form-data"
-
-    resultInput = createInputField("result", suiteFailed == true ? "failed" : "passed");
-    form.appendChild(resultInput);
-
-    timeInput = createInputField("totalTime", Math.floor((currentTime - startTime) / 1000));
-    form.appendChild(timeInput);
-
-    testPassesInput = createInputField("numTestPasses", numTestPasses);
-    form.appendChild(testPassesInput);
-
-    testFailuresInput = createInputField("numTestFailures", numTestFailures);
-    form.appendChild(testFailuresInput);
-
-    commandPassesInput = createInputField("numCommandPasses", numCommandPasses);
-    form.appendChild(commandPassesInput);
-
-    commandFailuresInput = createInputField("numCommandFailures", numCommandFailures);
-    form.appendChild(commandFailuresInput);
-
-    commandErrorsInput = createInputField("numCommandErrors", numCommandErrors);
-    form.appendChild(commandErrorsInput);
-
-    suiteInput = createInputField("suite", escape(suiteTable.parentNode.innerHTML));
-    form.appendChild(suiteInput);
-
-    // Create an input for each test table.  The inputs are named testTable.1, testTable.2, etc.
-    for (rowNum = 1;rowNum < suiteTable.rows.length;rowNum++) {
-        // If there is a second column, then add a new input
-        if (suiteTable.rows[rowNum].cells.length > 1) {
-            testInput = createInputField("testTable." + rowNum, escape(getText(suiteTable.rows[rowNum].cells[1])));
-            form.appendChild(testInput);
-        }
-    }
-
-    document.body.appendChild(form);
-
-    form.submit();
-}
-
-function createInputField(name, value) {
-    input = document.createElement("input");
-    input.type = "hidden";
-    input.name = name;
-    input.value = value;
-
-    return input;
-}
-
-function printMetrics() {
-    setText(document.getElementById("commandPasses"), numCommandPasses);
-    setText(document.getElementById("commandFailures"), numCommandFailures);
-    setText(document.getElementById("commandErrors"), numCommandErrors);
-    setText(document.getElementById("testRuns"), numTestPasses);
-    setText(document.getElementById("testFailures"), numTestFailures);
-
-    currentTime = new Date().getTime();
-
-    timeDiff = currentTime - startTime;
-    totalSecs = Math.floor(timeDiff / 1000);
-
-    minutes = Math.floor(totalSecs / 60);
-    seconds = totalSecs % 60;
-
-    setText(document.getElementById("elapsedTime"), pad(minutes)+":"+pad(seconds));
-}
-
-// Puts a leading 0 on num if it is less than 10
-function pad (num) {
-    return (num > 9) ? num : "0" + num;
-}
-
-// Search through str and replace all variable references ${varName} with their
-// value in storedVars.
-function replaceVariables(str) {
-
-     //handle the case of ${userid}.toUpper
-     pattern = /\$\{(\w+)\}\.(.+)/
-
-     var variableIndex = str;
-     var variableFunction='';
-
-     if(pattern.test(str)) {
-         pieces = str.split('.');
-
-         variableIndex = pieces[0];
-         variableFunction = pieces[1];
-    }
-
-
-    regex = /\$\{(\w+)\}/g;
-
-    var variableValue = variableIndex.replace(regex, function(match, word) {
-                                return storedVars[word];
-                              });
-
-    if( variableFunction == '')
-        return variableValue;
-    else
-    {
-        return eval("variableValue."+ eval("variableFunction") + "()" )
-    }
-}
-    // Register all of the built-in command handlers with the CommandHandlerFactory.
-// TODO work out an easy way for people to register handlers without modifying the Selenium sources.
-function registerCommandHandlers() {
-    commandFactory = new CommandHandlerFactory();
-    commandFactory.registerAll(selenium);
-
-    // These actions are overridden for fitrunner, as they still involve some FitRunner smarts,
-    // because of the wait/nowait behaviour modification. We need a generic solution to this.
-    commandFactory.registerAction("click", selenium.doClickWithOptionalWait);
-
-}
-
-function initialiseTestLoop() {
-    testLoop = new TestLoop(commandFactory);
-
-    testLoop.getCommandInterval = function() { return runInterval };
-    testLoop.firstCommand = nextCommand;
-    testLoop.nextCommand = nextCommand;
-    testLoop.commandStarted = commandStarted;
-    testLoop.commandComplete = commandComplete;
-    testLoop.commandError = commandError;
-    testLoop.testComplete = testComplete;
-    return testLoop
-}
-
-function nextCommand() {
-    if (currentCommandRow >= inputTableRows.length - 1) {
-        return null;
-    }
-
-    currentCommandRow++;
-
-    var commandName = getCellText(currentCommandRow, 0);
-    var target = replaceVariables(getCellText(currentCommandRow, 1));
-    var value = replaceVariables(getCellText(currentCommandRow, 2));
-
-    var command = new SeleniumCommand(commandName, target, value);
-    return command;
-}
-
-function commandStarted() {
-    // Make the current row blue
-    inputTableRows[currentCommandRow].bgColor = "#DEE7EC";
-
-    // Scroll the test frame down by 25 pixels once we get past the first 5 cells.
-    if(currentCommandRow >= 5)
-        getTestFrame().contentWindow.scrollBy(0,25);
-
-    printMetrics();
-}
-
-function commandComplete(result) {
-    if (result.failed) {
-        setRowFailed(result.failureMessage, FAILURE);
-    } else if (result.passed) {
-        setRowPassed();
-    } else {
-        setRowWhite();
-    }
-}
-
-function commandError(errorMessage) {
-    setRowFailed(errorMessage, ERROR);
-}
-
-function setRowWhite() {
-    inputTableRows[currentCommandRow].bgColor = "white";
-}
-
-function setRowPassed() {
-    numCommandPasses += 1;
-
-    // Set cell background to green
-    inputTableRows[currentCommandRow].bgColor = passColor;
-}
-
-function setRowFailed(errorMsg, failureType) {
-    if (failureType == ERROR)
-        numCommandErrors += 1;
-    else if (failureType == FAILURE)
-        numCommandFailures += 1;
-
-    // Set cell background to red
-    inputTableRows[currentCommandRow].bgColor = failColor;
-
-    // Set error message
-    inputTableRows[currentCommandRow].cells[2].innerHTML = errorMsg;
-    inputTableRows[currentCommandRow].title = errorMsg;
-    testFailed = true;
-    suiteFailed = true;
-}
-
-function testComplete() {
-     if(testFailed) {
-         inputTableRows[0].bgColor = failColor;
-         numTestFailures += 1;
-     }
-     else {
-         inputTableRows[0].bgColor = passColor;
-         numTestPasses += 1;
-     }
-
-     printMetrics();
-
-    window.setTimeout("runNextTest()", 1);
-}
-
-function getCellText(rowNumber, columnNumber) {
-    return getText(inputTableRows[rowNumber].cells[columnNumber]);
-}
-
-Selenium.prototype.doPause = function(waitTime) {
-    testLoop.pauseInterval = waitTime;
-}
-
-// Store the value of a form input in a variable
-Selenium.prototype.doStoreValue = function(target, varName) {
-    if (!varName) { 
-        // Backward compatibility mode: read the ENTIRE text of the page 
-        // and stores it in a variable with the name of the target
-        value = this.page().bodyText();
-        storedVars[target] = value;
-        return;
-    }
-    var element = this.page().findElement(target);
-    storedVars[varName] = getInputValue(element);
-}
-
-// Store the text of an element in a variable
-Selenium.prototype.doStoreText = function(target, varName) {
-    var element = this.page().findElement(target);
-    storedVars[varName] = getText(element);
-}
-
-Selenium.prototype.doClickWithOptionalWait = function(target, wait) {
-   
-    this.doClick(target);
-    
-    if(wait != "nowait") {
-        return SELENIUM_PROCESS_WAIT;
-    }
-
-}
-
-
-
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+*  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.
+*
+*/
+
+passColor = "#cfffcf";
+failColor = "#ffcfcf";
+workingColor = "#DEE7EC";
+
+// The current row in the list of commands (test script)
+currentCommandRow = 0;
+inputTableRows = null;
+
+// The current row in the list of tests (test suite)
+currentTestRow = 0;
+
+// Whether or not the jsFT should run all tests in the suite
+runAllTests = false;
+
+// Whether or not the current test has any errors;
+testFailed = false;
+suiteFailed = false;
+
+// Holds variables that are stored in a script
+storedVars = new Object();
+
+// Holds the handlers for each command.
+commandHandlers = null;
+
+// The number of tests run
+numTestPasses = 0;
+
+// The number of tests that have failed
+numTestFailures = 0;
+
+// The number of commands which have passed
+numCommandPasses = 0;
+
+// The number of commands which have failed
+numCommandFailures = 0;
+
+// The number of commands which have caused errors (element not found)
+numCommandErrors = 0;
+
+// The time that the test was started.
+startTime = null;
+
+// The current time.
+currentTime = null;
+
+// An simple enum for failureType
+ERROR = 0;
+FAILURE = 1;
+
+runInterval = 0;
+
+function setRunInterval() {
+    runInterval = this.value;
+}
+
+function continueCurrentTest() {
+    testLoop.finishCommandExecution();
+}
+
+function getApplicationFrame() {
+    return document.getElementById('myiframe');
+}
+
+function getSuiteFrame() {
+    return document.getElementById('testSuiteFrame');
+}
+
+function getTestFrame(){
+    return document.getElementById('testFrame');
+}
+
+function loadAndRunIfAuto() {
+    loadSuiteFrame();
+}
+
+function getExecutionContext() {
+    if (isNewWindow()) {
+        return getWindowExecutionContext();
+    }
+    else if (isSafari || isKonqueror) {
+        return new KonquerorIFrameExecutionContext();
+    }
+    else {
+        return new IFrameExecutionContext();
+    }
+}
+
+function start() {
+    loadSuiteFrame(getExecutionContext());
+}
+
+function loadSuiteFrame(executionContext) {
+
+    var testAppFrame = executionContext.loadFrame();
+    browserbot = createBrowserBot(testAppFrame,executionContext);
+    selenium = new Selenium(browserbot);
+    registerCommandHandlers();
+
+    //set the runInterval if there is a queryParameter for it
+    var tempRunInterval = getQueryParameter("runInterval");
+    if (tempRunInterval) {
+        runInterval = tempRunInterval;
+    }
+
+    document.getElementById("modeRun").onclick = setRunInterval;
+    document.getElementById('modeWalk').onclick = setRunInterval;
+    document.getElementById('modeStep').onclick = setRunInterval;
+    document.getElementById('continueTest').onclick = continueCurrentTest;
+
+    var testSuiteName = getQueryParameter("test");
+
+    if (testSuiteName) {
+        addLoadListener(getSuiteFrame(), onloadTestSuite);
+        getSuiteFrame().src = testSuiteName;
+    } else {
+        onloadTestSuite();
+    }
+}
+
+function startSingleTest() {
+    removeLoadListener(getApplicationFrame(), startSingleTest);
+    var singleTestName = getQueryParameter("singletest");
+    addLoadListener(getTestFrame(), startTest);
+    getTestFrame().src = singleTestName;
+}
+
+function getIframeDocument(iframe)
+{
+    if (iframe.contentDocument) {
+        return iframe.contentDocument;
+    }
+    else {
+        return iframe.contentWindow.document;
+    }
+}
+
+function onloadTestSuite() {
+    removeLoadListener(getSuiteFrame(), onloadTestSuite);
+    suiteTable = getIframeDocument(getSuiteFrame()).getElementsByTagName("table")[0];
+
+    // Add an onclick function to each link in the suite table
+    for(rowNum = 1;rowNum < suiteTable.rows.length; rowNum++) {
+        addOnclick(suiteTable, rowNum);
+    }
+
+
+    if (isAutomatedRun()) {
+        startTestSuite();
+    } else if (getQueryParameter("autoURL")) {
+
+        addLoadListener(getApplicationFrame(), startSingleTest);
+
+        getApplicationFrame().src = getQueryParameter("autoURL");
+
+    } else {
+        testLink = suiteTable.rows[currentTestRow+1].cells[0].getElementsByTagName("a")[0];
+        getTestFrame().src = testLink.href;
+    }
+}
+
+// Adds an onclick function to the link in the given row in suite table.
+// This function checks whether the test has already been run and the data is
+// stored. If the data is stored, it sets the test frame to be the stored data.
+// Otherwise, it loads the fresh page.
+function addOnclick(suiteTable, rowNum) {
+    aLink = suiteTable.rows[rowNum].cells[0].getElementsByTagName("a")[0];
+    aLink.onclick = function(eventObj) {
+        srcObj = null;
+
+        // For mozilla-like browsers
+        if(eventObj)
+                srcObj = eventObj.target;
+
+        // For IE-like browsers
+        else if (getSuiteFrame().contentWindow.event)
+                srcObj = getSuiteFrame().contentWindow.event.srcElement;
+
+        // The target row (the event source is not consistently reported by browsers)
+        row = srcObj.parentNode.parentNode.rowIndex || srcObj.parentNode.parentNode.parentNode.rowIndex;
+
+        // If the row has a stored results table, use that
+        if(suiteTable.rows[row].cells[1]) {
+            var bodyElement = getIframeDocument(getTestFrame()).body;
+
+            // Create a div element to hold the results table.
+            var tableNode = getIframeDocument(getTestFrame()).createElement("div");
+            var resultsCell = suiteTable.rows[row].cells[1];
+            tableNode.innerHTML = resultsCell.innerHTML;
+
+            // Append this text node, and remove all the preceding nodes.
+            bodyElement.appendChild(tableNode);
+            while (bodyElement.firstChild != bodyElement.lastChild) {
+                bodyElement.removeChild(bodyElement.firstChild);
+            }
+        }
+        // Otherwise, just open up the fresh page.
+        else {
+            getTestFrame().src = suiteTable.rows[row].cells[0].getElementsByTagName("a")[0].href;
+        }
+
+        return false;
+    };
+}
+
+function isQueryParameterTrue(name) {
+    parameterValue = getQueryParameter(name);
+    return (parameterValue != null && parameterValue.toLowerCase() == "true");
+}
+
+function getQueryParameter(searchKey) {
+    var clauses = location.search.substr(1).split('&');
+    for (var i = 0; i < clauses.length; i++) {
+        var keyValuePair = clauses[i].split('=',2);
+        var key = unescape(keyValuePair[0]);
+        if (key == searchKey) {
+            return unescape(keyValuePair[1]);
+        }
+    }
+    return null;
+}
+
+function isNewWindow() {
+    return isQueryParameterTrue("newWindow");
+}
+
+function isAutomatedRun() {
+    return isQueryParameterTrue("auto");
+}
+
+function resetMetrics() {
+    numTestPasses = 0;
+    numTestFailures = 0;
+    numCommandPasses = 0;
+    numCommandFailures = 0;
+    numCommandErrors = 0;
+    startTime = new Date().getTime();
+}
+
+function runSingleTest() {
+    runAllTests = false;
+    resetMetrics();
+    startTest();
+}
+
+function startTest() {
+    removeLoadListener(getTestFrame(), startTest);
+
+    // Scroll to the top of the test frame
+    if (getTestFrame().contentWindow) {
+        getTestFrame().contentWindow.scrollTo(0,0);
+    }
+    else {
+        frames['testFrame'].scrollTo(0,0);
+    }
+
+    inputTable = getIframeDocument(getTestFrame()).getElementsByTagName("table")[0];
+    inputTableRows = inputTable.rows;
+    currentCommandRow = 0;
+    testFailed = false;
+    storedVars = new Object();
+
+    clearRowColours();
+
+    testLoop = initialiseTestLoop();
+    testLoop.start();
+}
+
+function clearRowColours() {
+    for (var i = 0; i <= inputTableRows.length - 1; i++) {
+        inputTableRows[i].bgColor = "white";
+    }
+}
+
+function startTestSuite() {
+    resetMetrics();
+    currentTestRow = 0;
+    runAllTests = true;
+    suiteFailed = false;
+
+    runNextTest();
+}
+
+function runNextTest() {
+    if (!runAllTests)
+            return;
+
+    suiteTable = getIframeDocument(getSuiteFrame()).getElementsByTagName("table")[0];
+
+    // Do not change the row color of the first row
+    if(currentTestRow > 0) {
+        // Make the previous row green or red depending if the test passed or failed
+        if(testFailed)
+                setCellColor(suiteTable.rows, currentTestRow, 0, failColor);
+        else
+                setCellColor(suiteTable.rows, currentTestRow, 0, passColor);
+
+        // Set the results from the previous test run
+        setResultsData(suiteTable, currentTestRow);
+    }
+
+    currentTestRow++;
+
+    // If we are done with all of the tests, set the title bar as pass or fail
+    if(currentTestRow >= suiteTable.rows.length) {
+        if(suiteFailed)
+                setCellColor(suiteTable.rows, 0, 0, failColor);
+        else
+                setCellColor(suiteTable.rows, 0, 0, passColor);
+
+        // If this is an automated run (i.e., build script), then submit
+        // the test results by posting to a form
+        if (isAutomatedRun())
+                postTestResults(suiteFailed, suiteTable);
+    }
+
+    else {
+        // Make the current row blue
+        setCellColor(suiteTable.rows, currentTestRow, 0, workingColor);
+
+        testLink = suiteTable.rows[currentTestRow].cells[0].getElementsByTagName("a")[0];
+        testLink.focus();
+
+        addLoadListener(getTestFrame(), startTest);
+        getExecutionContext().open(testLink.href, getTestFrame());
+    }
+}
+
+function setCellColor(tableRows, row, col, colorStr) {
+    tableRows[row].cells[col].bgColor = colorStr;
+}
+
+// Sets the results from a test into a hidden column on the suite table.  So,
+// for each tests, the second column is set to the HTML from the test table.
+function setResultsData(suiteTable, row) {
+    // Create a text node of the test table
+    var resultTable = getIframeDocument(getTestFrame()).body.innerHTML;
+    if (!resultTable) return;
+
+    var tableNode = suiteTable.ownerDocument.createElement("div");
+    tableNode.innerHTML = resultTable;
+
+    var new_column = suiteTable.ownerDocument.createElement("td");
+    new_column.appendChild(tableNode);
+
+    // Set the column to be invisible
+    new_column.style.cssText = "display: none;";
+
+    // Add the invisible column
+    suiteTable.rows[row].appendChild(new_column);
+}
+
+// Post the results to a servlet, CGI-script, etc.  The URL of the
+// results-handler defaults to "/postResults", but an alternative location
+// can be specified by providing a "resultsUrl" query parameter.
+//
+// Parameters passed to the results-handler are:
+//      result:         passed/failed depending on whether the suite passed or failed
+//      totalTime:      the total running time in seconds for the suite.
+//
+//      numTestPasses:  the total number of tests which passed.
+//      numTestFailures: the total number of tests which failed.
+//
+//      numCommandPasses: the total number of commands which passed.
+//      numCommandFailures: the total number of commands which failed.
+//      numCommandErrors: the total number of commands which errored.
+//
+//      suite:      the suite table, including the hidden column of test results
+//      testTable.1 to testTable.N: the individual test tables
+//
+function postTestResults(suiteFailed, suiteTable) {
+
+    form = document.createElement("form");
+    document.body.appendChild(form);
+
+    form.id = "resultsForm";
+    form.method="post";
+    form.target="myiframe";
+
+    var resultsUrl = getQueryParameter("resultsUrl");
+    if (!resultsUrl) {
+        resultsUrl = "./postResults";
+    }
+
+    var actionAndParameters = resultsUrl.split('?',2);
+    form.action = actionAndParameters[0];
+    var resultsUrlQueryString = actionAndParameters[1];
+
+    form.createHiddenField = function(name, value) {
+        input = document.createElement("input");
+        input.type = "hidden";
+        input.name = name;
+        input.value = value;
+        this.appendChild(input);
+    };
+
+    if (resultsUrlQueryString) {
+        var clauses = resultsUrlQueryString.split('&');
+        for (var i = 0; i < clauses.length; i++) {
+            var keyValuePair = clauses[i].split('=',2);
+            var key = unescape(keyValuePair[0]);
+            var value = unescape(keyValuePair[1]);
+            form.createHiddenField(key, value);
+        }
+    }
+
+    form.createHiddenField("result", suiteFailed == true ? "failed" : "passed");
+
+    form.createHiddenField("totalTime", Math.floor((currentTime - startTime) / 1000));
+    form.createHiddenField("numTestPasses", numTestPasses);
+    form.createHiddenField("numTestFailures", numTestFailures);
+    form.createHiddenField("numCommandPasses", numCommandPasses);
+    form.createHiddenField("numCommandFailures", numCommandFailures);
+    form.createHiddenField("numCommandErrors", numCommandErrors);
+
+    // Create an input for each test table.  The inputs are named
+    // testTable.1, testTable.2, etc.
+    for (rowNum = 1; rowNum < suiteTable.rows.length;rowNum++) {
+        // If there is a second column, then add a new input
+        if (suiteTable.rows[rowNum].cells.length > 1) {
+            var resultCell = suiteTable.rows[rowNum].cells[1];
+            form.createHiddenField("testTable." + rowNum, getText(resultCell));
+            // remove the resultCell, so it's not included in the suite HTML
+            resultCell.parentNode.removeChild(resultCell); 
+        }
+    }
+
+    // Add HTML for the suite itself
+    form.createHiddenField("suite", suiteTable.parentNode.innerHTML);
+
+    form.submit();
+    document.body.removeChild(form);
+
+}
+
+function printMetrics() {
+    setText(document.getElementById("commandPasses"), numCommandPasses);
+    setText(document.getElementById("commandFailures"), numCommandFailures);
+    setText(document.getElementById("commandErrors"), numCommandErrors);
+    setText(document.getElementById("testRuns"), numTestPasses + numTestFailures);
+    setText(document.getElementById("testFailures"), numTestFailures);
+
+    currentTime = new Date().getTime();
+
+    timeDiff = currentTime - startTime;
+    totalSecs = Math.floor(timeDiff / 1000);
+
+    minutes = Math.floor(totalSecs / 60);
+    seconds = totalSecs % 60;
+
+    setText(document.getElementById("elapsedTime"), pad(minutes)+":"+pad(seconds));
+}
+
+// Puts a leading 0 on num if it is less than 10
+function pad (num) {
+    return (num > 9) ? num : "0" + num;
+}
+
+/*
+ * Search through str and replace all variable references ${varName} with their
+ * value in storedVars.
+ */
+function replaceVariables(str) {
+    // We can't use a String.replace(regexp, replacementFunction) since this doesn't
+    // work in safari. So replace each match 1 at a time.
+    var stringResult = str;
+    var match;
+    while (match = stringResult.match(/\$\{(\w+)\}/)) {
+        var variable = match[0];
+        var name = match[1];
+        var replacement = storedVars[name];
+        stringResult = stringResult.replace(variable, replacement);
+    }
+    return stringResult;
+}
+
+/*
+ * Register all of the built-in command handlers with the CommandHandlerFactory.
+ * TODO work out an easy way for people to register handlers without modifying the Selenium sources.
+ */
+function registerCommandHandlers() {
+    commandFactory = new CommandHandlerFactory();
+    commandFactory.registerAll(selenium);
+
+    // These actions are overridden for fitrunner, as they still involve some FitRunner smarts,
+    // because of the wait/nowait behaviour modification. We need a generic solution to this.
+    commandFactory.registerAction("click", selenium.doClickWithOptionalWait);
+
+}
+
+function initialiseTestLoop() {
+    testLoop = new TestLoop(commandFactory, getExecutionContext());
+
+    testLoop.getCommandInterval = function() { return runInterval; };
+    testLoop.firstCommand = nextCommand;
+    testLoop.nextCommand = nextCommand;
+    testLoop.commandStarted = commandStarted;
+    testLoop.commandComplete = commandComplete;
+    testLoop.commandError = commandError;
+    testLoop.testComplete = testComplete;
+    return testLoop;
+}
+
+function nextCommand() {
+    if (currentCommandRow >= inputTableRows.length - 1) {
+        return null;
+    }
+
+    currentCommandRow++;
+
+    var commandName = getCellText(currentCommandRow, 0);
+    var target = replaceVariables(getCellText(currentCommandRow, 1));
+    var value = replaceVariables(getCellText(currentCommandRow, 2));
+
+
+    var command = new SeleniumCommand(commandName, target, removeNbsp(value));
+    return command;
+}
+
+function removeNbsp(value)
+{
+    return value.replace(/\240/g, "");
+}
+
+function focusOnElement(element) {
+    if (element.focus) {
+        element.focus();
+        return;
+    }
+    var anchor = element.ownerDocument.createElement("a");
+    anchor.innerHTML = "!CURSOR!";
+    element.appendChild(anchor, element);
+    anchor.focus();
+    element.removeChild(anchor);
+}
+
+function commandStarted() {
+    inputTableRows[currentCommandRow].bgColor = workingColor;
+    focusOnElement(inputTableRows[currentCommandRow].cells[0]);
+    printMetrics();
+}
+
+function commandComplete(result) {
+    if (result.failed) {
+        setRowFailed(result.failureMessage, FAILURE);
+    } else if (result.passed) {
+        setRowPassed();
+    } else {
+        setRowWhite();
+    }
+}
+
+function commandError(errorMessage) {
+    setRowFailed(errorMessage, ERROR);
+}
+
+function setRowWhite() {
+    inputTableRows[currentCommandRow].bgColor = "white";
+}
+
+function setRowPassed() {
+    numCommandPasses += 1;
+
+    // Set cell background to green
+    inputTableRows[currentCommandRow].bgColor = passColor;
+}
+
+function setRowFailed(errorMsg, failureType) {
+    if (failureType == ERROR)
+            numCommandErrors += 1;
+    else if (failureType == FAILURE)
+            numCommandFailures += 1;
+
+    // Set cell background to red
+    inputTableRows[currentCommandRow].bgColor = failColor;
+
+    // Set error message
+    inputTableRows[currentCommandRow].cells[2].innerHTML = errorMsg;
+    inputTableRows[currentCommandRow].title = errorMsg;
+    testFailed = true;
+    suiteFailed = true;
+}
+
+function testComplete() {
+    if(testFailed) {
+        inputTableRows[0].bgColor = failColor;
+        numTestFailures += 1;
+    }
+    else {
+        inputTableRows[0].bgColor = passColor;
+        numTestPasses += 1;
+    }
+
+    printMetrics();
+
+    window.setTimeout("runNextTest()", 1);
+}
+
+function getCellText(rowNumber, columnNumber) {
+    return getText(inputTableRows[rowNumber].cells[columnNumber]);
+}
+
+Selenium.prototype.doPause = function(waitTime) {
+    selenium.callOnNextPageLoad(null);
+    testLoop.pauseInterval = waitTime;
+};
+
+// Store the value of a form input in a variable
+Selenium.prototype.doStoreValue = function(target, varName) {
+    if (!varName) { 
+        // Backward compatibility mode: read the ENTIRE text of the page 
+        // and stores it in a variable with the name of the target
+        value = this.page().bodyText();
+        storedVars[target] = value;
+        return;
+    }
+    var element = this.page().findElement(target);
+    storedVars[varName] = getInputValue(element);
+};
+
+// Store the text of an element in a variable
+Selenium.prototype.doStoreText = function(target, varName) {
+    var element = this.page().findElement(target);
+    storedVars[varName] = getText(element);
+};
+
+Selenium.prototype.doSetVariable = function(varName, variableExpression) {
+    var value = eval(variableExpression);
+    storedVars[varName] = value;
+};
+
+Selenium.prototype.doClickWithOptionalWait = function(target, wait) {
+
+    this.doClick(target);
+
+    if(wait != "nowait") {
+        return SELENIUM_PROCESS_WAIT;
+    }
+
+};


=== Products/Zelenium/selenium/selenium.css 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium.css:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium.css	Mon May  2 23:48:16 2005
@@ -1,92 +1,187 @@
 /*
- * Copyright 2004 ThoughtWorks, Inc
- *
+ * Copyright 2005 ThoughtWorks, Inc
+ * 
  *  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.
- *
  */
-#seleniumControlPanel {
-    position: absolute;
-    top: 0px;
-    left: 230px;
-    height: 20%;
-    width: 77%;
-    background-color: white;
+
+/*---( Layout )---*/
+
+body {
+    margin: 0;
+    padding: 0;
+    overflow: auto;
+}
+
+td {
+    position: static;
+}
+
+tr {
+    vertical-align: top;
+}
+
+.layout {
+    width: 100%;
+    height: 100%;
+    border-collapse: collapse;
+}
+
+.layout td {
+    margin: 0;
+    padding: 0;
+    border: 0;
+}
+
+iframe {
+    width: 100%;
+    height: 100%;
+    border: 0;
+    background: white;
+    overflow: auto;
+}
+
+/*---( Style )---*/
+
+body, html {
+    font-family: Verdana, Arial, sans-serif;
+}
+
+.selenium th, .selenium td {
+    border: 1px solid #999;
+}
+
+.header {
+    background: #ccc;
+    padding: 0;
+    font-size: 90%;
+}
+
+#controlPanel {
+    padding: 5px;
+    background: #eee;
     overflow: auto;
-    padding: 0px;
-    margin: 5px;
-    background: url(selenium-logo.jpg) no-repeat right;
-}
-#launchPanel {
-    position: absolute;
-    top: 10px;
-    left: 2%;
-    width: 10%;
-}
-#launchPanel button {
-    color: white;
-    background-color: green;
+}
+
+#controlPanel table {
+    font-size: 75%;
+}
+
+#controlPanel th, #controlPanel td {
+    border: 0;
+}
+
+#controls {
+    color: inherit;
+    width: 100%;
+}
+
+#controls td {
+    margin: 1px;
+    padding: 1px;
+    text-align: center;
+}
+
+h1 {
+    margin: 0.2ex;
+    font-size: 130%;
     font-weight: bold;
-    font-size: 12px;
-    display: block;
+}
+
+h2 {
+    margin: 0.2ex;
+    font-size: 80%;
+    font-weight: normal;
+}
+
+.selenium a {
+    color: black;
+    text-decoration: none;
+}
+
+.selenium a:hover {
+    text-decoration: underline;
+}
+
+button, label {
     cursor: pointer;
-    margin-top:7pt;
 }
-#runSpeedPanel {
-    position: absolute;
-    top: 10px;
-    left: 19%;
-    width: 15%;
-}
-#runSpeedPanel label {
-    display: block;
-}
-
-table#resultsPanel {
-    position: absolute;
-    top: 10px;
-    left: 35%;
-    background-color: white;
-    border: solid 1px;
-    overflow: hidden;
-    height: 20%;
-}
-table#resultsPanel td {
-    padding:0px;
-    margin:0px;
+
+#stats {
+    border-top: 1px solid #999;
+    border-bottom: 1px solid #999;
+    margin-top: 10px;
 }
-table#resultsPanel th {
+
+#stats th, #stats td {
     text-align: left;
+    padding-left: 2px;
+}
+
+#stats th {
+    text-decoration: underline;
+}
+
+#stats td.count {
     font-weight: bold;
-    padding:0px;
-    margin:0px;
+    text-align: right;
 }
-td#testRuns {
+
+#testRuns {
     color: green;
-    font-weight: bold;
 }
-td#testFailures {
+
+#testFailures {
     color: red;
-    font-weight: bold;
 }
-td#commandPasses {
+
+#commandPasses {
     color: green;
-    font-weight: bold;
 }
-td#commandFailures {
-    color: orange;
-    font-weight: bold;
-}
-td#commandErrors {
+
+#commandFailures {
     color: red;
-    font-weight: bold;
 }
+
+#commandErrors {
+    color: #f90;
+}
+
+.splash {
+    border: 1px solid black;
+    padding: 20px;
+    background: #ccc;
+}
+
+/*---( Logging Console )---*/
+#logging-console {
+   background: #FFF;
+   padding: 5px;
+   border: 1px solid #888;
+   font-size: 10px;
+}
+
+#logging-console h1 {
+   font-weight: bold;
+}
+
+#logging-console ul {
+   list-style-type: none;
+   margin: 0px;
+   padding: 0px;
+   clear: both;
+}
+
+#logging-console ul li.error {
+	font-weight: bold;
+	color: red;
+}
\ No newline at end of file



More information about the Zope-CVS mailing list