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 <[email protected]>
Newsgroups gmane.comp.web.zope.public-cvs
Message-ID <[email protected]>
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

_______________________________________________
Zope-CVS maillist  -  [email protected]
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.