[jboss-svn-commits] JBoss Portal SVN: r5194 - in trunk/theme/src/bin/portal-ajax-war: . js js/connection js/dom js/dragdrop js/event js/logger js/logger/assets js/portal js/yahoo

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Sep 13 16:09:58 EDT 2006


Author: roy.russo at jboss.com
Date: 2006-09-13 16:09:38 -0400 (Wed, 13 Sep 2006)
New Revision: 5194

Added:
   trunk/theme/src/bin/portal-ajax-war/js/
   trunk/theme/src/bin/portal-ajax-war/js/connection/
   trunk/theme/src/bin/portal-ajax-war/js/connection/README
   trunk/theme/src/bin/portal-ajax-war/js/connection/connection-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/connection/connection-min.js
   trunk/theme/src/bin/portal-ajax-war/js/connection/connection.js
   trunk/theme/src/bin/portal-ajax-war/js/dom/
   trunk/theme/src/bin/portal-ajax-war/js/dom/README
   trunk/theme/src/bin/portal-ajax-war/js/dom/dom-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/dom/dom-min.js
   trunk/theme/src/bin/portal-ajax-war/js/dom/dom.js
   trunk/theme/src/bin/portal-ajax-war/js/dragdrop/
   trunk/theme/src/bin/portal-ajax-war/js/dragdrop/README
   trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-min.js
   trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop.js
   trunk/theme/src/bin/portal-ajax-war/js/event/
   trunk/theme/src/bin/portal-ajax-war/js/event/README
   trunk/theme/src/bin/portal-ajax-war/js/event/event-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/event/event-min.js
   trunk/theme/src/bin/portal-ajax-war/js/event/event.js
   trunk/theme/src/bin/portal-ajax-war/js/logger/
   trunk/theme/src/bin/portal-ajax-war/js/logger/README
   trunk/theme/src/bin/portal-ajax-war/js/logger/assets/
   trunk/theme/src/bin/portal-ajax-war/js/logger/assets/logger.css
   trunk/theme/src/bin/portal-ajax-war/js/logger/logger-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/logger/logger-min.js
   trunk/theme/src/bin/portal-ajax-war/js/logger/logger.js
   trunk/theme/src/bin/portal-ajax-war/js/portal/
   trunk/theme/src/bin/portal-ajax-war/js/portal/PortalDD.js
   trunk/theme/src/bin/portal-ajax-war/js/yahoo/
   trunk/theme/src/bin/portal-ajax-war/js/yahoo/README
   trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-debug.js
   trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-min.js
   trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo.js
Log:
JBPORTAL-1008 - Adding javascript libraries

Added: trunk/theme/src/bin/portal-ajax-war/js/connection/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/connection/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/connection/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,80 @@
+Connection Manager Release Notes
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transactions can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release

Added: trunk/theme/src/bin/portal-ajax-war/js/connection/connection-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/connection/connection-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/connection/connection-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,803 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.1
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+			'MSXML2.XMLHTTP.3.0',
+			'MSXML2.XMLHTTP',
+			'Microsoft.XMLHTTP'
+			],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Property that that determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:true,
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type string
+  */
+    _poll:[],
+
+ /**
+  * Queue of timeout references for each transaction with a defined timeout value.
+  * @private
+  * @type string
+  */
+    _timeOut:[],
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		YAHOO.log('Default POST header set to  ' + b, 'info', 'Connection');
+		this._default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+				this._polling_interval = i;
+				YAHOO.log('Default polling interval set to  ' + i, 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction  ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction  ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					postData =  this._sFormData;
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._default_post_header)){
+				this.initHeader('Content-Type','application/x-www-form-urlencoded');
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			//Verify whether the transaction has any user-defined HTTP headers
+			//and set them.
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			postData?o.conn.send(postData):o.conn.send(null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+        var timeOut = callback.timeout;
+        var oConn = this;
+
+        try
+        {
+            if(timeOut !== undefined){
+            	this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true) }, timeOut);
+            }
+            this._poll[o.tId] = window.setInterval(
+                function(){
+					if(o.conn && o.conn.readyState == 4){
+						window.clearInterval(oConn._poll[o.tId]);
+						oConn._poll.splice(o.tId);
+						if(timeOut){
+							oConn._timeOut.splice(o.tId);
+						}
+
+						oConn.handleTransactionResponse(o, callback);
+                    }
+                }
+            ,this._polling_interval);
+        }
+        catch(e)
+        {
+            window.clearInterval(oConn._poll[o.tId]);
+            oConn._poll.splice(o.tId);
+			if(timeOut){
+				oConn._timeOut.splice(o.tId);
+			}
+
+            oConn.handleTransactionResponse(o, callback);
+        }
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process.  Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			responseObject = this.createResponseObject(o, callback.argument);
+			if(callback.success){
+				if(!callback.scope){
+					callback.success(responseObject);
+					YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+				}
+				else{
+					// If a scope property is defined, the callback will be fired from
+					// the context of the object.
+					callback.success.apply(callback.scope, [responseObject]);
+					YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+				}
+			}
+		}
+		else{
+			switch(httpStatus){
+				// The following case labels are wininet.dll error codes that may be encountered.
+				// Server timeout
+				case 12002:
+				// 12029 to 12031 correspond to dropped connections.
+				case 12029:
+				case 12030:
+				case 12031:
+				// Connection closed by server.
+				case 12152:
+				// See above comments for variable status.
+				case 13030:
+					responseObject = this.createExceptionObject(o.tId, callback.argument, isAbort);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+							YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+							YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+						}
+					}
+					break;
+				default:
+					responseObject = this.createResponseObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+							YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+							YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+						}
+					}
+			}
+		}
+
+		this.releaseObject(o);
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.propertyIsEnumerable){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			(typeof secureUri == 'string')?this.createFrame(secureUri):this.createFrame();
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oDisabled = oForm.elements[i].disabled;
+
+			// If the name attribute is not populated, the form field's
+			// value will not be submitted.
+			oElement = oForm.elements[i];
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName !== undefined)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].value || oElement.options[j].text) + '&';
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+
+		YAHOO.log('Form initialized for transaction. POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as DOM
+		// properties.  A different iframe creation pattern is required for IE.
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME name="ioFrame" id="ioFrame">');
+			if(secureUri){
+				// IE will throw a security exception in an SSL environment if the
+				// iframe source isn't set to a valid resource.
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = 'ioFrame';
+			io.name = 'ioFrame';
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = 'ioFrame';
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var oResponse =
+			{
+				tId: id,
+				responseText: document.getElementById("ioFrame").contentWindow.document.body.innerHTML,
+				argument: callback.argument
+			}
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(oResponse);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [oResponse]);
+					YAHOO.log('Upload callback with object scope.', 'info', 'Connection');
+				}
+			}
+
+			YAHOO.util.Event.removeListener("ioFrame", "load", uploadCallback);
+			window.ioFrame.location.replace('#');
+			setTimeout("document.body.removeChild(document.getElementById('ioFrame'))",100);
+		};
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		YAHOO.util.Event.addListener("ioFrame", "load", uploadCallback);
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			window.clearInterval(this._poll[o.tId]);
+			this._poll.splice(o.tId);
+			if(isTimeout){
+				this._timeOut.splice(o.tId);
+			}
+			o.conn.abort();
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort failed.', 'warn', 'Connection');
+
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+
+		//dereference the connection object.
+		o = null;
+	}
+};

Added: trunk/theme/src/bin/portal-ajax-war/js/connection/connection-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/connection/connection-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/connection/connection-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.1
+*/
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_default_post_header:true,_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:[],_timeOut:[],_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=this._sFormData;}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._default_post_header)){this.initHeader('Content-Type','application/x-www-form-urlencoded');if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);postData?o.conn.send(postData):o.conn.send(null);return o;}},handleReadyState:function(o,callback)
+{var timeOut=callback.timeout;var oConn=this;try
+{if(timeOut!==undefined){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true)},timeOut);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);oConn._poll.splice(o.tId);if(timeOut){oConn._timeOut.splice(o.tId);}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);}
+catch(e)
+{window.clearInterval(oConn._poll[o.tId]);oConn._poll.splice(o.tId);if(timeOut){oConn._timeOut.splice(o.tId);}
+oConn.handleTransactionResponse(o,callback);}},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+else{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,isAbort);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+this.releaseObject(o);},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.propertyIsEnumerable){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){(typeof secureUri=='string')?this.createFrame(secureUri):this.createFrame();this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oDisabled=oForm.elements[i].disabled;oElement=oForm.elements[i];oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].value||oElement.options[j].text)+'&';}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){if(window.ActiveXObject){var io=document.createElement('<IFRAME name="ioFrame" id="ioFrame">');if(secureUri){io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id='ioFrame';io.name='ioFrame';}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target='ioFrame';this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var oResponse={tId:id,responseText:document.getElementById("ioFrame").contentWindow.document.body.innerHTML,argument:callback.argument}
+if(callback.upload){if(!callback.scope){callback.upload(oResponse);}
+else{callback.upload.apply(callback.scope,[oResponse]);}}
+YAHOO.util.Event.removeListener("ioFrame","load",uploadCallback);window.ioFrame.location.replace('#');setTimeout("document.body.removeChild(document.getElementById('ioFrame'))",100);};YAHOO.util.Event.addListener("ioFrame","load",uploadCallback);},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){window.clearInterval(this._poll[o.tId]);this._poll.splice(o.tId);if(isTimeout){this._timeOut.splice(o.tId);}
+o.conn.abort();this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};

Added: trunk/theme/src/bin/portal-ajax-war/js/connection/connection.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/connection/connection.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/connection/connection.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,835 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.1
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+			'MSXML2.XMLHTTP.3.0',
+			'MSXML2.XMLHTTP',
+			'Microsoft.XMLHTTP'
+			],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:true,
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type string
+  */
+    _poll:[],
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type string
+  */
+    _timeOut:[],
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+				this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					postData =  this._sFormData;
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._default_post_header)){
+				this.initHeader('Content-Type','application/x-www-form-urlencoded');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			//Verify whether the transaction has any user-defined HTTP headers
+			//and set them.
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			postData?o.conn.send(postData):o.conn.send(null);
+
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an synchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	syncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					postData =  this._sFormData;
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, false);
+
+			if(this._isFormSubmit || (postData && this._default_post_header)){
+				this.initHeader('Content-Type','application/x-www-form-urlencoded');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			//Verify whether the transaction has any user-defined HTTP headers
+			//and set them.
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			postData?o.conn.send(postData):o.conn.send(null);
+
+			return o;
+		}
+	},
+	
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+        var timeOut = callback.timeout;
+        var oConn = this;
+
+        try
+        {
+            if(timeOut !== undefined){
+            	this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true) }, timeOut);
+            }
+            this._poll[o.tId] = window.setInterval(
+                function(){
+					if(o.conn && o.conn.readyState == 4){
+						window.clearInterval(oConn._poll[o.tId]);
+						oConn._poll.splice(o.tId);
+						if(timeOut){
+							oConn._timeOut.splice(o.tId);
+						}
+
+						oConn.handleTransactionResponse(o, callback);
+                    }
+                }
+            ,this._polling_interval);
+        }
+        catch(e)
+        {
+            window.clearInterval(oConn._poll[o.tId]);
+            oConn._poll.splice(o.tId);
+			if(timeOut){
+				oConn._timeOut.splice(o.tId);
+			}
+
+            oConn.handleTransactionResponse(o, callback);
+        }
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			responseObject = this.createResponseObject(o, callback.argument);
+			if(callback.success){
+				if(!callback.scope){
+					callback.success(responseObject);
+				}
+				else{
+					// If a scope property is defined, the callback will be fired from
+					// the context of the object.
+					callback.success.apply(callback.scope, [responseObject]);
+				}
+			}
+		}
+		else{
+			switch(httpStatus){
+				// The following case labels are wininet.dll error codes that may be encountered.
+				// Server timeout
+				case 12002:
+				// 12029 to 12031 correspond to dropped connections.
+				case 12029:
+				case 12030:
+				case 12031:
+				// Connection closed by server.
+				case 12152:
+				// See above comments for variable status.
+				case 13030:
+					responseObject = this.createExceptionObject(o.tId, callback.argument, isAbort);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope, [responseObject]);
+						}
+					}
+					break;
+				default:
+					responseObject = this.createResponseObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope, [responseObject]);
+						}
+					}
+			}
+		}
+
+		this.releaseObject(o);
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.propertyIsEnumerable){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			(typeof secureUri == 'string')?this.createFrame(secureUri):this.createFrame();
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oDisabled = oForm.elements[i].disabled;
+
+			// If the name attribute is not populated, the form field's
+			// value will not be submitted.
+			oElement = oForm.elements[i];
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].value || oElement.options[j].text) + '&';
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as DOM
+		// properties.  A different iframe creation pattern is required for IE.
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME name="ioFrame" id="ioFrame">');
+			if(secureUri){
+				// IE will throw a security exception in an SSL environment if the
+				// iframe source isn't set to a valid resource.
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = 'ioFrame';
+			io.name = 'ioFrame';
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = 'ioFrame';
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var oResponse =
+			{
+				tId: id,
+				responseText: document.getElementById("ioFrame").contentWindow.document.body.innerHTML,
+				argument: callback.argument
+			}
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(oResponse);
+				}
+				else{
+					callback.upload.apply(callback.scope, [oResponse]);
+				}
+			}
+
+			YAHOO.util.Event.removeListener("ioFrame", "load", uploadCallback);
+			window.ioFrame.location.replace('#');
+			setTimeout("document.body.removeChild(document.getElementById('ioFrame'))",100);
+		};
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		YAHOO.util.Event.addListener("ioFrame", "load", uploadCallback);
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			window.clearInterval(this._poll[o.tId]);
+			this._poll.splice(o.tId);
+			if(isTimeout){
+				this._timeOut.splice(o.tId);
+			}
+			o.conn.abort();
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};

Added: trunk/theme/src/bin/portal-ajax-war/js/dom/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dom/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dom/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,45 @@
+Dom Release Notes
+
+*** version 0.11.1 ***
+
+* return null if el is null for get()
+* test offsetParent rather than parentNode for getXY()
+* limit depth of parent.document crawl for IE getXY() to 1
+* if no oldClassName to replace, just addClass for replaceClass()
+
+
+*** version 0.11.0 ***
+* Work around Opera 9 broken currentStyle
+* Removed timeout wrapper from setXY retry
+* Tagname tests now case-insensitive
+* Internal "this" references changed to allow for method shorthand
+* get/setStyle now accept both camel and hyphen case
+* Gecko reverted to crawling offsets for getXY
+ 
+
+*** version 0.10.0 ***
+
+* Safari now fails gracefully when querying computedStyle of an unavailable element 
+
+* Class management functions added (hasClass, addClass, removeClass, replaceClass, getElementsByClassName) 
+
+* All methods that accept HTMLElements or IDs now also accept arrays of HTMLElements and/or IDs
+
+* GenerateId method added
+
+* isAncestor method added
+
+* inDocument method added
+
+* getElementsBy method added
+
+* batch method added
+
+* getClientHeight/Width deprecated in favor of getViewportHeight/Width
+
+* getDocumentHeight/Width methods added 
+
+*** version 0.9.0 ***
+
+* Initial release
+

Added: trunk/theme/src/bin/portal-ajax-war/js/dom/dom-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dom/dom-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dom/dom-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,921 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.1
+*/
+
+/**
+ * @class Provides helper methods for DOM elements.
+ */
+YAHOO.util.Dom = function() {
+   var ua = navigator.userAgent.toLowerCase();
+   var isOpera = (ua.indexOf('opera') > -1);
+   var isSafari = (ua.indexOf('safari') > -1);
+   var isIE = (window.ActiveXObject);
+
+   var id_counter = 0;
+   var util = YAHOO.util; // internal shorthand
+   var property_cache = {}; // to cache case conversion for set/getStyle
+   var logger = {};
+   logger.log = function() {YAHOO.log.apply(window, arguments)};
+   
+   var toCamel = function(property) {
+      var convert = function(prop) {
+         var test = /(-[a-z])/i.exec(prop);
+         return prop.replace(RegExp.$1, RegExp.$1.substr(1).toUpperCase());
+      };
+      
+      while(property.indexOf('-') > -1) {
+         property = convert(property);
+      }
+
+      return property;
+      //return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug
+   };
+   
+   var toHyphen = function(property) {
+      if (property.indexOf('-') > -1) { // assume hyphen
+         return property;
+      }
+      
+      var converted = '';
+      for (var i = 0, len = property.length;i < len; ++i) {
+         if (property.charAt(i) == property.charAt(i).toUpperCase()) {
+            converted = converted + '-' + property.charAt(i).toLowerCase();
+         } else {
+            converted = converted + property.charAt(i);
+         }
+      }
+
+      return converted;
+      //return property.replace(/([a-z])([A-Z]+)/g, function(m0, m1, m2) {return (m1 + '-' + m2.toLowerCase())});
+   };
+   
+   // improve performance by only looking up once
+   var cacheConvertedProperties = function(property) {
+      property_cache[property] = {
+         camel: toCamel(property),
+         hyphen: toHyphen(property)
+      };
+   };
+   
+   return {
+      /**
+       * Returns an HTMLElement reference
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @return {HTMLElement/Array} A DOM reference to an HTML element or an array of HTMLElements.
+       */
+      get: function(el) {
+         if (!el) { return null; } // nothing to work with
+         
+         if (typeof el != 'string' && !(el instanceof Array) ) { // assuming HTMLElement or HTMLCollection, so pass back as is
+            logger.log('get(' + el + ') returning ' + el, 'info', 'Dom');
+            return el;
+         }
+         
+         if (typeof el == 'string') { // ID
+            logger.log('get("' + el + '") returning ' + document.getElementById(el), 'info', 'Dom');
+            return document.getElementById(el);
+         }
+         else { // array of ID's and/or elements
+            var collection = [];
+            for (var i = 0, len = el.length; i < len; ++i) {
+               collection[collection.length] = util.Dom.get(el[i]);
+            }
+            
+            logger.log('get("' + el + '") returning ' + collection, 'info', 'Dom');
+            return collection;
+         }
+
+         logger.log('element ' + el + ' not found', 'error', 'Dom');
+         return null; // safety, should never happen
+      },
+   
+      /**
+       * Normalizes currentStyle and ComputedStyle.
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {String} property The style property whose value is returned.
+       * @return {String/Array} The current value of the style property for the element(s).
+       */
+      getStyle: function(el, property) {
+         var f = function(el) {
+            var value = null;
+            var dv = document.defaultView;
+            
+            if (!property_cache[property]) {
+               cacheConvertedProperties(property);
+            }
+            
+            var camel = property_cache[property]['camel'];
+            var hyphen = property_cache[property]['hyphen'];
+
+            if (property == 'opacity' && el.filters) {// IE opacity
+               value = 1;
+               try {
+                  value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
+               } catch(e) {
+                  try {
+                     value = el.filters.item('alpha').opacity / 100;
+                  } catch(e) {}
+               }
+            } else if (el.style[camel]) { // camelCase for valid styles
+               value = el.style[camel];
+            }
+            else if (isIE && el.currentStyle && el.currentStyle[camel]) { // camelCase for currentStyle; isIE to workaround broken Opera 9 currentStyle
+               value = el.currentStyle[camel];
+            }
+            else if ( dv && dv.getComputedStyle ) { // hyphen-case for computedStyle
+               var computed = dv.getComputedStyle(el, '');
+               
+               if (computed && computed.getPropertyValue(hyphen)) {
+                  value = computed.getPropertyValue(hyphen);
+               }
+            }
+      
+            logger.log('getStyle ' + property + ' returning ' + value, 'info', 'Dom');
+            return value;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {String} property The style property to be set.
+       * @param {String} val The value to apply to the given property.
+       */
+      setStyle: function(el, property, val) {
+         if (!property_cache[property]) {
+            cacheConvertedProperties(property);
+         }
+         
+         var camel = property_cache[property]['camel'];
+         
+         var f = function(el) {
+            switch(property) {
+               case 'opacity' :
+                  if (isIE && typeof el.style.filter == 'string') { // in case not appended
+                     el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+                     
+                     if (!el.currentStyle || !el.currentStyle.hasLayout) {
+                        el.style.zoom = 1; // when no layout or cant tell
+                     }
+                  } else {
+                     el.style.opacity = val;
+                     el.style['-moz-opacity'] = val;
+                     el.style['-khtml-opacity'] = val;
+                  }
+
+                  break;
+               default :
+                  el.style[camel] = val;
+            }
+            
+            logger.log('setStyle setting ' + property + ' to ' + val, 'info', 'Dom');
+            
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       @ return {Array} The XY position of the element(s)
+       */
+      getXY: function(el) {
+         var f = function(el) {
+   
+         // has to be part of document to have pageXY
+            if (el.offsetParent === null || this.getStyle(el, 'display') == 'none') {
+               logger.log('getXY failed: element not available', 'error', 'Dom');
+               return false;
+            }
+            
+            var parentNode = null;
+            var pos = [];
+            var box;
+            
+            if (el.getBoundingClientRect) { // IE
+               box = el.getBoundingClientRect();
+               var doc = document;
+               if ( !this.inDocument(el) && parent.document != document) {// might be in a frame, need to get its scroll
+                  doc = parent.document;
+
+                  if ( !this.isAncestor(doc.documentElement, el) ) {
+                     logger.log('getXY failed: element not available', 'error', 'Dom');
+                     return false;                 
+                  }
+
+               }
+
+               var scrollTop = Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
+               var scrollLeft = Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
+               
+               return [box.left + scrollLeft, box.top + scrollTop];
+            }
+            else { // safari, opera, & gecko
+               pos = [el.offsetLeft, el.offsetTop];
+               parentNode = el.offsetParent;
+               if (parentNode != el) {
+                  while (parentNode) {
+                     pos[0] += parentNode.offsetLeft;
+                     pos[1] += parentNode.offsetTop;
+                     parentNode = parentNode.offsetParent;
+                  }
+               }
+               if (isSafari && this.getStyle(el, 'position') == 'absolute' ) { // safari doubles in some cases
+                  pos[0] -= document.body.offsetLeft;
+                  pos[1] -= document.body.offsetTop;
+               } 
+            }
+            
+            if (el.parentNode) { parentNode = el.parentNode; }
+            else { parentNode = null; }
+      
+            while (parentNode && parentNode.tagName.toUpperCase() != 'BODY' && parentNode.tagName.toUpperCase() != 'HTML') 
+            { // account for any scrolled ancestors
+               pos[0] -= parentNode.scrollLeft;
+               pos[1] -= parentNode.scrollTop;
+      
+               if (parentNode.parentNode) { parentNode = parentNode.parentNode; } 
+               else { parentNode = null; }
+            }
+      
+            logger.log('getXY returning ' + pos, 'info', 'Dom');
+            
+            return pos;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @return {String/Array} The X position of the element(s)
+       */
+      getX: function(el) {
+         return util.Dom.getXY(el)[0];
+      },
+      
+      /**
+       * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @return {String/Array} The Y position of the element(s)
+       */
+      getY: function(el) {
+         return util.Dom.getXY(el)[1];
+      },
+      
+      /**
+       * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @param {Array} pos Contains X & Y values for new position (coordinates are page-based)
+       * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+       */
+      setXY: function(el, pos, noRetry) {
+         var f = function(el) {
+            var style_pos = this.getStyle(el, 'position');
+            if (style_pos == 'static') { // default to relative
+               this.setStyle(el, 'position', 'relative');
+               style_pos = 'relative';
+            }
+            
+            var pageXY = this.getXY(el);
+            if (pageXY === false) { // has to be part of doc to have pageXY
+               logger.log('setXY failed: element not available', 'error', 'Dom');
+               return false; 
+            }
+            
+            var delta = [ // assuming pixels; if not we will have to retry
+               parseInt( this.getStyle(el, 'left'), 10 ),
+               parseInt( this.getStyle(el, 'top'), 10 )
+            ];
+         
+            if ( isNaN(delta[0]) ) {// in case of 'auto'
+               delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
+            } 
+            if ( isNaN(delta[1]) ) { // in case of 'auto'
+               delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
+            } 
+      
+            if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
+            if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
+      
+            var newXY = this.getXY(el);
+      
+            // if retry is true, try one more time if we miss 
+            if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
+               this.setXY(el, pos, true);
+            }
+            
+            logger.log('setXY setting position to ' + pos, 'info', 'Dom');
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {Int} x to use as the X coordinate for the element(s).
+       */
+      setX: function(el, x) {
+         util.Dom.setXY(el, [x, null]);
+      },
+      
+      /**
+       * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {Int} x to use as the Y coordinate for the element(s).
+       */
+      setY: function(el, y) {
+         util.Dom.setXY(el, [null, y]);
+      },
+      
+      /**
+       * Returns the region position of the given element.
+       * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @return {Region/Array} A Region or array of Region instances containing "top, left, bottom, right" member data.
+       */
+      getRegion: function(el) {
+         var f = function(el) {
+            var region = new YAHOO.util.Region.getRegion(el);
+            logger.log('getRegion returning ' + region, 'info', 'Dom');
+            return region;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Returns the width of the client (viewport).
+       * Now using getViewportWidth.  This interface left intact for back compat.
+       * @return {Int} The width of the viewable area of the page.
+       */
+      getClientWidth: function() {
+         return util.Dom.getViewportWidth();
+      },
+      
+      /**
+       * Returns the height of the client (viewport).
+       * Now using getViewportHeight.  This interface left intact for back compat.
+       * @return {Int} The height of the viewable area of the page.
+       */
+      getClientHeight: function() {
+         return util.Dom.getViewportHeight();
+      },
+
+      /**
+       * Returns a array of HTMLElements with the given class
+       * For optimized performance, include a tag and/or root node if possible
+       * @param {String} className The class name to match against
+       * @param {String} tag (optional) The tag name of the elements being collected
+       * @param {String/HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 
+       * @return {Array} An array of elements that have the given class name
+       */
+      getElementsByClassName: function(className, tag, root) {
+         var method = function(el) { return util.Dom.hasClass(el, className) };
+         return util.Dom.getElementsBy(method, tag, root);
+      },
+
+      /**
+       * Determines whether an HTMLElement has the given className
+       * @param {String/HTMLElement/Array} el The element or collection to test
+       * @param {String} className the class name to search for
+       * @return {Boolean/Array} A boolean value or array of boolean values
+       */
+      hasClass: function(el, className) {
+         var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+         
+         var f = function(el) {
+            logger.log('hasClass returning ' + re.test(el['className']), 'info', 'Dom');
+            return re.test(el['className']);
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Adds a class name to a given element or collection of elements
+       * @param {String/HTMLElement/Array} el The element or collection to add the class to
+       * @param {String} className the class name to add to the class attribute
+       */
+      addClass: function(el, className) {
+         var f = function(el) {
+            if (this.hasClass(el, className)) { return; } // already present
+            
+            logger.log('addClass adding ' + className, 'info', 'Dom');
+            
+            el['className'] = [el['className'], className].join(' ');
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Removes a class name from a given element or collection of elements
+       * @param {String/HTMLElement/Array} el The element or collection to remove the class from
+       * @param {String} className the class name to remove from the class attribute
+       */
+      removeClass: function(el, className) {
+         var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
+
+         var f = function(el) {
+            if (!this.hasClass(el, className)) { return; } // not present
+            
+            logger.log('removeClass removing ' + className, 'info', 'Dom');
+            
+            var c = el['className'];
+            el['className'] = c.replace(re, ' ');
+            if ( this.hasClass(el, className) ) { // in case of multiple adjacent
+               this.removeClass(el, className);
+            }
+            
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Replace a class with another class for a given element or collection of elements.
+       * If no oldClassName is present, the newClassName is simply added.
+       * @param {String/HTMLElement/Array} el The element or collection to remove the class from
+       * @param {String} oldClassName the class name to be replaced
+       * @param {String} newClassName the class name that will be replacing the old class name
+       */
+      replaceClass: function(el, oldClassName, newClassName) {
+         var re = new RegExp('(?:^|\\s+)' + oldClassName + '(?:\\s+|$)', 'g');
+
+         var f = function(el) {
+            logger.log('replaceClass replacing ' + oldClassName + ' with ' + newClassName, 'info', 'Dom');
+         
+            if ( !this.hasClass(el, oldClassName) ) {
+               this.addClass(el, newClassName); // just add it if nothing to replace
+               return; // note return
+            }
+         
+            el['className'] = el['className'].replace(re, ' ' + newClassName + ' ');
+
+            if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent
+               this.replaceClass(el, oldClassName, newClassName);
+            }
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Generates a unique ID
+       * @param {String/HTMLElement/Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present)
+       * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen")
+       * @return {String/Array} The generated ID, or array of generated IDs (or original ID if already present on an element)
+       */
+      generateId: function(el, prefix) {
+         prefix = prefix || 'yui-gen';
+         el = el || {};
+         
+         var f = function(el) {
+            if (el) {
+               el = util.Dom.get(el);
+            } else {
+               el = {}; // just generating ID in this case
+            }
+            
+            if (!el.id) {
+               el.id = prefix + id_counter++; 
+               logger.log('generateId generating ' + el.id, 'info', 'Dom');
+            } // dont override existing
+            
+            logger.log('generateId returning ' + el.id, 'info', 'Dom');
+            
+            return el.id;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy
+       * @param {String/HTMLElement} haystack The possible ancestor
+       * @param {String/HTMLElement} needle The possible descendent
+       * @return {Boolean} Whether or not the haystack is an ancestor of needle
+       */
+      isAncestor: function(haystack, needle) {
+         haystack = util.Dom.get(haystack);
+         if (!haystack || !needle) { return false; }
+         
+         var f = function(needle) {
+            if (haystack.contains && !isSafari) { // safari "contains" is broken
+               logger.log('isAncestor returning ' + haystack.contains(needle), 'info', 'Dom');
+               return haystack.contains(needle);
+            }
+            else if ( haystack.compareDocumentPosition ) {
+               logger.log('isAncestor returning ' + !!(haystack.compareDocumentPosition(needle) & 16), 'info', 'Dom');
+               return !!(haystack.compareDocumentPosition(needle) & 16);
+            }
+            else { // loop up and test each parent
+               var parent = needle.parentNode;
+               
+               while (parent) {
+                  if (parent == haystack) {
+                     logger.log('isAncestor returning true', 'info', 'Dom');
+                     return true;
+                  }
+                  else if (parent.tagName.toUpperCase() == 'HTML') {
+                     logger.log('isAncestor returning false', 'info', 'Dom');
+                     return false;
+                  }
+                  
+                  parent = parent.parentNode;
+               }
+               logger.log('isAncestor returning false', 'info', 'Dom');
+               return false;
+            }    
+         };
+         
+         return util.Dom.batch(needle, f, util.Dom, true);     
+      },
+      
+      /**
+       * Determines whether an HTMLElement is present in the current document
+       * @param {String/HTMLElement} el The element to search for
+       * @return {Boolean} Whether or not the element is present in the current document
+       */
+      inDocument: function(el) {
+         var f = function(el) {
+            return this.isAncestor(document.documentElement, el);
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Returns a array of HTMLElements that pass the test applied by supplied boolean method
+       * For optimized performance, include a tag and/or root node if possible
+       * @param {Function} method A boolean method to test elements with
+       * @param {String} tag (optional) The tag name of the elements being collected
+       * @param {String/HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 
+       */
+      getElementsBy: function(method, tag, root) {
+         tag = tag || '*';
+         root = util.Dom.get(root) || document;
+         
+         var nodes = [];
+         var elements = root.getElementsByTagName(tag);
+         
+         if ( !elements.length && (tag == '*' && root.all) ) {
+            elements = root.all; // IE < 6
+         }
+         
+         for (var i = 0, len = elements.length; i < len; ++i) 
+         {
+            if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
+         }
+
+         logger.log('getElementsBy returning ' + nodes, 'info', 'Dom');
+         
+         return nodes;
+      },
+      
+      /**
+       * Returns an array of elements that have had the supplied method applied.
+       * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) )
+       * @param {String/HTMLElement/Array} el (optional) An element or array of elements to apply the method to
+       * @param {Function} method The method to apply to the element(s)
+       * @param {Generic} (optional) o An optional arg that is passed to the supplied method
+       * @param {Boolean} (optional) override Whether or not to override the scope of "method" with "o"
+       * @return {HTMLElement/Array} The element(s) with the method applied
+       */
+      batch: function(el, method, o, override) {
+         var id = el;
+         el = util.Dom.get(el);
+         
+         var scope = (override) ? o : window;
+         
+         if (!el || el.tagName || !el.length) { // is null or not a collection (tagName for SELECT and others that can be both an element and a collection)
+            if (!el) {
+               logger.log(id + ' not available', 'error', 'Dom');
+               return false;
+            }
+            return method.call(scope, el, o);
+         } 
+         
+         var collection = [];
+         
+         for (var i = 0, len = el.length; i < len; ++i) {
+            if (!el[i]) {
+               id = id[i];
+               logger.log(id + ' not available', 'error', 'Dom');
+            }
+            collection[collection.length] = method.call(scope, el[i], o);
+         }
+         
+         return collection;
+      },
+      
+      /**
+       * Returns the height of the document.
+       * @return {Int} The height of the actual document (which includes the body and its margin).
+       */
+      getDocumentHeight: function() {
+         var scrollHeight=-1,windowHeight=-1,bodyHeight=-1;
+         var marginTop = parseInt(util.Dom.getStyle(document.body, 'marginTop'), 10);
+         var marginBottom = parseInt(util.Dom.getStyle(document.body, 'marginBottom'), 10);
+         
+         var mode = document.compatMode;
+         
+         if ( (mode || isIE) && !isOpera ) { // (IE, Gecko)
+            switch (mode) {
+               case 'CSS1Compat': // Standards mode
+                  scrollHeight = ((window.innerHeight && window.scrollMaxY) ?  window.innerHeight+window.scrollMaxY : -1);
+                  windowHeight = [document.documentElement.clientHeight,self.innerHeight||-1].sort(function(a, b){return(a-b);})[1];
+                  bodyHeight = document.body.offsetHeight + marginTop + marginBottom;
+                  break;
+               
+               default: // Quirks
+                  scrollHeight = document.body.scrollHeight;
+                  bodyHeight = document.body.clientHeight;
+            }
+         } else { // Safari & Opera
+            scrollHeight = document.documentElement.scrollHeight;
+            windowHeight = self.innerHeight;
+            bodyHeight = document.documentElement.clientHeight;
+         }
+      
+         var h = [scrollHeight,windowHeight,bodyHeight].sort(function(a, b){return(a-b);});
+         logger.log('getDocumentHeight returning ' + h[2], 'info', 'Dom');
+         return h[2];
+      },
+      
+      /**
+       * Returns the width of the document.
+       * @return {Int} The width of the actual document (which includes the body and its margin).
+       */
+      getDocumentWidth: function() {
+         var docWidth=-1,bodyWidth=-1,winWidth=-1;
+         var marginRight = parseInt(util.Dom.getStyle(document.body, 'marginRight'), 10);
+         var marginLeft = parseInt(util.Dom.getStyle(document.body, 'marginLeft'), 10);
+         
+         var mode = document.compatMode;
+         
+         if (mode || isIE) { // (IE, Gecko, Opera)
+            switch (mode) {
+               case 'CSS1Compat': // Standards mode
+                  docWidth = document.documentElement.clientWidth;
+                  bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
+                  winWidth = self.innerWidth || -1;
+                  break;
+                  
+               default: // Quirks
+                  bodyWidth = document.body.clientWidth;
+                  winWidth = document.body.scrollWidth;
+                  break;
+            }
+         } else { // Safari
+            docWidth = document.documentElement.clientWidth;
+            bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
+            winWidth = self.innerWidth;
+         }
+      
+         var w = [docWidth,bodyWidth,winWidth].sort(function(a, b){return(a-b);});
+         logger.log('getDocumentWidth returning ' + w[2], 'info', 'Dom');
+         return w[2];
+      },
+
+      /**
+       * Returns the current height of the viewport.
+       * @return {Int} The height of the viewable area of the page (excludes scrollbars).
+       */
+      getViewportHeight: function() {
+         var height = -1;
+         var mode = document.compatMode;
+      
+         if ( (mode || isIE) && !isOpera ) {
+            switch (mode) { // (IE, Gecko)
+               case 'CSS1Compat': // Standards mode
+                  height = document.documentElement.clientHeight;
+                  break;
+      
+               default: // Quirks
+                  height = document.body.clientHeight;
+            }
+         } else { // Safari, Opera
+            height = self.innerHeight;
+         }
+      
+         logger.log('getViewportHeight returning ' + height, 'info', 'Dom');
+         return height;
+      },
+      
+      /**
+       * Returns the current width of the viewport.
+       * @return {Int} The width of the viewable area of the page (excludes scrollbars).
+       */
+      
+      getViewportWidth: function() {
+         var width = -1;
+         var mode = document.compatMode;
+         
+         if (mode || isIE) { // (IE, Gecko, Opera)
+            switch (mode) {
+            case 'CSS1Compat': // Standards mode 
+               width = document.documentElement.clientWidth;
+               break;
+               
+            default: // Quirks
+               width = document.body.clientWidth;
+            }
+         } else { // Safari
+            width = self.innerWidth;
+         }
+         logger.log('getViewportWidth returning ' + width, 'info', 'Dom');
+         return width;
+      }
+   };
+}();
+
+/**
+ * @class A region is a representation of an object on a grid.  It is defined
+ * by the top, right, bottom, left extents, so is rectangular by default.  If 
+ * other shapes are required, this class could be extended to support it.
+ *
+ * @param {int} t the top extent
+ * @param {int} r the right extent
+ * @param {int} b the bottom extent
+ * @param {int} l the left extent
+ * @constructor
+ */
+YAHOO.util.Region = function(t, r, b, l) {
+
+    /**
+     * The region's top extent
+     * @type int
+     */
+    this.top = t;
+    
+    /**
+     * The region's top extent as index, for symmetry with set/getXY
+     * @type int
+     */
+    this[1] = t;
+
+    /**
+     * The region's right extent
+     * @type int
+     */
+    this.right = r;
+
+    /**
+     * The region's bottom extent
+     * @type int
+     */
+    this.bottom = b;
+
+    /**
+     * The region's left extent
+     * @type int
+     */
+    this.left = l;
+    
+    /**
+     * The region's left extent as index, for symmetry with set/getXY
+     * @type int
+     */
+    this[0] = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ *
+ * @param  {Region}  region The region to evaluate
+ * @return {boolean}        True if the region is contained with this region, 
+ *                          else false
+ */
+YAHOO.util.Region.prototype.contains = function(region) {
+    return ( region.left   >= this.left   && 
+             region.right  <= this.right  && 
+             region.top    >= this.top    && 
+             region.bottom <= this.bottom    );
+
+    // this.logger.debug("does " + this + " contain " + region + " ... " + ret);
+};
+
+/**
+ * Returns the area of the region
+ *
+ * @return {int} the region's area
+ */
+YAHOO.util.Region.prototype.getArea = function() {
+    return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+/**
+ * Returns the region where the passed in region overlaps with this one
+ *
+ * @param  {Region} region The region that intersects
+ * @return {Region}        The overlap region, or null if there is no overlap
+ */
+YAHOO.util.Region.prototype.intersect = function(region) {
+    var t = Math.max( this.top,    region.top    );
+    var r = Math.min( this.right,  region.right  );
+    var b = Math.min( this.bottom, region.bottom );
+    var l = Math.max( this.left,   region.left   );
+    
+    if (b >= t && r >= l) {
+        return new YAHOO.util.Region(t, r, b, l);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Returns the region representing the smallest region that can contain both
+ * the passed in region and this region.
+ *
+ * @param  {Region} region The region that to create the union with
+ * @return {Region}        The union region
+ */
+YAHOO.util.Region.prototype.union = function(region) {
+    var t = Math.min( this.top,    region.top    );
+    var r = Math.max( this.right,  region.right  );
+    var b = Math.max( this.bottom, region.bottom );
+    var l = Math.min( this.left,   region.left   );
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/**
+ * toString
+ * @return string the region properties
+ */
+YAHOO.util.Region.prototype.toString = function() {
+    return ( "Region {"    +
+             "top: "       + this.top    + 
+             ", right: "   + this.right  + 
+             ", bottom: "  + this.bottom + 
+             ", left: "    + this.left   + 
+             "}" );
+};
+
+/**
+ * Returns a region that is occupied by the DOM element
+ *
+ * @param  {HTMLElement} el The element
+ * @return {Region}         The region that the element occupies
+ * @static
+ */
+YAHOO.util.Region.getRegion = function(el) {
+    var p = YAHOO.util.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * @class
+ *
+ * A point is a region that is special in that it represents a single point on 
+ * the grid.
+ *
+ * @param {int} x The X position of the point
+ * @param {int} y The Y position of the point
+ * @constructor
+ * @extends Region
+ */
+YAHOO.util.Point = function(x, y) {
+   if (x instanceof Array) { // accept output from Dom.getXY
+      y = x[1];
+      x = x[0];
+   }
+   
+    /**
+     * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry)
+     * @type int
+     */
+
+    this.x = this.right = this.left = this[0] = x;
+     
+    /**
+     * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry)
+     * @type int
+     */
+    this.y = this.top = this.bottom = this[1] = y;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
+

Added: trunk/theme/src/bin/portal-ajax-war/js/dom/dom-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dom/dom-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dom/dom-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1 @@
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.1 */ YAHOO.util.Dom=function(){var ua=navigator.userAgent.toLowerCase();var isOpera=(ua.indexOf('opera')>-1);var isSafari=(ua.indexOf('safari')>-1);var isIE=(window.ActiveXObject);var id_counter=0;var util=YAHOO.util;var property_cache={};var toCamel=function(property){var convert=function(prop){var test=/(-[a-z])/i.exec(prop);return prop.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());};while(property.indexOf('-')>-1){property=convert(property);}return property;};var toHyphen=function(property){if(property.indexOf('-')>-1){return property;}var converted='';for(var i=0,len=property.length;i<len;++i){if(property.charAt(i)==property.charAt(i).toUpperCase()){converted=converted+'-'+property.charAt(i).toLowerCase();}else{converted=converted+property.charAt(i);}}return converted;};var cacheConvertedProperties=function(propert!
 y){property_cache[property]={camel:toCamel(property),hyphen:toHyphen(property)};};return{get:function(el){if(!el){return null;}if(typeof el!='string'&&!(el instanceof Array)){return el;}if(typeof el=='string'){return document.getElementById(el);}else{var collection=[];for(var i=0,len=el.length;i<len;++i){collection[collection.length]=util.Dom.get(el[i]);}return collection;}return null;},getStyle:function(el,property){var f=function(el){var value=null;var dv=document.defaultView;if(!property_cache[property]){cacheConvertedProperties(property);}var camel=property_cache[property]['camel'];var hyphen=property_cache[property]['hyphen'];if(property=='opacity'&&el.filters){value=1;try{value=el.filters.item('DXImageTransform.Microsoft.Alpha').opacity/100;}catch(e){try{value=el.filters.item('alpha').opacity/100;}catch(e){}}}else if(el.style[camel]){value=el.style[camel];}else if(isIE&&el.currentStyle&&el.currentStyle[camel]){value=el.currentStyle[camel];}else if(dv&&dv.getComputedSt!
 yle){var computed=dv.getComputedStyle(el,'');if(computed&&computed.get
PropertyValue(hyphen)){value=computed.getPropertyValue(hyphen);}}return value;};return util.Dom.batch(el,f,util.Dom,true);},setStyle:function(el,property,val){if(!property_cache[property]){cacheConvertedProperties(property);}var camel=property_cache[property]['camel'];var f=function(el){switch(property){case'opacity':if(isIE&&typeof el.style.filter=='string'){el.style.filter='alpha(opacity='+val*100+')';if(!el.currentStyle||!el.currentStyle.hasLayout){el.style.zoom=1;}}else{el.style.opacity=val;el.style['-moz-opacity']=val;el.style['-khtml-opacity']=val;}break;default:el.style[camel]=val;}};util.Dom.batch(el,f,util.Dom,true);},getXY:function(el){var f=function(el){if(el.offsetParent===null||this.getStyle(el,'display')=='none'){return false;}var parentNode=null;var pos=[];var box;if(el.getBoundingClientRect){box=el.getBoundingClientRect();var doc=document;if(!this.inDocument(el)&&parent.document!=document){doc=parent.document;if(!this.isAncestor(doc.documentElement,el)){retur!
 n false;}}var scrollTop=Math.max(doc.documentElement.scrollTop,doc.body.scrollTop);var scrollLeft=Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft);return[box.left+scrollLeft,box.top+scrollTop];}else{pos=[el.offsetLeft,el.offsetTop];parentNode=el.offsetParent;if(parentNode!=el){while(parentNode){pos[0]+=parentNode.offsetLeft;pos[1]+=parentNode.offsetTop;parentNode=parentNode.offsetParent;}}if(isSafari&&this.getStyle(el,'position')=='absolute'){pos[0]-=document.body.offsetLeft;pos[1]-=document.body.offsetTop;}}if(el.parentNode){parentNode=el.parentNode;}else{parentNode=null;}while(parentNode&&parentNode.tagName.toUpperCase()!='BODY'&&parentNode.tagName.toUpperCase()!='HTML'){pos[0]-=parentNode.scrollLeft;pos[1]-=parentNode.scrollTop;if(parentNode.parentNode){parentNode=parentNode.parentNode;}else{parentNode=null;}}return pos;};return util.Dom.batch(el,f,util.Dom,true);},getX:function(el){return util.Dom.getXY(el)[0];},getY:function(el){return util.Dom.getXY(el)[1]!
 ;},setXY:function(el,pos,noRetry){var f=function(el){var style_pos=thi
s.getStyle(el,'position');if(style_pos=='static'){this.setStyle(el,'position','relative');style_pos='relative';}var pageXY=this.getXY(el);if(pageXY===false){return false;}var delta=[parseInt(this.getStyle(el,'left'),10),parseInt(this.getStyle(el,'top'),10)];if(isNaN(delta[0])){delta[0]=(style_pos=='relative')?0:el.offsetLeft;}if(isNaN(delta[1])){delta[1]=(style_pos=='relative')?0:el.offsetTop;}if(pos[0]!==null){el.style.left=pos[0]-pageXY[0]+delta[0]+'px';}if(pos[1]!==null){el.style.top=pos[1]-pageXY[1]+delta[1]+'px';}var newXY=this.getXY(el);if(!noRetry&&(newXY[0]!=pos[0]||newXY[1]!=pos[1])){this.setXY(el,pos,true);}};util.Dom.batch(el,f,util.Dom,true);},setX:function(el,x){util.Dom.setXY(el,[x,null]);},setY:function(el,y){util.Dom.setXY(el,[null,y]);},getRegion:function(el){var f=function(el){var region=new YAHOO.util.Region.getRegion(el);return region;};return util.Dom.batch(el,f,util.Dom,true);},getClientWidth:function(){return util.Dom.getViewportWidth();},getClientHeig!
 ht:function(){return util.Dom.getViewportHeight();},getElementsByClassName:function(className,tag,root){var method=function(el){return util.Dom.hasClass(el,className)};return util.Dom.getElementsBy(method,tag,root);},hasClass:function(el,className){var re=new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');var f=function(el){return re.test(el['className']);};return util.Dom.batch(el,f,util.Dom,true);},addClass:function(el,className){var f=function(el){if(this.hasClass(el,className)){return;}el['className']=[el['className'],className].join(' ');};util.Dom.batch(el,f,util.Dom,true);},removeClass:function(el,className){var re=new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)','g');var f=function(el){if(!this.hasClass(el,className)){return;}var c=el['className'];el['className']=c.replace(re,' ');if(this.hasClass(el,className)){this.removeClass(el,className);}};util.Dom.batch(el,f,util.Dom,true);},replaceClass:function(el,oldClassName,newClassName){var re=new RegExp('(?:^|\\s+)'+oldClas!
 sName+'(?:\\s+|$)','g');var f=function(el){if(!this.hasClass(el,oldCla
ssName)){this.addClass(el,newClassName);return;}el['className']=el['className'].replace(re,' '+newClassName+' ');if(this.hasClass(el,oldClassName)){this.replaceClass(el,oldClassName,newClassName);}};util.Dom.batch(el,f,util.Dom,true);},generateId:function(el,prefix){prefix=prefix||'yui-gen';el=el||{};var f=function(el){if(el){el=util.Dom.get(el);}else{el={};}if(!el.id){el.id=prefix+id_counter++;}return el.id;};return util.Dom.batch(el,f,util.Dom,true);},isAncestor:function(haystack,needle){haystack=util.Dom.get(haystack);if(!haystack||!needle){return false;}var f=function(needle){if(haystack.contains&&!isSafari){return haystack.contains(needle);}else if(haystack.compareDocumentPosition){return!!(haystack.compareDocumentPosition(needle)&16);}else{var parent=needle.parentNode;while(parent){if(parent==haystack){return true;}else if(parent.tagName.toUpperCase()=='HTML'){return false;}parent=parent.parentNode;}return false;}};return util.Dom.batch(needle,f,util.Dom,true);},inDocu!
 ment:function(el){var f=function(el){return this.isAncestor(document.documentElement,el);};return util.Dom.batch(el,f,util.Dom,true);},getElementsBy:function(method,tag,root){tag=tag||'*';root=util.Dom.get(root)||document;var nodes=[];var elements=root.getElementsByTagName(tag);if(!elements.length&&(tag=='*'&&root.all)){elements=root.all;}for(var i=0,len=elements.length;i<len;++i){if(method(elements[i])){nodes[nodes.length]=elements[i];}}return nodes;},batch:function(el,method,o,override){var id=el;el=util.Dom.get(el);var scope=(override)?o:window;if(!el||el.tagName||!el.length){if(!el){return false;}return method.call(scope,el,o);}var collection=[];for(var i=0,len=el.length;i<len;++i){if(!el[i]){id=id[i];}collection[collection.length]=method.call(scope,el[i],o);}return collection;},getDocumentHeight:function(){var scrollHeight=-1,windowHeight=-1,bodyHeight=-1;var marginTop=parseInt(util.Dom.getStyle(document.body,'marginTop'),10);var marginBottom=parseInt(util.Dom.getStyle!
 (document.body,'marginBottom'),10);var mode=document.compatMode;if((mo
de||isIE)&&!isOpera){switch(mode){case'CSS1Compat':scrollHeight=((window.innerHeight&&window.scrollMaxY)?window.innerHeight+window.scrollMaxY:-1);windowHeight=[document.documentElement.clientHeight,self.innerHeight||-1].sort(function(a,b){return(a-b);})[1];bodyHeight=document.body.offsetHeight+marginTop+marginBottom;break;default:scrollHeight=document.body.scrollHeight;bodyHeight=document.body.clientHeight;}}else{scrollHeight=document.documentElement.scrollHeight;windowHeight=self.innerHeight;bodyHeight=document.documentElement.clientHeight;}var h=[scrollHeight,windowHeight,bodyHeight].sort(function(a,b){return(a-b);});return h[2];},getDocumentWidth:function(){var docWidth=-1,bodyWidth=-1,winWidth=-1;var marginRight=parseInt(util.Dom.getStyle(document.body,'marginRight'),10);var marginLeft=parseInt(util.Dom.getStyle(document.body,'marginLeft'),10);var mode=document.compatMode;if(mode||isIE){switch(mode){case'CSS1Compat':docWidth=document.documentElement.clientWidth;bodyWidth!
 =document.body.offsetWidth+marginLeft+marginRight;winWidth=self.innerWidth||-1;break;default:bodyWidth=document.body.clientWidth;winWidth=document.body.scrollWidth;break;}}else{docWidth=document.documentElement.clientWidth;bodyWidth=document.body.offsetWidth+marginLeft+marginRight;winWidth=self.innerWidth;}var w=[docWidth,bodyWidth,winWidth].sort(function(a,b){return(a-b);});return w[2];},getViewportHeight:function(){var height=-1;var mode=document.compatMode;if((mode||isIE)&&!isOpera){switch(mode){case'CSS1Compat':height=document.documentElement.clientHeight;break;default:height=document.body.clientHeight;}}else{height=self.innerHeight;}return height;},getViewportWidth:function(){var width=-1;var mode=document.compatMode;if(mode||isIE){switch(mode){case'CSS1Compat':width=document.documentElement.clientWidth;break;default:width=document.body.clientWidth;}}else{width=self.innerWidth;}return width;}};}();YAHOO.util.Region=function(t,r,b,l){this.top=t;this[1]=t;this.right=r;th!
 is.bottom=b;this.left=l;this[0]=l;};YAHOO.util.Region.prototype.contai
ns=function(region){return(region.left>=this.left&&region.right<=this.right&&region.top>=this.top&&region.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(region){var t=Math.max(this.top,region.top);var r=Math.min(this.right,region.right);var b=Math.min(this.bottom,region.bottom);var l=Math.max(this.left,region.left);if(b>=t&&r>=l){return new YAHOO.util.Region(t,r,b,l);}else{return null;}};YAHOO.util.Region.prototype.union=function(region){var t=Math.min(this.top,region.top);var r=Math.max(this.right,region.right);var b=Math.max(this.bottom,region.bottom);var l=Math.min(this.left,region.left);return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(el){var p=YAHOO.util.Dom.getX!
 Y(el);var t=p[1];var r=p[0]+el.offsetWidth;var b=p[1]+el.offsetHeight;var l=p[0];return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Point=function(x,y){if(x instanceof Array){y=x[1];x=x[0];}this.x=this.right=this.left=this[0]=x;this.y=this.top=this.bottom=this[1]=y;};YAHOO.util.Point.prototype=new YAHOO.util.Region();

Added: trunk/theme/src/bin/portal-ajax-war/js/dom/dom.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dom/dom.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dom/dom.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,887 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.1
+*/
+
+/**
+ * @class Provides helper methods for DOM elements.
+ */
+YAHOO.util.Dom = function() {
+   var ua = navigator.userAgent.toLowerCase();
+   var isOpera = (ua.indexOf('opera') > -1);
+   var isSafari = (ua.indexOf('safari') > -1);
+   var isIE = (window.ActiveXObject);
+
+   var id_counter = 0;
+   var util = YAHOO.util; // internal shorthand
+   var property_cache = {}; // to cache case conversion for set/getStyle
+   
+   var toCamel = function(property) {
+      var convert = function(prop) {
+         var test = /(-[a-z])/i.exec(prop);
+         return prop.replace(RegExp.$1, RegExp.$1.substr(1).toUpperCase());
+      };
+      
+      while(property.indexOf('-') > -1) {
+         property = convert(property);
+      }
+
+      return property;
+      //return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug
+   };
+   
+   var toHyphen = function(property) {
+      if (property.indexOf('-') > -1) { // assume hyphen
+         return property;
+      }
+      
+      var converted = '';
+      for (var i = 0, len = property.length;i < len; ++i) {
+         if (property.charAt(i) == property.charAt(i).toUpperCase()) {
+            converted = converted + '-' + property.charAt(i).toLowerCase();
+         } else {
+            converted = converted + property.charAt(i);
+         }
+      }
+
+      return converted;
+      //return property.replace(/([a-z])([A-Z]+)/g, function(m0, m1, m2) {return (m1 + '-' + m2.toLowerCase())});
+   };
+   
+   // improve performance by only looking up once
+   var cacheConvertedProperties = function(property) {
+      property_cache[property] = {
+         camel: toCamel(property),
+         hyphen: toHyphen(property)
+      };
+   };
+   
+   return {
+      /**
+       * Returns an HTMLElement reference
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @return {HTMLElement/Array} A DOM reference to an HTML element or an array of HTMLElements.
+       */
+      get: function(el) {
+         if (!el) { return null; } // nothing to work with
+         
+         if (typeof el != 'string' && !(el instanceof Array) ) { // assuming HTMLElement or HTMLCollection, so pass back as is
+            return el;
+         }
+         
+         if (typeof el == 'string') { // ID
+            return document.getElementById(el);
+         }
+         else { // array of ID's and/or elements
+            var collection = [];
+            for (var i = 0, len = el.length; i < len; ++i) {
+               collection[collection.length] = util.Dom.get(el[i]);
+            }
+            
+            return collection;
+         }
+
+         return null; // safety, should never happen
+      },
+   
+      /**
+       * Normalizes currentStyle and ComputedStyle.
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {String} property The style property whose value is returned.
+       * @return {String/Array} The current value of the style property for the element(s).
+       */
+      getStyle: function(el, property) {
+         var f = function(el) {
+            var value = null;
+            var dv = document.defaultView;
+            
+            if (!property_cache[property]) {
+               cacheConvertedProperties(property);
+            }
+            
+            var camel = property_cache[property]['camel'];
+            var hyphen = property_cache[property]['hyphen'];
+
+            if (property == 'opacity' && el.filters) {// IE opacity
+               value = 1;
+               try {
+                  value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
+               } catch(e) {
+                  try {
+                     value = el.filters.item('alpha').opacity / 100;
+                  } catch(e) {}
+               }
+            } else if (el.style[camel]) { // camelCase for valid styles
+               value = el.style[camel];
+            }
+            else if (isIE && el.currentStyle && el.currentStyle[camel]) { // camelCase for currentStyle; isIE to workaround broken Opera 9 currentStyle
+               value = el.currentStyle[camel];
+            }
+            else if ( dv && dv.getComputedStyle ) { // hyphen-case for computedStyle
+               var computed = dv.getComputedStyle(el, '');
+               
+               if (computed && computed.getPropertyValue(hyphen)) {
+                  value = computed.getPropertyValue(hyphen);
+               }
+            }
+      
+            return value;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {String} property The style property to be set.
+       * @param {String} val The value to apply to the given property.
+       */
+      setStyle: function(el, property, val) {
+         if (!property_cache[property]) {
+            cacheConvertedProperties(property);
+         }
+         
+         var camel = property_cache[property]['camel'];
+         
+         var f = function(el) {
+            switch(property) {
+               case 'opacity' :
+                  if (isIE && typeof el.style.filter == 'string') { // in case not appended
+                     el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+                     
+                     if (!el.currentStyle || !el.currentStyle.hasLayout) {
+                        el.style.zoom = 1; // when no layout or cant tell
+                     }
+                  } else {
+                     el.style.opacity = val;
+                     el.style['-moz-opacity'] = val;
+                     el.style['-khtml-opacity'] = val;
+                  }
+
+                  break;
+               default :
+                  el.style[camel] = val;
+            }
+            
+            
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       @ return {Array} The XY position of the element(s)
+       */
+      getXY: function(el) {
+         var f = function(el) {
+   
+         // has to be part of document to have pageXY
+            if (el.offsetParent === null || this.getStyle(el, 'display') == 'none') {
+               return false;
+            }
+            
+            var parentNode = null;
+            var pos = [];
+            var box;
+            
+            if (el.getBoundingClientRect) { // IE
+               box = el.getBoundingClientRect();
+               var doc = document;
+               if ( !this.inDocument(el) && parent.document != document) {// might be in a frame, need to get its scroll
+                  doc = parent.document;
+
+                  if ( !this.isAncestor(doc.documentElement, el) ) {
+                     return false;                 
+                  }
+
+               }
+
+               var scrollTop = Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
+               var scrollLeft = Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
+               
+               return [box.left + scrollLeft, box.top + scrollTop];
+            }
+            else { // safari, opera, & gecko
+               pos = [el.offsetLeft, el.offsetTop];
+               parentNode = el.offsetParent;
+               if (parentNode != el) {
+                  while (parentNode) {
+                     pos[0] += parentNode.offsetLeft;
+                     pos[1] += parentNode.offsetTop;
+                     parentNode = parentNode.offsetParent;
+                  }
+               }
+               if (isSafari && this.getStyle(el, 'position') == 'absolute' ) { // safari doubles in some cases
+                  pos[0] -= document.body.offsetLeft;
+                  pos[1] -= document.body.offsetTop;
+               } 
+            }
+            
+            if (el.parentNode) { parentNode = el.parentNode; }
+            else { parentNode = null; }
+      
+            while (parentNode && parentNode.tagName.toUpperCase() != 'BODY' && parentNode.tagName.toUpperCase() != 'HTML') 
+            { // account for any scrolled ancestors
+               pos[0] -= parentNode.scrollLeft;
+               pos[1] -= parentNode.scrollTop;
+      
+               if (parentNode.parentNode) { parentNode = parentNode.parentNode; } 
+               else { parentNode = null; }
+            }
+      
+            
+            return pos;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @return {String/Array} The X position of the element(s)
+       */
+      getX: function(el) {
+         return util.Dom.getXY(el)[0];
+      },
+      
+      /**
+       * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @return {String/Array} The Y position of the element(s)
+       */
+      getY: function(el) {
+         return util.Dom.getXY(el)[1];
+      },
+      
+      /**
+       * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+       * @param {Array} pos Contains X & Y values for new position (coordinates are page-based)
+       * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+       */
+      setXY: function(el, pos, noRetry) {
+         var f = function(el) {
+            var style_pos = this.getStyle(el, 'position');
+            if (style_pos == 'static') { // default to relative
+               this.setStyle(el, 'position', 'relative');
+               style_pos = 'relative';
+            }
+            
+            var pageXY = this.getXY(el);
+            if (pageXY === false) { // has to be part of doc to have pageXY
+               return false; 
+            }
+            
+            var delta = [ // assuming pixels; if not we will have to retry
+               parseInt( this.getStyle(el, 'left'), 10 ),
+               parseInt( this.getStyle(el, 'top'), 10 )
+            ];
+         
+            if ( isNaN(delta[0]) ) {// in case of 'auto'
+               delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
+            } 
+            if ( isNaN(delta[1]) ) { // in case of 'auto'
+               delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
+            } 
+      
+            if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
+            if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
+      
+            var newXY = this.getXY(el);
+      
+            // if retry is true, try one more time if we miss 
+            if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
+               this.setXY(el, pos, true);
+            }
+            
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {Int} x to use as the X coordinate for the element(s).
+       */
+      setX: function(el, x) {
+         util.Dom.setXY(el, [x, null]);
+      },
+      
+      /**
+       * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+       * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @param {Int} x to use as the Y coordinate for the element(s).
+       */
+      setY: function(el, y) {
+         util.Dom.setXY(el, [null, y]);
+      },
+      
+      /**
+       * Returns the region position of the given element.
+       * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
+       * @param {String/HTMLElement/Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+       * @return {Region/Array} A Region or array of Region instances containing "top, left, bottom, right" member data.
+       */
+      getRegion: function(el) {
+         var f = function(el) {
+            var region = new YAHOO.util.Region.getRegion(el);
+            return region;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Returns the width of the client (viewport).
+       * Now using getViewportWidth.  This interface left intact for back compat.
+       * @return {Int} The width of the viewable area of the page.
+       */
+      getClientWidth: function() {
+         return util.Dom.getViewportWidth();
+      },
+      
+      /**
+       * Returns the height of the client (viewport).
+       * Now using getViewportHeight.  This interface left intact for back compat.
+       * @return {Int} The height of the viewable area of the page.
+       */
+      getClientHeight: function() {
+         return util.Dom.getViewportHeight();
+      },
+
+      /**
+       * Returns a array of HTMLElements with the given class
+       * For optimized performance, include a tag and/or root node if possible
+       * @param {String} className The class name to match against
+       * @param {String} tag (optional) The tag name of the elements being collected
+       * @param {String/HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 
+       * @return {Array} An array of elements that have the given class name
+       */
+      getElementsByClassName: function(className, tag, root) {
+         var method = function(el) { return util.Dom.hasClass(el, className) };
+         return util.Dom.getElementsBy(method, tag, root);
+      },
+
+      /**
+       * Determines whether an HTMLElement has the given className
+       * @param {String/HTMLElement/Array} el The element or collection to test
+       * @param {String} className the class name to search for
+       * @return {Boolean/Array} A boolean value or array of boolean values
+       */
+      hasClass: function(el, className) {
+         var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+         
+         var f = function(el) {
+            return re.test(el['className']);
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Adds a class name to a given element or collection of elements
+       * @param {String/HTMLElement/Array} el The element or collection to add the class to
+       * @param {String} className the class name to add to the class attribute
+       */
+      addClass: function(el, className) {
+         var f = function(el) {
+            if (this.hasClass(el, className)) { return; } // already present
+            
+            
+            el['className'] = [el['className'], className].join(' ');
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+   
+      /**
+       * Removes a class name from a given element or collection of elements
+       * @param {String/HTMLElement/Array} el The element or collection to remove the class from
+       * @param {String} className the class name to remove from the class attribute
+       */
+      removeClass: function(el, className) {
+         var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
+
+         var f = function(el) {
+            if (!this.hasClass(el, className)) { return; } // not present
+            
+            
+            var c = el['className'];
+            el['className'] = c.replace(re, ' ');
+            if ( this.hasClass(el, className) ) { // in case of multiple adjacent
+               this.removeClass(el, className);
+            }
+            
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Replace a class with another class for a given element or collection of elements.
+       * If no oldClassName is present, the newClassName is simply added.
+       * @param {String/HTMLElement/Array} el The element or collection to remove the class from
+       * @param {String} oldClassName the class name to be replaced
+       * @param {String} newClassName the class name that will be replacing the old class name
+       */
+      replaceClass: function(el, oldClassName, newClassName) {
+         var re = new RegExp('(?:^|\\s+)' + oldClassName + '(?:\\s+|$)', 'g');
+
+         var f = function(el) {
+         
+            if ( !this.hasClass(el, oldClassName) ) {
+               this.addClass(el, newClassName); // just add it if nothing to replace
+               return; // note return
+            }
+         
+            el['className'] = el['className'].replace(re, ' ' + newClassName + ' ');
+
+            if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent
+               this.replaceClass(el, oldClassName, newClassName);
+            }
+         };
+         
+         util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Generates a unique ID
+       * @param {String/HTMLElement/Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present)
+       * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen")
+       * @return {String/Array} The generated ID, or array of generated IDs (or original ID if already present on an element)
+       */
+      generateId: function(el, prefix) {
+         prefix = prefix || 'yui-gen';
+         el = el || {};
+         
+         var f = function(el) {
+            if (el) {
+               el = util.Dom.get(el);
+            } else {
+               el = {}; // just generating ID in this case
+            }
+            
+            if (!el.id) {
+               el.id = prefix + id_counter++; 
+            } // dont override existing
+            
+            
+            return el.id;
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy
+       * @param {String/HTMLElement} haystack The possible ancestor
+       * @param {String/HTMLElement} needle The possible descendent
+       * @return {Boolean} Whether or not the haystack is an ancestor of needle
+       */
+      isAncestor: function(haystack, needle) {
+         haystack = util.Dom.get(haystack);
+         if (!haystack || !needle) { return false; }
+         
+         var f = function(needle) {
+            if (haystack.contains && !isSafari) { // safari "contains" is broken
+               return haystack.contains(needle);
+            }
+            else if ( haystack.compareDocumentPosition ) {
+               return !!(haystack.compareDocumentPosition(needle) & 16);
+            }
+            else { // loop up and test each parent
+               var parent = needle.parentNode;
+               
+               while (parent) {
+                  if (parent == haystack) {
+                     return true;
+                  }
+                  else if (parent.tagName.toUpperCase() == 'HTML') {
+                     return false;
+                  }
+                  
+                  parent = parent.parentNode;
+               }
+               return false;
+            }    
+         };
+         
+         return util.Dom.batch(needle, f, util.Dom, true);     
+      },
+      
+      /**
+       * Determines whether an HTMLElement is present in the current document
+       * @param {String/HTMLElement} el The element to search for
+       * @return {Boolean} Whether or not the element is present in the current document
+       */
+      inDocument: function(el) {
+         var f = function(el) {
+            return this.isAncestor(document.documentElement, el);
+         };
+         
+         return util.Dom.batch(el, f, util.Dom, true);
+      },
+      
+      /**
+       * Returns a array of HTMLElements that pass the test applied by supplied boolean method
+       * For optimized performance, include a tag and/or root node if possible
+       * @param {Function} method A boolean method to test elements with
+       * @param {String} tag (optional) The tag name of the elements being collected
+       * @param {String/HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 
+       */
+      getElementsBy: function(method, tag, root) {
+         tag = tag || '*';
+         root = util.Dom.get(root) || document;
+         
+         var nodes = [];
+         var elements = root.getElementsByTagName(tag);
+         
+         if ( !elements.length && (tag == '*' && root.all) ) {
+            elements = root.all; // IE < 6
+         }
+         
+         for (var i = 0, len = elements.length; i < len; ++i) 
+         {
+            if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
+         }
+
+         
+         return nodes;
+      },
+      
+      /**
+       * Returns an array of elements that have had the supplied method applied.
+       * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) )
+       * @param {String/HTMLElement/Array} el (optional) An element or array of elements to apply the method to
+       * @param {Function} method The method to apply to the element(s)
+       * @param {Generic} (optional) o An optional arg that is passed to the supplied method
+       * @param {Boolean} (optional) override Whether or not to override the scope of "method" with "o"
+       * @return {HTMLElement/Array} The element(s) with the method applied
+       */
+      batch: function(el, method, o, override) {
+         var id = el;
+         el = util.Dom.get(el);
+         
+         var scope = (override) ? o : window;
+         
+         if (!el || el.tagName || !el.length) { // is null or not a collection (tagName for SELECT and others that can be both an element and a collection)
+            if (!el) {
+               return false;
+            }
+            return method.call(scope, el, o);
+         } 
+         
+         var collection = [];
+         
+         for (var i = 0, len = el.length; i < len; ++i) {
+            if (!el[i]) {
+               id = id[i];
+            }
+            collection[collection.length] = method.call(scope, el[i], o);
+         }
+         
+         return collection;
+      },
+      
+      /**
+       * Returns the height of the document.
+       * @return {Int} The height of the actual document (which includes the body and its margin).
+       */
+      getDocumentHeight: function() {
+         var scrollHeight=-1,windowHeight=-1,bodyHeight=-1;
+         var marginTop = parseInt(util.Dom.getStyle(document.body, 'marginTop'), 10);
+         var marginBottom = parseInt(util.Dom.getStyle(document.body, 'marginBottom'), 10);
+         
+         var mode = document.compatMode;
+         
+         if ( (mode || isIE) && !isOpera ) { // (IE, Gecko)
+            switch (mode) {
+               case 'CSS1Compat': // Standards mode
+                  scrollHeight = ((window.innerHeight && window.scrollMaxY) ?  window.innerHeight+window.scrollMaxY : -1);
+                  windowHeight = [document.documentElement.clientHeight,self.innerHeight||-1].sort(function(a, b){return(a-b);})[1];
+                  bodyHeight = document.body.offsetHeight + marginTop + marginBottom;
+                  break;
+               
+               default: // Quirks
+                  scrollHeight = document.body.scrollHeight;
+                  bodyHeight = document.body.clientHeight;
+            }
+         } else { // Safari & Opera
+            scrollHeight = document.documentElement.scrollHeight;
+            windowHeight = self.innerHeight;
+            bodyHeight = document.documentElement.clientHeight;
+         }
+      
+         var h = [scrollHeight,windowHeight,bodyHeight].sort(function(a, b){return(a-b);});
+         return h[2];
+      },
+      
+      /**
+       * Returns the width of the document.
+       * @return {Int} The width of the actual document (which includes the body and its margin).
+       */
+      getDocumentWidth: function() {
+         var docWidth=-1,bodyWidth=-1,winWidth=-1;
+         var marginRight = parseInt(util.Dom.getStyle(document.body, 'marginRight'), 10);
+         var marginLeft = parseInt(util.Dom.getStyle(document.body, 'marginLeft'), 10);
+         
+         var mode = document.compatMode;
+         
+         if (mode || isIE) { // (IE, Gecko, Opera)
+            switch (mode) {
+               case 'CSS1Compat': // Standards mode
+                  docWidth = document.documentElement.clientWidth;
+                  bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
+                  winWidth = self.innerWidth || -1;
+                  break;
+                  
+               default: // Quirks
+                  bodyWidth = document.body.clientWidth;
+                  winWidth = document.body.scrollWidth;
+                  break;
+            }
+         } else { // Safari
+            docWidth = document.documentElement.clientWidth;
+            bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
+            winWidth = self.innerWidth;
+         }
+      
+         var w = [docWidth,bodyWidth,winWidth].sort(function(a, b){return(a-b);});
+         return w[2];
+      },
+
+      /**
+       * Returns the current height of the viewport.
+       * @return {Int} The height of the viewable area of the page (excludes scrollbars).
+       */
+      getViewportHeight: function() {
+         var height = -1;
+         var mode = document.compatMode;
+      
+         if ( (mode || isIE) && !isOpera ) {
+            switch (mode) { // (IE, Gecko)
+               case 'CSS1Compat': // Standards mode
+                  height = document.documentElement.clientHeight;
+                  break;
+      
+               default: // Quirks
+                  height = document.body.clientHeight;
+            }
+         } else { // Safari, Opera
+            height = self.innerHeight;
+         }
+      
+         return height;
+      },
+      
+      /**
+       * Returns the current width of the viewport.
+       * @return {Int} The width of the viewable area of the page (excludes scrollbars).
+       */
+      
+      getViewportWidth: function() {
+         var width = -1;
+         var mode = document.compatMode;
+         
+         if (mode || isIE) { // (IE, Gecko, Opera)
+            switch (mode) {
+            case 'CSS1Compat': // Standards mode 
+               width = document.documentElement.clientWidth;
+               break;
+               
+            default: // Quirks
+               width = document.body.clientWidth;
+            }
+         } else { // Safari
+            width = self.innerWidth;
+         }
+         return width;
+      }
+   };
+}();
+
+/**
+ * @class A region is a representation of an object on a grid.  It is defined
+ * by the top, right, bottom, left extents, so is rectangular by default.  If 
+ * other shapes are required, this class could be extended to support it.
+ *
+ * @param {int} t the top extent
+ * @param {int} r the right extent
+ * @param {int} b the bottom extent
+ * @param {int} l the left extent
+ * @constructor
+ */
+YAHOO.util.Region = function(t, r, b, l) {
+
+    /**
+     * The region's top extent
+     * @type int
+     */
+    this.top = t;
+    
+    /**
+     * The region's top extent as index, for symmetry with set/getXY
+     * @type int
+     */
+    this[1] = t;
+
+    /**
+     * The region's right extent
+     * @type int
+     */
+    this.right = r;
+
+    /**
+     * The region's bottom extent
+     * @type int
+     */
+    this.bottom = b;
+
+    /**
+     * The region's left extent
+     * @type int
+     */
+    this.left = l;
+    
+    /**
+     * The region's left extent as index, for symmetry with set/getXY
+     * @type int
+     */
+    this[0] = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ *
+ * @param  {Region}  region The region to evaluate
+ * @return {boolean}        True if the region is contained with this region, 
+ *                          else false
+ */
+YAHOO.util.Region.prototype.contains = function(region) {
+    return ( region.left   >= this.left   && 
+             region.right  <= this.right  && 
+             region.top    >= this.top    && 
+             region.bottom <= this.bottom    );
+
+};
+
+/**
+ * Returns the area of the region
+ *
+ * @return {int} the region's area
+ */
+YAHOO.util.Region.prototype.getArea = function() {
+    return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+/**
+ * Returns the region where the passed in region overlaps with this one
+ *
+ * @param  {Region} region The region that intersects
+ * @return {Region}        The overlap region, or null if there is no overlap
+ */
+YAHOO.util.Region.prototype.intersect = function(region) {
+    var t = Math.max( this.top,    region.top    );
+    var r = Math.min( this.right,  region.right  );
+    var b = Math.min( this.bottom, region.bottom );
+    var l = Math.max( this.left,   region.left   );
+    
+    if (b >= t && r >= l) {
+        return new YAHOO.util.Region(t, r, b, l);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Returns the region representing the smallest region that can contain both
+ * the passed in region and this region.
+ *
+ * @param  {Region} region The region that to create the union with
+ * @return {Region}        The union region
+ */
+YAHOO.util.Region.prototype.union = function(region) {
+    var t = Math.min( this.top,    region.top    );
+    var r = Math.max( this.right,  region.right  );
+    var b = Math.max( this.bottom, region.bottom );
+    var l = Math.min( this.left,   region.left   );
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/**
+ * toString
+ * @return string the region properties
+ */
+YAHOO.util.Region.prototype.toString = function() {
+    return ( "Region {"    +
+             "top: "       + this.top    + 
+             ", right: "   + this.right  + 
+             ", bottom: "  + this.bottom + 
+             ", left: "    + this.left   + 
+             "}" );
+};
+
+/**
+ * Returns a region that is occupied by the DOM element
+ *
+ * @param  {HTMLElement} el The element
+ * @return {Region}         The region that the element occupies
+ * @static
+ */
+YAHOO.util.Region.getRegion = function(el) {
+    var p = YAHOO.util.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @class
+ *
+ * A point is a region that is special in that it represents a single point on 
+ * the grid.
+ *
+ * @param {int} x The X position of the point
+ * @param {int} y The Y position of the point
+ * @constructor
+ * @extends Region
+ */
+YAHOO.util.Point = function(x, y) {
+   if (x instanceof Array) { // accept output from Dom.getXY
+      y = x[1];
+      x = x[0];
+   }
+   
+    /**
+     * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry)
+     * @type int
+     */
+
+    this.x = this.right = this.left = this[0] = x;
+     
+    /**
+     * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry)
+     * @type int
+     */
+    this.y = this.top = this.bottom = this[1] = y;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
+

Added: trunk/theme/src/bin/portal-ajax-war/js/dragdrop/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dragdrop/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dragdrop/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,61 @@
+Drag and Drop Release Notes
+
+0.11.2
+
+   * Drag and drop will no longer interfere with selecting text on elements
+     that are not involved in drag and drop.
+
+   * The shared drag and drop proxy element now resizes correctly when autoResize
+     is enabled.
+
+0.11.1
+
+   * Fixes an issue where the setXY cache could get out of sync if the element's
+     offsetParent is changed during onDragDrop.
+
+0.11.0
+
+   * The Dom.util.setXY calculation for the initial placement of the dragged
+     element is cached during the drag, enhancing the drag performance.
+
+   * DDProxy no longer enforces having a single proxy element for all instances.
+     dragElId can be set in the config object in the constructor.  If the
+     element already exists it will use that element, otherwise a new one will
+     be created with that id.
+
+   * DDProxy->borderWidth has been removed. The value is calculated on the fly
+     instead.
+
+   * Added DragDrop->clearTicks and DragDrop->clearConstraints
+
+   * All drag and drop constructors now have an additional, optional parameter
+     call "config".  It is an object that can contain properties for a
+     number of configuration settings.
+
+   * Drag and drop will not be disabled for elements that cannot have their
+     location determined.
+
+   * isLegalTarget won't return dd objects that are not targetable.
+
+   * Added DragDrop->removeFromGroup.
+
+   * Constraints are now applied properly when determining which drag and drop
+     events should fire.
+
+
+0.10.0
+
+   * Improved the performance in intersect mode
+
+   * It was possible for the drag and drop initialization to be skipped
+     for very slow loading pages.  This was fixed.
+
+   * New methods to exclude regions within your drag and drop element: 
+     addInvalidHandleId(), addInvalidHandleClass()
+
+   * Added an onAvailable handler that is executed after the initial state is set.
+
+   * Drag and drop is more forgiving when the implementer attempts to create the
+     instance prior to the element being in the document, but after the window
+     load event has fired.
+

Added: trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,2808 @@
+
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.2
+*/ 
+
+/**
+ * Defines the interface and base operation of items that that can be 
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with 
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that 
+ * was clicked matches a handle element.  By default this is the linked 
+ * element, but there are times that you will want only a portion of the 
+ * linked element to initiate the drag operation, and the setHandleElId() 
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any 
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would 
+ * actually happen if you were to run the code above.  Normally you would 
+ * override this class or one of the default implementations, but you can 
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DragDrop: 
+ *                    padding, isTarget, maintainOffset, primaryButtonOnly
+ */
+YAHOO.util.DragDrop = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config); 
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we 
+     * refer to as the "linked element" because the size and position of 
+     * this element is used to determine when the drag and drop objects have 
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * Configuration attributes passed into the constructor
+     * @type object
+     */
+    config: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same 
+     * as the linked element , but could be changed to another element. Ex: 
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null, 
+
+    /**
+     * the id of the element that initiates the drag operation.  By default 
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the 
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null, 
+
+    /**
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @type {string: string}
+     */
+    invalidHandleTypes: null, 
+
+    /**
+     * An associative array of ids for elements that will be ignored if clicked
+     * @type {string: string}
+     */
+    invalidHandleIds: null, 
+
+    /**
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @type string[]
+     */
+    invalidHandleClasses: null, 
+
+    /**
+     * The linked element's absolute X position at the time the drag was 
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was 
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are 
+     * related.  Instances only get events when interacting with other 
+     * DragDrop object in the same group.  This lets us define multiple 
+     * groups using a single DragDrop subclass if we want.
+     * @type {string: string}
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent 
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @type int[]
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint 
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint 
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the 
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a 
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a 
+     * vertical graduation/interval.  This array is generated automatically 
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @type boolean
+     */
+    available: false,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an 
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over 
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more 
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another 
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items 
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items 
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop 
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this 
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+   
+    /**
+     * Override the onAvailable method to do what is needed after the initial
+     * position was determined.
+     */
+    onAvailable: function () { 
+        this.logger.log("onAvailable (base)"); 
+    },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {HTMLElement} the html element 
+     */
+    getEl: function() { 
+        if (!this._domRef) {
+            this._domRef = YAHOO.util.Dom.get(this.id); 
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another 
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {HTMLElement} the html element 
+     */
+    getDragEl: function() {
+        return YAHOO.util.Dom.get(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    init: function(id, sGroup, config) {
+        this.initTarget(id, sGroup, config);
+        YAHOO.util.Event.addListener(this.id, "mousedown", 
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    initTarget: function(id, sGroup, config) {
+
+        // configuration attributes 
+        this.config = config || {};
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter.
+        this.handleElId = id;
+
+        YAHOO.util.Event.onAvailable(id, this.handleOnAvailable, this, true);
+
+        // create a logger instance
+        this.logger = (YAHOO.widget.LogWriter) ? 
+                new YAHOO.widget.LogWriter(this.toString()) : YAHOO;
+
+        // the linked element is the element that gets dragged by default
+        this.setDragElId(id); 
+
+        // by default, clicked anchors will not start drag operations. 
+        // @TODO what else should be here?  Probably form fields.
+        this.invalidHandleTypes = { A: "A" };
+        this.invalidHandleIds = {};
+        this.invalidHandleClasses = [];
+
+        this.applyConfig();
+    },
+
+    /**
+     * Applies the configuration parameters that were passed into the constructor.
+     * This is supposed to happen at each level through the inheritance chain.  So
+     * a DDProxy implentation will execute apply config on DDProxy, DD, and 
+     * DragDrop in order to get all of the parameters that are available in
+     * each object.
+     */
+    applyConfig: function() {
+
+        // configurable properties: 
+        //    padding, isTarget, maintainOffset, primaryButtonOnly
+        this.padding           = this.config.padding || [0, 0, 0, 0];
+        this.isTarget          = (this.config.isTarget !== false);
+        this.maintainOffset    = (this.config.maintainOffset);
+        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
+
+    },
+
+    /**
+     * Executed when the linked element is available
+     * @private
+     */
+    handleOnAvailable: function() {
+        this.logger.log("handleOnAvailable");
+        this.available = true;
+        this.resetConstraints();
+        this.onAvailable();
+    },
+
+     /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.  
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            this.logger.log(this.id + " element is broken");
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+        this.logger.log(this.id + " inital position: " + this.initPageX + 
+                ", " + this.initPageY);
+
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+        this.deltaSetXY = null;
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All 
+     * instances belong to at least one group, and can belong to as many 
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Remove's this instance from the supplied interaction group
+     * @param {string}  sGroup  The group to drop
+     */
+    removeFromGroup: function(sGroup) {
+        this.logger.log("Removing from group: " + sGroup);
+        if (this.groups[sGroup]) {
+            delete this.groups[sGroup];
+        }
+
+        this.DDM.removeDDFromGroup(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element 
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be 
+     * used to initiate the drag operation.  An example of this would be if 
+     * you have a content div with text and links.  Clicking anywhere in the 
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element 
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag 
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        this.logger.log("Adding outer handle event: " + id);
+        YAHOO.util.Event.addListener(id, "mousedown", 
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        this.logger.log("DragDrop obj cleanup " + this.id);
+        YAHOO.util.Event.removeListener(this.id, "mousedown", 
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else 
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e 
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+        this.logger.log("isLocked: " + this.isLocked());
+
+        var EU = YAHOO.util.Event;
+
+        var button = e.which || e.button;
+        this.logger.log("button: " + button);
+
+        if (this.primaryButtonOnly && button > 1) {
+            this.logger.log("Mousedown was not produced by the primary button");
+            return;
+        }
+
+        if (this.isLocked()) {
+            this.logger.log("Drag and drop is disabled, aborting");
+            return;
+        }
+
+        this.logger.log("mousedown " + this.id);
+        this.DDM.refreshCache(this.groups);
+        // var self = this;
+        // setTimeout( function() { self.DDM.refreshCache(self.groups); }, 0);
+
+        // Only process the event if we really clicked within the linked 
+        // element.  The reason we make this check is that in the case that 
+        // another element was moved between the clicked element and the 
+        // cursor in the time between the mousedown and mouseup events. When 
+        // this happens, the element gets the next mousedown event 
+        // regardless of where on the screen it happened.  
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+            this.logger.log("click is over target");
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId || 
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+                this.logger.log("click was a valid handle");
+
+                // set the initial element position
+                this.setStartPosition();
+
+                this.logger.log("firing onMouseDown events");
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     * 
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Lets you to specify an element id for a child of a drag handle
+     * that should not initiate a drag
+     * @param {string} id the element id of the element you wish to ignore
+     */
+    addInvalidHandleId: function(id) {
+        this.invalidHandleIds[id] = id;
+    },
+
+
+    /**
+     * Lets you specify a css class of elements that will not initiate a drag
+     * @param {string} cssClass the class of the elements you wish to ignore
+     */
+    addInvalidHandleClass: function(cssClass) {
+        this.invalidHandleClasses.push(cssClass);
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     * 
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        // this.invalidHandleTypes[type] = null;
+        delete this.invalidHandleTypes[type];
+    },
+    
+    /**
+     * Unsets an invalid handle id
+     * @param {string} the id of the element to re-enable
+     */
+    removeInvalidHandleId: function(id) {
+        delete this.invalidHandleIds[id];
+    },
+
+    /**
+     * Unsets an invalid css class
+     * @param {string} the class of the element(s) you wish to re-enable
+     */
+    removeInvalidHandleClass: function(cssClass) {
+        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
+            if (this.invalidHandleClasses[i] == cssClass) {
+                delete this.invalidHandleClasses[i];
+            }
+        }
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+
+        var valid = true;
+        // var n = (node.nodeName == "#text") ? node.parentNode : node;
+        var nodeName;
+        try {
+            nodeName = node.nodeName.toUpperCase();
+        } catch(e) {
+            nodeName = node.nodeName;
+        }
+        valid = valid && !this.invalidHandleTypes[nodeName];
+        valid = valid && !this.invalidHandleIds[node.id];
+
+        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
+            valid = !YAHOO.util.Dom.hasClass(node, this.invalidHandleClasses[i]);
+        }
+
+        this.logger.log("Valid handle? ... " + valid);
+
+        return valid;
+
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+        
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+        this.logger.log("xTicks: " + this.xTicks.join());
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in 
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        // this.logger.log("setYTicks: " + iStartY + ", " + iTickSize
+               // + ", " + this.initPageY + ", " + this.minY + ", " + this.maxY );
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+        this.logger.log("yTicks: " + this.yTicks.join());
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use 
+     * this method to limit the horizontal travel of the element.  Pass in 
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the 
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the 
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+        this.logger.log("initPageX:" + this.initPageX + " minX:" + this.minX + 
+                " maxX:" + this.maxX);
+    },
+
+    /**
+     * Clears any constraints applied to this instance.  Also clears ticks
+     * since they can't exist independent of a constraint at this time.
+     */
+    clearConstraints: function() {
+        this.logger.log("Clearing constraints");
+        this.constrainX = false;
+        this.constrainY = false;
+        this.clearTicks();
+    },
+
+    /**
+     * Clears any tick interval defined for this instance
+     */
+    clearTicks: function() {
+        this.logger.log("Clearing ticks");
+        this.xTicks = null;
+        this.yTicks = null;
+        this.xTickSize = 0;
+        this.yTickSize = 0;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set 
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the 
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.logger.log("setYConstraint: " + iUp + "," + iDown + "," + iTickSize);
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+        
+        this.logger.log("initPageY:" + this.initPageY + " minY:" + this.minY + 
+                " maxY:" + this.maxY);
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+        this.logger.log("resetConstraints");
+
+        // Maintain offsets if necessary
+        if (this.initPageX || this.initPageX === 0) {
+            this.logger.log("init pagexy: " + this.initPageX + ", " + 
+                               this.initPageY);
+            this.logger.log("last pagexy: " + this.lastPageX + ", " + 
+                               this.lastPageY);
+            // figure out how much this thing has moved
+            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+            this.setInitPosition(dx, dy);
+
+        // This is the first time we have detected the element's position
+        } else {
+            this.setInitPosition();
+        }
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint, 
+                                 this.rightConstraint, 
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint, 
+                                 this.bottomConstraint, 
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify 
+     * that it move a number of pixels at a time.  This method resolves the 
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel, 
+            // so we return the value passed to us.
+            return val; 
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i=0, len=tickArray.length; i<len; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function() {
+        return ("DragDrop " + this.id);
+    }
+
+};
+
+// Only load the library once.  Rewriting the manager class would orphan 
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * Handles the element interaction for all DragDrop items in the 
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop 
+     * implementations.  This class should not be instantiated; all methods 
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first 
+         * dimension is the DragDrop item group, the second the DragDrop 
+         * object.
+         *
+         * @type {string: string}
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine 
+         * if the element that generated the mousedown event is actually the 
+         * handle and not the html element itself.
+         *
+         * @type {string: string}
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+        this.logger = null;
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to 
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events 
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+        
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+            this.logger = (YAHOO.widget.LogWriter) ?
+                new YAHOO.widget.LogWriter("DragDropMgr") : YAHOO;
+            this.initialized = true;
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the 
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the 
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+            this.init();
+
+            this.logger.log("DDM onload");
+            var EU = YAHOO.util.Event;
+
+            EU.on(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.on(document, "mousemove", this.handleMouseMove, this, true);
+            EU.on(window,   "unload",    this._onUnload, this, true);
+            EU.on(window,   "resize",    this._onResize, this, true);
+            EU.on(window,   "mouseout",    this._test);
+
+            this.logger.log("DDM loaded");
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this.logger.log("window resize");
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the 
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the 
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a 
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a 
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.  
+         * This is executed in DragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+            
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Removes the supplied dd instance from the supplied group. Executed
+         * by DragDrop.removeFromGroup.
+         * @private
+         */
+        this.removeDDFromGroup = function(oDD, sGroup) {
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+
+            var obj = this.ids[sGroup];
+            if (obj && obj[oDD.id]) {
+                delete obj[oDD.id];
+            }
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in 
+         * DragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing DragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag 
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been 
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item, 
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {DragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {DragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for 
+         * the specifice drag obj
+         *
+         * @param {DragDrop} the drag obj
+         * @param {DragDrop) the target
+         * @return {boolean} true if the target is a legal target for the 
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD, true);
+            for (var i=0, len=targets.length;i<len;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof DragDrop, and the exact subclass of DragDrop.  typeof 
+         * returns "object", oDD.constructor.toString() always returns
+         * "DragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in DragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = DragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been 
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false 
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] && 
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+
+            this.currentTarget = YAHOO.util.Event.getTarget(e);
+
+            this.logger.log("mousedown - adding event handlers");
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = YAHOO.util.Event.getPageX(e);
+            this.startY = YAHOO.util.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout( 
+                    function() { 
+                        var DDM = YAHOO.util.DDM;
+                        DDM.startDrag(DDM.startX, DDM.startY); 
+                    }, 
+                    this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold 
+         * time threshold has been met.
+         * 
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            this.logger.log("firing drag start events");
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked 
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.logger.log("mouseup detected - completing drag");
+                this.fireEvents(e, true);
+            } else {
+                this.logger.log("drag threshold not met");
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these 
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                YAHOO.util.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                YAHOO.util.Event.preventDefault(e);
+            }
+        };
+
+        /** 
+         * Internal function to clean up event handlers after the drag 
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+            // this.logger.log("mouseup - removing event handlers");
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.logger.log("firing endDrag events");
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.logger.log("firing mouseUp event");
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+
+        /** 
+         * Internal function to handle the mousemove event.  Will be invoked 
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the 
+         * user drags objects beyond the window boundary.  Currently we can 
+         * detect this in internet explorer by verifying that the mouse is 
+         * down during the mousemove event.  Firefox doesn't give us the 
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                // this.logger.log("no current drag obj");
+                return true;
+            }
+
+            // var button = e.which || e.button;
+            // this.logger.log("which: " + e.which + ", button: "+ e.button);
+
+            // check for IE mouseup outside of page boundary
+            if (YAHOO.util.Event.isIE && !e.button) {
+                this.logger.log("button failure");
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - YAHOO.util.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - YAHOO.util.Event.getPageY(e));
+                // this.logger.log("diffX: " + diffX + "diffY: " + diffY);
+                if (diffX > this.clickPixelThresh || 
+                            diffY > this.clickPixelThresh) {
+                    this.logger.log("pixel threshold met");
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+
+            return true;
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are 
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could 
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = YAHOO.util.Event.getPageX(e);
+            var y = YAHOO.util.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object(s) we were hovering over is no longer 
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+                // this.logger.log("Processing group " + sGroup);
+                
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length) {
+                    this.logger.log(dc.id+" onDragOut: " + outEvts);
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length) {
+                    this.logger.log(dc.id+" onDragEnter: " + enterEvts);
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length) {
+                    this.logger.log(dc.id+" onDragOver: " + overEvts);
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length) {
+                    this.logger.log(dc.id+" onDragDrop: " + dropEvts);
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                var len = 0;
+                for (i=0, len=outEvts.length; i<len; ++i) {
+                    this.logger.log(dc.id+" onDragOut: " + outEvts[i].id);
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+                 
+                // fire enter events
+                for (i=0,len=enterEvts.length; i<len; ++i) {
+                    this.logger.log(dc.id + " onDragEnter " + enterEvts[i].id);
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+         
+                // fire over events
+                for (i=0,len=overEvts.length; i<len; ++i) {
+                    this.logger.log(dc.id + " onDragOver " + overEvts[i].id);
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0, len=dropEvts.length; i<len; ++i) {
+                    this.logger.log(dc.id + " dropped on " + dropEvts[i].id);
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag 
+         * and drop objects returned by the drag and drop events when we are 
+         * in INTERSECT mode.  It returns either the first object that the 
+         * cursor is over, or the object that has the greatest overlap with 
+         * the dragged element.
+         *
+         * @param  {DragDrop[]} dds The array of drag and drop objects 
+         * targeted
+         * @return {DragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            var len = dds.length;
+
+            if (len == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<len; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the 
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner || 
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the 
+         * drag and drop objects in the specified groups
+         *
+         * @param {Object} groups an associative array of groups to refresh
+         */
+        this.refreshCache = function(groups) {
+            this.logger.log("refreshing element location cache");
+            for (sGroup in groups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            this.logger.log("Could not get the loc for " + oDD.id,
+                                    "warn");
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            // oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+                this.logger.log("detected problem with an element");
+            }
+
+            return false;
+        };
+        
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the DragDrop.padding configured for it
+         *
+         * @param {DragDrop} oDD the drag and drop object to get the 
+         * location for
+         * @return array containing the top left and bottom right points of the 
+         * element 
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                this.logger.log(oDD + " is not a DD obj");
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            // element will not have an offsetparent if it was removed from the
+            // document or display=none
+            // if (!this.verifyEl(el)) {
+                // this.logger.log(oDD + " element is not usable");
+                // return null;
+            // }
+
+            // this.logger.log(oDD.id + " padding: " + oDD.padding);
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = null;
+            try {
+                aPos= YAHOO.util.Dom.getXY(el);
+            } catch (e) { }
+
+            if (!aPos) {
+                return null;
+            }
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         * 
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {DragDrop} oTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oTarget.id];
+            if (!loc || !this.useCache) {
+                this.logger.log("cache not populated");
+                loc = this.getLocation(oTarget);
+                this.locationCache[oTarget.id] = loc;
+
+                this.logger.log("cache: " + loc);
+            }
+
+            if (!loc) {
+                return false;
+            }
+
+            oTarget.cursorIsOver = loc.contains( pt );
+
+            // DragDrop is using this as a sanity check for the initial mousedown
+            // in this case we are done.  In POINT mode, if the drag obj has no
+            // contraints, we are also done. Otherwise we need to evaluate the 
+            // location of the target as related to the actual location of the
+            // dragged element.
+            var dc = this.dragCurrent;
+            if (!dc || (!intersect && !dc.constrainX && !dc.constrainY)) {
+                return oTarget.cursorIsOver;
+            }
+
+            oTarget.overlap = null;
+
+            // Get the current location of the drag element, this is the
+            // location of the mouse event less the delta that represents
+            // where the original mousedown happened on the element.  We
+            // need to consider constraints and ticks as well.
+            var pos = dc.getTargetCoord(pt.x, pt.y);
+
+            var el = dc.getDragEl();
+            var curRegion = new YAHOO.util.Region( pos.y, 
+                                                   pos.x + el.offsetWidth,
+                                                   pos.y + el.offsetHeight, 
+                                                   pos.x );
+
+            var overlap = curRegion.intersect(loc);
+
+            if (overlap) {
+                oTarget.overlap = overlap;
+                return (intersect) ? true : oTarget.cursorIsOver;
+            } else {
+                return false;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         * @private
+         */
+        this.unregAll = function() {
+            this.logger.log("unregister all");
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         * @private
+         */
+        this.elementCache = {};
+        
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         * @deprecated
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                oWrapper = this.elementCache[id] = 
+                    new this.ElementWrapper(YAHOO.util.Dom.get(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         * @deprecated
+         */
+        this.getElement = function(id) {
+            return YAHOO.util.Dom.get(id);
+        };
+        
+        /**
+         * Returns the style property for the DOM element (i.e., 
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         * @deprecated
+         */
+        this.getCss = function(id) {
+            var el = YAHOO.util.Dom.get(id);
+            return (el) ? el.style : null;
+        };
+
+        /**
+         * Inner class for cached elements
+         * @private
+         * @deprecated
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         * @deprecated
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         * @deprecated
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el); 
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we 
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky. 
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2, n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string} The value of the style property
+         * @deprecated, use YAHOO.util.Dom.getStyle
+         */
+        this.getStyle = function(el, styleProp) {
+            return YAHOO.util.Dom.getStyle(el, styleProp);
+        };
+
+        /**
+         * Gets the scrollTop
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        /**
+         * Sets the x/y position of an element to the location of the
+         * target element.
+         * @param {HTMLElement} moveEl      The element to move
+         * @param {HTMLElement} targetEl    The position reference element
+         */
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            this.logger.log("moveToEl: " + aCoord);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         * @return {int} client height in px
+         * @deprecated
+         */
+        this.getClientHeight = function() {
+            return YAHOO.util.Dom.getClientHeight();
+        };
+
+        /**
+         * Gets the client width
+         * @return {int} client width in px
+         * @deprecated
+         */
+        this.getClientWidth = function() {
+            return YAHOO.util.Dom.getClientWidth();
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         * @private
+         */
+        this._addListeners = function() {
+            if ( YAHOO.util.Event && document ) {
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 1000) {
+                    this.logger.log("DragDrop requires the Event Utility");
+                } else {
+                    var DDM = YAHOO.util.DDM;
+                    setTimeout( function() { DDM._addListeners(); }, 10);
+                    if (document && document.body) {
+                        this._timeoutCount += 1;
+                    }
+                }
+            }
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for 
+         * the handle element in order to determine wheter or not it was 
+         * clicked.
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                this.logger.log("clicked node is a handle");
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+                // this.logger.log("p: " + p);
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        this.logger.log(p.id + " is not a handle");
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    } ();
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/**
+ * A DragDrop implementation where the linked element follows the 
+ * mouse cursor during a drag.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element 
+ * @param {String} sGroup the group of related DragDrop items
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DD: 
+ *                    scroll
+ */
+YAHOO.util.DD = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+    }
+};
+
+// YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+YAHOO.extend(YAHOO.util.DD, YAHOO.util.DragDrop);
+
+/**
+ * When set to true, the utility automatically tries to scroll the browser
+ * window wehn a drag and drop element is dragged near the viewport boundary.
+ * Defaults to true.
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true; 
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top 
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    // var el = this.getEl();
+    // var aCoord = YAHOO.util.Dom.getXY(el);
+    // var x = iPageX - aCoord[0];
+    // var y = iPageY - aCoord[1];
+    var x = iPageX - this.startPageX;
+    var y = iPageY - this.startPageY;
+    this.setDelta(x, y);
+    // this.logger.log("autoOffset el pos: " + aCoord + ", delta: " + x + "," + y);
+};
+
+/** 
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in YAHOO.widget.Slider)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+    this.logger.log("deltaX:" + this.deltaX + ", deltaY:" + this.deltaY);
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event, 
+ * maintaining the cursor location relative to the location on the element 
+ * that was clicked.  Override this if you want to place the element in a 
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    // the first time we do this, we are going to check to make sure
+    // the element has css positioning
+
+    var el = this.getDragEl();
+
+    // if (!this.cssVerified) {
+        // var pos = el.style.position;
+        // this.logger.log("drag element position: " + pos);
+    // }
+
+    this.alignElWithMouse(el, iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event, 
+ * maintaining the cursor location relative to the location on the element 
+ * that was clicked.  Override this if you want to place the element in a 
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+    // this.logger.log("****alignElWithMouse : " + el.id + ", " + aCoord + ", " + el.style.display);
+
+    // this.deltaSetXY = null;
+    if (!this.deltaSetXY) {
+        var aCoord = [oCoord.x, oCoord.y];
+        YAHOO.util.Dom.setXY(el, aCoord);
+        var newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
+        var newTop  = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
+
+        this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
+
+        // this.logger.log("css X: " + YAHOO.util.Dom.getStyle(el, "left"));
+        // this.logger.log("css Y: " + YAHOO.util.Dom.getStyle(el, "top"));
+        // this.logger.log("deltaSetXY: " + this.deltaSetXY);
+    } else {
+        YAHOO.util.Dom.setStyle(el, "left", (oCoord.x + this.deltaSetXY[0]) + "px");
+        YAHOO.util.Dom.setStyle(el, "top",  (oCoord.y + this.deltaSetXY[1]) + "px");
+    }
+    
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the 
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area, 
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+        // this.logger.log( " x: " + x + " y: " + y + " h: " + h + 
+        // " clientH: " + clientH + " clientW: " + clientW + 
+        // " st: " + st + " sl: " + sl + " bot: " + bot + 
+        // " right: " + right + " toBot: " + toBot + " toRight: " + toRight);
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce 
+        // clunky scrolling. IE is more sensitive about this ... it needs this 
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the 
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) { 
+            window.scrollTo(sl, st + scrAmt); 
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) { 
+            window.scrollTo(sl, st - scrAmt); 
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) { 
+            window.scrollTo(sl + scrAmt, st); 
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) { 
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+    // this.logger.log("getTargetCoord: " + iPageX + ", " + iPageY);
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+    // this.logger.log("getTargetCoord " + 
+            // " iPageX: " + iPageX +
+            // " iPageY: " + iPageY +
+            // " x: " + x + ", y: " + y);
+
+    return {x:x, y:y};
+};
+
+YAHOO.util.DD.prototype.applyConfig = function() {
+    YAHOO.util.DD.superclass.applyConfig.call(this);
+    this.scroll = (this.config.scroll !== false);
+};
+
+/** 
+ * Event that fires prior to the onMouseDown event.  Overrides 
+ * YAHOO.util.DragDrop.
+ */
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e), 
+                        YAHOO.util.Event.getPageY(e));
+};
+
+/** 
+ * Event that fires prior to the onDrag event.  Overrides 
+ * YAHOO.util.DragDrop.
+ */
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e), 
+                        YAHOO.util.Event.getPageY(e));
+};
+
+YAHOO.util.DD.prototype.toString = function() {
+    return ("DD " + this.id);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+    this.logger.log(this.id.toString()  + " startDrag");
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+    this.logger.log(this.id.toString() + " onDrag");
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+    this.logger.log(this.id.toString() + " onDragEnter: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+    this.logger.log(this.id.toString() + " onDragOver: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+    this.logger.log(this.id.toString() + " onDragOut: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+    this.logger.log(this.id.toString() + " onDragDrop: " + id);
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+    this.logger.log(this.id.toString() + " endDrag");
+};
+*/
+
+/**
+ * A DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * References to the "frame" element refer to the single proxy element that
+ * was created to be dragged in place of all DDProxy elements on the
+ * page.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DDProxy in addition to those in DragDrop: 
+ *                   resizeFrame, centerFrame, dragElId
+ */
+YAHOO.util.DDProxy = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+        this.initFrame(); 
+    }
+};
+
+YAHOO.extend(YAHOO.util.DDProxy, YAHOO.util.DD);
+
+/**
+ * The default drag frame div id
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior.
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.prototype.createFrame = function() {
+    var self = this;
+    var body = document.body;
+
+    if (!body || !body.firstChild) {
+        setTimeout( function() { self.createFrame(); }, 50 );
+        return;
+    }
+
+    var div = this.getDragEl();
+
+    if (!div) {
+        div    = document.createElement("div");
+        div.id = this.dragElId;
+        var s  = div.style;
+
+        s.position   = "absolute";
+        s.visibility = "hidden";
+        s.cursor     = "move";
+        s.border     = "2px solid #aaa";
+        s.zIndex     = 999;
+
+        // appendChild can blow up IE if invoked prior to the window load event
+        // while rendering a table.  It is possible there are other scenarios 
+        // that would cause this to happen as well.
+        body.insertBefore(div, body.firstChild);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    // YAHOO.util.DDProxy.createFrame();
+    // this.setDragElId(YAHOO.util.DDProxy.dragElId);
+
+    this.createFrame();
+
+};
+
+YAHOO.util.DDProxy.prototype.applyConfig = function() {
+    this.logger.log("DDProxy applyConfig");
+    YAHOO.util.DDProxy.superclass.applyConfig.call(this);
+
+    this.resizeFrame = (this.config.resizeFrame !== false);
+    this.centerFrame = (this.config.centerFrame);
+    this.setDragElId(this.config.dragElId || YAHOO.util.DDProxy.dragElId);
+
+    //this.logger.log("dragElId: " + this.dragElId);
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions 
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var dragEl = this.getDragEl();
+    var s = dragEl.style;
+
+    this._resizeProxy();
+
+    if (this.centerFrame) {
+        this.setDelta( Math.round(parseInt(s.width,  10)/2), 
+                       Math.round(parseInt(s.height, 10)/2) );
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    YAHOO.util.Dom.setStyle(dragEl, "visibility", "visible"); 
+};
+
+YAHOO.util.DDProxy.prototype._resizeProxy = function() {
+    var DOM    = YAHOO.util.Dom;
+    var el     = this.getEl();
+    var dragEl = this.getDragEl();
+
+    if (this.resizeFrame) {
+        var bt = parseInt( DOM.getStyle(dragEl, "borderTopWidth"    ), 10);
+        var br = parseInt( DOM.getStyle(dragEl, "borderRightWidth"  ), 10);
+        var bb = parseInt( DOM.getStyle(dragEl, "borderBottomWidth" ), 10);
+        var bl = parseInt( DOM.getStyle(dragEl, "borderLeftWidth"   ), 10);
+
+        if (isNaN(bt)) { bt = 0; }
+        if (isNaN(br)) { br = 0; }
+        if (isNaN(bb)) { bb = 0; }
+        if (isNaN(bl)) { bl = 0; }
+
+        this.logger.log("proxy size: " + bt + "  " + br + " " + bb + " " + bl);
+
+        var newWidth  = el.offsetWidth - br - bl;
+        var newHeight = el.offsetHeight - bt - bb;
+
+        this.logger.log("Resizing proxy element");
+
+        DOM.setStyle( dragEl, "width",  newWidth  + "px" );
+        DOM.setStyle( dragEl, "height", newHeight + "px" );
+    }
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.logger.log("start drag show frame, x: " + x + ", y: " + y);
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+    this.logger.log(this.id + " b4EndDrag");
+    YAHOO.util.Dom.setStyle(this.getDragEl(), "visibility", "hidden"); 
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.  
+// This is so that the default behavior mirrors that of YAHOO.util.DD.  
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    var DOM = YAHOO.util.Dom;
+    this.logger.log(this.id + " endDrag");
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    // del.style.visibility = "";
+    DOM.setStyle(del, "visibility", ""); 
+
+    // Hide the linked element before the move to get around a Safari 
+    // rendering bug.
+    //lel.style.visibility = "hidden";
+    DOM.setStyle(lel, "visibility", "hidden"); 
+    YAHOO.util.DDM.moveToEl(lel, del);
+    //del.style.visibility = "hidden";
+    DOM.setStyle(del, "visibility", "hidden"); 
+    //lel.style.visibility = "";
+    DOM.setStyle(lel, "visibility", ""); 
+};
+
+YAHOO.util.DDProxy.prototype.toString = function() {
+    return ("DDProxy " + this.id);
+};
+
+/**
+ * A DragDrop implementation that does not move, but can be a drop 
+ * target.  You would get the same result by simply omitting implementation 
+ * for the event callbacks, but this way we reduce the processing cost of the 
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop 
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DDTarget in addition to those in DragDrop: 
+ *                  none
+ */
+ 
+YAHOO.util.DDTarget = function(id, sGroup, config) {
+    if (id) {
+        this.initTarget(id, sGroup, config);
+    }
+};
+
+// YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+YAHOO.extend(YAHOO.util.DDTarget, YAHOO.util.DragDrop);
+
+YAHOO.util.DDTarget.prototype.toString = function() {
+    return ("DDTarget " + this.id);
+};
+

Added: trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,9 @@
+
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.2
+*/ 
+
+YAHOO.util.DragDrop=function(id,_2,_3){if(id){this.init(id,_2,_3);}};YAHOO.util.DragDrop.prototype={id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,b4StartDrag:function(x,y){},startDrag:function(x,y){},b4Drag:function(e){},onDrag:function(e){},onDragEnter:function(e,id){},b4DragOver:function(e){},onDragOver:function(e,id){},b4DragOut:function(e){},onDragOut:function(e,id){},b4DragDrop:function(e){},onDragDrop:function(e,id){},b4EndDrag:function(e){},endDrag:function(e){},b4MouseDown:function(e){},onMouseDown:function(e){},onMouseUp:function(e){},onAvailable:function(){},getEl:fun!
 ction(){if(!this._domRef){this._domRef=YAHOO.util.Dom.get(this.id);}return this._domRef;},getDragEl:function(){return YAHOO.util.Dom.get(this.dragElId);},init:function(id,_7,_8){this.initTarget(id,_7,_8);YAHOO.util.Event.addListener(this.id,"mousedown",this.handleMouseDown,this,true);},initTarget:function(id,_9,_10){this.config=_10||{};this.DDM=YAHOO.util.DDM;this.groups={};this.id=id;this.addToGroup((_9)?_9:"default");this.handleElId=id;YAHOO.util.Event.onAvailable(id,this.handleOnAvailable,this,true);this.setDragElId(id);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(_11,_12,_13,!
 _14){if(!_12&&0!==_12){this.padding=[_11,_11,_11,_11];}else{if(!_13&&0
!==_13){this.padding=[_11,_12,_11,_12];}else{this.padding=[_11,_12,_13,_14];}}},setInitPosition:function(_15,_16){var el=this.getEl();if(!this.DDM.verifyEl(el)){return;}var dx=_15||0;var dy=_16||0;var p=YAHOO.util.Dom.getXY(el);this.initPageX=p[0]-dx;this.initPageY=p[1]-dy;this.lastPageX=p[0];this.lastPageY=p[1];this.setStartPosition(p);},setStartPosition:function(pos){var p=pos||YAHOO.util.Dom.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=p[0];this.startPageY=p[1];},addToGroup:function(_22){this.groups[_22]=true;this.DDM.regDragDrop(this,_22);},removeFromGroup:function(_23){if(this.groups[_23]){delete this.groups[_23];}this.DDM.removeDDFromGroup(this,_23);},setDragElId:function(id){this.dragElId=id;},setHandleElId:function(id){this.handleElId=id;this.DDM.regHandle(this.id,id);},setOuterHandleElId:function(id){YAHOO.util.Event.addListener(id,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(id);},unreg:function(){YAHOO.util.Event.removeListener(this.i!
 d,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return (this.DDM.isLocked()||this.locked);},handleMouseDown:function(e,oDD){var EU=YAHOO.util.Event;var _26=e.which||e.button;if(this.primaryButtonOnly&&_26>1){return;}if(this.isLocked()){return;}this.DDM.refreshCache(this.groups);var pt=new YAHOO.util.Point(EU.getPageX(e),EU.getPageY(e));if(this.DDM.isOverTarget(pt,this)){var _28=EU.getTarget(e);if(this.isValidHandleChild(_28)&&(this.id==this.handleElId||this.DDM.handleWasClicked(_28,this.id))){this.setStartPosition();this.b4MouseDown(e);this.onMouseDown(e);this.DDM.handleMouseDown(e,this);this.DDM.stopEvent(e);}}},addInvalidHandleType:function(_29){var _30=_29.toUpperCase();this.invalidHandleTypes[_30]=_30;},addInvalidHandleId:function(id){this.invalidHandleIds[id]=id;},addInvalidHandleClass:function(_31){this.invalidHandleClasses.push(_31);},removeInvalidHandleType:function(_32){var _33=_32.toUpperCase();delete this.invalid!
 HandleTypes[_33];},removeInvalidHandleId:function(id){delete this.inva
lidHandleIds[id];},removeInvalidHandleClass:function(_34){for(var i=0,len=this.invalidHandleClasses.length;i<len;++i){if(this.invalidHandleClasses[i]==_34){delete this.invalidHandleClasses[i];}}},isValidHandleChild:function(_36){var _37=true;var _38;try{_38=_36.nodeName.toUpperCase();}catch(e){_38=_36.nodeName;}_37=_37&&!this.invalidHandleTypes[_38];_37=_37&&!this.invalidHandleIds[_36.id];for(var i=0,len=this.invalidHandleClasses.length;_37&&i<len;++i){_37=!YAHOO.util.Dom.hasClass(_36,this.invalidHandleClasses[i]);}return _37;},setXTicks:function(_39,_40){this.xTicks=[];this.xTickSize=_40;var _41={};for(var i=this.initPageX;i>=this.minX;i=i-_40){if(!_41[i]){this.xTicks[this.xTicks.length]=i;_41[i]=true;}}for(i=this.initPageX;i<=this.maxX;i=i+_40){if(!_41[i]){this.xTicks[this.xTicks.length]=i;_41[i]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(_42,_43){this.yTicks=[];this.yTickSize=_43;var _44={};for(var i=this.initPageY;i>=this.minY;i=i-_43){if(!_44[i])!
 {this.yTicks[this.yTicks.length]=i;_44[i]=true;}}for(i=this.initPageY;i<=this.maxY;i=i+_43){if(!_44[i]){this.yTicks[this.yTicks.length]=i;_44[i]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(_45,_46,_47){this.leftConstraint=_45;this.rightConstraint=_46;this.minX=this.initPageX-_45;this.maxX=this.initPageX+_46;if(_47){this.setXTicks(this.initPageX,_47);}this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(iUp,_49,_50){this.topConstraint=iUp;this.bottomConstraint=_49;this.minY=this.initPageY-iUp;this.maxY=this.initPageY+_49;if(_50){this.setYTicks(this.initPageY,_50);}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var dx=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var dy=(this.maintainOffset)?this.lastPageY-this.initPageY:0;!
 this.setInitPosition(dx,dy);}else{this.setInitPosition();}if(this.cons
trainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(val,_52){if(!_52){return val;}else{if(_52[0]>=val){return _52[0];}else{for(var i=0,len=_52.length;i<len;++i){var _53=i+1;if(_52[_53]&&_52[_53]>=val){var _54=val-_52[i];var _55=_52[_53]-val;return (_55>_54)?_52[i]:_52[_53];}}return _52[_52.length-1];}}},toString:function(){return ("DragDrop "+this.id);}};if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=new function(){this.ids={};this.handleIds={};this.dragCurrent=null;this.dragOvers={};this.deltaX=0;this.deltaY=0;this.preventDefault=true;this.stopPropagation=true;this.initalized=false;this.locked=false;this.init=function(){this.initialized=true;};this.POINT=0;this.INTERSECT=1;this.mode=this.POINT;this._execOnAll=function(_56,_57){for(var i in this.ids){for(var j in this.ids[i]){var oDD=this.ids[i][j];if(!this.isTypeOfDD(oDD)!
 ){continue;}oDD[_56].apply(oDD,_57);}}};this._onLoad=function(){this.init();var EU=YAHOO.util.Event;EU.on(document,"mouseup",this.handleMouseUp,this,true);EU.on(document,"mousemove",this.handleMouseMove,this,true);EU.on(window,"unload",this._onUnload,this,true);EU.on(window,"resize",this._onResize,this,true);};this._onResize=function(e){this._execOnAll("resetConstraints",[]);};this.lock=function(){this.locked=true;};this.unlock=function(){this.locked=false;};this.isLocked=function(){return this.locked;};this.locationCache={};this.useCache=true;this.clickPixelThresh=3;this.clickTimeThresh=1000;this.dragThreshMet=false;this.clickTimeout=null;this.startX=0;this.startY=0;this.regDragDrop=function(oDD,_59){if(!this.initialized){this.init();}if(!this.ids[_59]){this.ids[_59]={};}this.ids[_59][oDD.id]=oDD;};this.removeDDFromGroup=function(oDD,_60){if(!this.ids[_60]){this.ids[_60]={};}var obj=this.ids[_60];if(obj&&obj[oDD.id]){delete obj[oDD.id];}};this._remove=function(oDD){for(var!
  g in oDD.groups){if(g&&this.ids[g][oDD.id]){delete this.ids[g][oDD.id
];}}delete this.handleIds[oDD.id];};this.regHandle=function(_63,_64){if(!this.handleIds[_63]){this.handleIds[_63]={};}this.handleIds[_63][_64]=_64;};this.isDragDrop=function(id){return (this.getDDById(id))?true:false;};this.getRelated=function(_65,_66){var _67=[];for(var i in _65.groups){for(j in this.ids[i]){var dd=this.ids[i][j];if(!this.isTypeOfDD(dd)){continue;}if(!_66||dd.isTarget){_67[_67.length]=dd;}}}return _67;};this.isLegalTarget=function(oDD,_69){var _70=this.getRelated(oDD,true);for(var i=0,len=_70.length;i<len;++i){if(_70[i].id==_69.id){return true;}}return false;};this.isTypeOfDD=function(oDD){return (oDD&&oDD.__ygDragDrop);};this.isHandle=function(_71,_72){return (this.handleIds[_71]&&this.handleIds[_71][_72]);};this.getDDById=function(id){for(var i in this.ids){if(this.ids[i][id]){return this.ids[i][id];}}return null;};this.handleMouseDown=function(e,oDD){this.currentTarget=YAHOO.util.Event.getTarget(e);this.dragCurrent=oDD;var el=oDD.getEl();this.startX=YAHO!
 O.util.Event.getPageX(e);this.startY=YAHOO.util.Event.getPageY(e);this.deltaX=this.startX-el.offsetLeft;this.deltaY=this.startY-el.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX,DDM.startY);},this.clickTimeThresh);};this.startDrag=function(x,y){clearTimeout(this.clickTimeout);if(this.dragCurrent){this.dragCurrent.b4StartDrag(x,y);this.dragCurrent.startDrag(x,y);}this.dragThreshMet=true;};this.handleMouseUp=function(e){if(!this.dragCurrent){return;}clearTimeout(this.clickTimeout);if(this.dragThreshMet){this.fireEvents(e,true);}else{}this.stopDrag(e);this.stopEvent(e);};this.stopEvent=function(e){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(e);}if(this.preventDefault){YAHOO.util.Event.preventDefault(e);}};this.stopDrag=function(e){if(this.dragCurrent){if(this.dragThreshMet){this.dragCurrent.b4EndDrag(e);this.dragCurrent.endDrag(e);}this.dragCurrent.onMouseUp(e);}this.dragCurrent=null;this!
 .dragOvers={};};this.handleMouseMove=function(e){if(!this.dragCurrent)
{return true;}if(YAHOO.util.Event.isIE&&!e.button){this.stopEvent(e);return this.handleMouseUp(e);}if(!this.dragThreshMet){var _74=Math.abs(this.startX-YAHOO.util.Event.getPageX(e));var _75=Math.abs(this.startY-YAHOO.util.Event.getPageY(e));if(_74>this.clickPixelThresh||_75>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){this.dragCurrent.b4Drag(e);this.dragCurrent.onDrag(e);this.fireEvents(e,false);}this.stopEvent(e);return true;};this.fireEvents=function(e,_76){var dc=this.dragCurrent;if(!dc||dc.isLocked()){return;}var x=YAHOO.util.Event.getPageX(e);var y=YAHOO.util.Event.getPageY(e);var pt=new YAHOO.util.Point(x,y);var _78=[];var _79=[];var _80=[];var _81=[];var _82=[];for(var i in this.dragOvers){var ddo=this.dragOvers[i];if(!this.isTypeOfDD(ddo)){continue;}if(!this.isOverTarget(pt,ddo,this.mode)){_79.push(ddo);}_78[i]=true;delete this.dragOvers[i];}for(var _84 in dc.groups){if("string"!=typeof _84){continue;}for(i in this.ids[_84])!
 {var oDD=this.ids[_84][i];if(!this.isTypeOfDD(oDD)){continue;}if(oDD.isTarget&&!oDD.isLocked()&&oDD!=dc){if(this.isOverTarget(pt,oDD,this.mode)){if(_76){_81.push(oDD);}else{if(!_78[oDD.id]){_82.push(oDD);}else{_80.push(oDD);}this.dragOvers[oDD.id]=oDD;}}}}}if(this.mode){if(_79.length){dc.b4DragOut(e,_79);dc.onDragOut(e,_79);}if(_82.length){dc.onDragEnter(e,_82);}if(_80.length){dc.b4DragOver(e,_80);dc.onDragOver(e,_80);}if(_81.length){dc.b4DragDrop(e,_81);dc.onDragDrop(e,_81);}}else{var len=0;for(i=0,len=_79.length;i<len;++i){dc.b4DragOut(e,_79[i].id);dc.onDragOut(e,_79[i].id);}for(i=0,len=_82.length;i<len;++i){dc.onDragEnter(e,_82[i].id);}for(i=0,len=_80.length;i<len;++i){dc.b4DragOver(e,_80[i].id);dc.onDragOver(e,_80[i].id);}for(i=0,len=_81.length;i<len;++i){dc.b4DragDrop(e,_81[i].id);dc.onDragDrop(e,_81[i].id);}}};this.getBestMatch=function(dds){var _87=null;var len=dds.length;if(len==1){_87=dds[0];}else{for(var i=0;i<len;++i){var dd=dds[i];if(dd.cursorIsOver){_87=dd;brea!
 k;}else{if(!_87||_87.overlap.getArea()<dd.overlap.getArea()){_87=dd;}}
}}return _87;};this.refreshCache=function(_88){for(sGroup in _88){if("string"!=typeof sGroup){continue;}for(i in this.ids[sGroup]){var oDD=this.ids[sGroup][i];if(this.isTypeOfDD(oDD)){var loc=this.getLocation(oDD);if(loc){this.locationCache[oDD.id]=loc;}else{delete this.locationCache[oDD.id];}}}}};this.verifyEl=function(el){try{if(el){var _90=el.offsetParent;if(_90){return true;}}}catch(e){}return false;};this.getLocation=function(oDD){if(!this.isTypeOfDD(oDD)){return null;}var el=oDD.getEl();var _91=null;try{_91=YAHOO.util.Dom.getXY(el);}catch(e){}if(!_91){return null;}x1=_91[0];x2=x1+el.offsetWidth;y1=_91[1];y2=y1+el.offsetHeight;var t=y1-oDD.padding[0];var r=x2+oDD.padding[1];var b=y2+oDD.padding[2];var l=x1-oDD.padding[3];return new YAHOO.util.Region(t,r,b,l);};this.isOverTarget=function(pt,_96,_97){var loc=this.locationCache[_96.id];if(!loc||!this.useCache){loc=this.getLocation(_96);this.locationCache[_96.id]=loc;}if(!loc){return false;}_96.cursorIsOver=loc.contains(pt)!
 ;var dc=this.dragCurrent;if(!dc||(!_97&&!dc.constrainX&&!dc.constrainY)){return _96.cursorIsOver;}_96.overlap=null;var pos=dc.getTargetCoord(pt.x,pt.y);var el=dc.getDragEl();var _98=new YAHOO.util.Region(pos.y,pos.x+el.offsetWidth,pos.y+el.offsetHeight,pos.x);var _99=_98.intersect(loc);if(_99){_96.overlap=_99;return (_97)?true:_96.cursorIsOver;}else{return false;}};this._onUnload=function(e,me){this.unregAll();};this.unregAll=function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}this._execOnAll("unreg",[]);for(i in this.elementCache){delete this.elementCache[i];}this.elementCache={};this.ids={};};this.elementCache={};this.getElWrapper=function(id){var _101=this.elementCache[id];if(!_101||!_101.el){_101=this.elementCache[id]=new this.ElementWrapper(YAHOO.util.Dom.get(id));}return _101;};this.getElement=function(id){return YAHOO.util.Dom.get(id);};this.getCss=function(id){var el=YAHOO.util.Dom.get(id);return (el)?el.style:null;};this.ElementWrapper=function(e!
 l){this.el=el||null;this.id=this.el&&el.id;this.css=this.el&&el.style;
};this.getPosX=function(el){return YAHOO.util.Dom.getX(el);};this.getPosY=function(el){return YAHOO.util.Dom.getY(el);};this.swapNode=function(n1,n2){if(n1.swapNode){n1.swapNode(n2);}else{var p=n2.parentNode;var s=n2.nextSibling;n1.parentNode.replaceChild(n2,n1);p.insertBefore(n1,s);}};this.getScroll=function(){var t,l;if(document.documentElement&&document.documentElement.scrollTop){t=document.documentElement.scrollTop;l=document.documentElement.scrollLeft;}else{if(document.body){t=document.body.scrollTop;l=document.body.scrollLeft;}}return {top:t,left:l};};this.getStyle=function(el,_105){return YAHOO.util.Dom.getStyle(el,_105);};this.getScrollTop=function(){return this.getScroll().top;};this.getScrollLeft=function(){return this.getScroll().left;};this.moveToEl=function(_106,_107){var _108=YAHOO.util.Dom.getXY(_107);YAHOO.util.Dom.setXY(_106,_108);};this.getClientHeight=function(){return YAHOO.util.Dom.getClientHeight();};this.getClientWidth=function(){return YAHOO.util.Dom.!
 getClientWidth();};this.numericSort=function(a,b){return (a-b);};this._timeoutCount=0;this._addListeners=function(){if(YAHOO.util.Event&&document){this._onLoad();}else{if(this._timeoutCount>1000){}else{var DDM=YAHOO.util.DDM;setTimeout(function(){DDM._addListeners();},10);if(document&&document.body){this._timeoutCount+=1;}}}};this.handleWasClicked=function(node,id){if(this.isHandle(id,node.id)){return true;}else{var p=node.parentNode;while(p){if(this.isHandle(id,p.id)){return true;}else{p=p.parentNode;}}}return false;};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}YAHOO.util.DD=function(id,_111,_112){if(id){this.init(id,_111,_112);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop);YAHOO.util.DD.prototype.scroll=true;YAHOO.util.DD.prototype.autoOffset=function(_113,_114){var x=_113-this.startPageX;var y=_114-this.startPageY;this.setDelta(x,y);};YAHOO.util.DD.prototype.setDelta=function(_115,_116){this.deltaX=_115;this.deltaY=_116;};YAHOO.util.DD.p!
 rototype.setDragElPos=function(_117,_118){var el=this.getDragEl();this
.alignElWithMouse(el,_117,_118);};YAHOO.util.DD.prototype.alignElWithMouse=function(el,_119,_120){var _121=this.getTargetCoord(_119,_120);if(!this.deltaSetXY){var _122=[_121.x,_121.y];YAHOO.util.Dom.setXY(el,_122);var _123=parseInt(YAHOO.util.Dom.getStyle(el,"left"),10);var _124=parseInt(YAHOO.util.Dom.getStyle(el,"top"),10);this.deltaSetXY=[_123-_121.x,_124-_121.y];}else{YAHOO.util.Dom.setStyle(el,"left",(_121.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(el,"top",(_121.y+this.deltaSetXY[1])+"px");}this.cachePosition(_121.x,_121.y);this.autoScroll(_121.x,_121.y,el.offsetHeight,el.offsetWidth);};YAHOO.util.DD.prototype.cachePosition=function(_125,_126){if(_125){this.lastPageX=_125;this.lastPageY=_126;}else{var _127=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=_127[0];this.lastPageY=_127[1];}};YAHOO.util.DD.prototype.autoScroll=function(x,y,h,w){if(this.scroll){var _130=this.DDM.getClientHeight();var _131=this.DDM.getClientWidth();var st=this.DDM.getScrollTop();var!
  sl=this.DDM.getScrollLeft();var bot=h+y;var _135=w+x;var _136=(_130+st-y-this.deltaY);var _137=(_131+sl-x-this.deltaX);var _138=40;var _139=(document.all)?80:30;if(bot>_130&&_136<_138){window.scrollTo(sl,st+_139);}if(y<st&&st>0&&y-st<_138){window.scrollTo(sl,st-_139);}if(_135>_131&&_137<_138){window.scrollTo(sl+_139,st);}if(x<sl&&sl>0&&x-sl<_138){window.scrollTo(sl-_139,st);}}};YAHOO.util.DD.prototype.getTargetCoord=function(_140,_141){var x=_140-this.deltaX;var y=_141-this.deltaY;if(this.constrainX){if(x<this.minX){x=this.minX;}if(x>this.maxX){x=this.maxX;}}if(this.constrainY){if(y<this.minY){y=this.minY;}if(y>this.maxY){y=this.maxY;}}x=this.getTick(x,this.xTicks);y=this.getTick(y,this.yTicks);return {x:x,y:y};};YAHOO.util.DD.prototype.applyConfig=function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);};YAHOO.util.DD.prototype.b4MouseDown=function(e){this.autoOffset(YAHOO.util.Event.getPageX(e),YAHOO.util.Event.getPageY(e));};Y!
 AHOO.util.DD.prototype.b4Drag=function(e){this.setDragElPos(YAHOO.util
.Event.getPageX(e),YAHOO.util.Event.getPageY(e));};YAHOO.util.DD.prototype.toString=function(){return ("DD "+this.id);};YAHOO.util.DDProxy=function(id,_142,_143){if(id){this.init(id,_142,_143);this.initFrame();}};YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD);YAHOO.util.DDProxy.dragElId="ygddfdiv";YAHOO.util.DDProxy.prototype.resizeFrame=true;YAHOO.util.DDProxy.prototype.centerFrame=false;YAHOO.util.DDProxy.prototype.createFrame=function(){var self=this;var body=document.body;if(!body||!body.firstChild){setTimeout(function(){self.createFrame();},50);return;}var div=this.getDragEl();if(!div){div=document.createElement("div");div.id=this.dragElId;var s=div.style;s.position="absolute";s.visibility="hidden";s.cursor="move";s.border="2px solid #aaa";s.zIndex=999;body.insertBefore(div,body.firstChild);}};YAHOO.util.DDProxy.prototype.initFrame=function(){this.createFrame();};YAHOO.util.DDProxy.prototype.applyConfig=function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);thi!
 s.resizeFrame=(this.config.resizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);};YAHOO.util.DDProxy.prototype.showFrame=function(_147,_148){var el=this.getEl();var _149=this.getDragEl();var s=_149.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(s.width,10)/2),Math.round(parseInt(s.height,10)/2));}this.setDragElPos(_147,_148);YAHOO.util.Dom.setStyle(_149,"visibility","visible");};YAHOO.util.DDProxy.prototype._resizeProxy=function(){var DOM=YAHOO.util.Dom;var el=this.getEl();var _151=this.getDragEl();if(this.resizeFrame){var bt=parseInt(DOM.getStyle(_151,"borderTopWidth"),10);var br=parseInt(DOM.getStyle(_151,"borderRightWidth"),10);var bb=parseInt(DOM.getStyle(_151,"borderBottomWidth"),10);var bl=parseInt(DOM.getStyle(_151,"borderLeftWidth"),10);if(isNaN(bt)){bt=0;}if(isNaN(br)){br=0;}if(isNaN(bb)){bb=0;}if(isNaN(bl)){bl=0;}var _156=el.offsetWidth-br-bl;var _157=e!
 l.offsetHeight-bt-bb;DOM.setStyle(_151,"width",_156+"px");DOM.setStyle
(_151,"height",_157+"px");}};YAHOO.util.DDProxy.prototype.b4MouseDown=function(e){var x=YAHOO.util.Event.getPageX(e);var y=YAHOO.util.Event.getPageY(e);this.autoOffset(x,y);this.setDragElPos(x,y);};YAHOO.util.DDProxy.prototype.b4StartDrag=function(x,y){this.showFrame(x,y);};YAHOO.util.DDProxy.prototype.b4EndDrag=function(e){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden");};YAHOO.util.DDProxy.prototype.endDrag=function(e){var DOM=YAHOO.util.Dom;var lel=this.getEl();var del=this.getDragEl();DOM.setStyle(del,"visibility","");DOM.setStyle(lel,"visibility","hidden");YAHOO.util.DDM.moveToEl(lel,del);DOM.setStyle(del,"visibility","hidden");DOM.setStyle(lel,"visibility","");};YAHOO.util.DDProxy.prototype.toString=function(){return ("DDProxy "+this.id);};YAHOO.util.DDTarget=function(id,_160,_161){if(id){this.initTarget(id,_160,_161);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop);YAHOO.util.DDTarget.prototype.toString=function(){return ("DDTarget "+this.id);};
\ No newline at end of file

Added: trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/dragdrop/dragdrop.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,2698 @@
+
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.2
+*/ 
+
+/**
+ * Defines the interface and base operation of items that that can be 
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with 
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that 
+ * was clicked matches a handle element.  By default this is the linked 
+ * element, but there are times that you will want only a portion of the 
+ * linked element to initiate the drag operation, and the setHandleElId() 
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any 
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would 
+ * actually happen if you were to run the code above.  Normally you would 
+ * override this class or one of the default implementations, but you can 
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DragDrop: 
+ *                    padding, isTarget, maintainOffset, primaryButtonOnly
+ */
+YAHOO.util.DragDrop = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config); 
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we 
+     * refer to as the "linked element" because the size and position of 
+     * this element is used to determine when the drag and drop objects have 
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * Configuration attributes passed into the constructor
+     * @type object
+     */
+    config: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same 
+     * as the linked element , but could be changed to another element. Ex: 
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null, 
+
+    /**
+     * the id of the element that initiates the drag operation.  By default 
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the 
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null, 
+
+    /**
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @type {string: string}
+     */
+    invalidHandleTypes: null, 
+
+    /**
+     * An associative array of ids for elements that will be ignored if clicked
+     * @type {string: string}
+     */
+    invalidHandleIds: null, 
+
+    /**
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @type string[]
+     */
+    invalidHandleClasses: null, 
+
+    /**
+     * The linked element's absolute X position at the time the drag was 
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was 
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are 
+     * related.  Instances only get events when interacting with other 
+     * DragDrop object in the same group.  This lets us define multiple 
+     * groups using a single DragDrop subclass if we want.
+     * @type {string: string}
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent 
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @type int[]
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint 
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint 
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the 
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a 
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a 
+     * vertical graduation/interval.  This array is generated automatically 
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @type boolean
+     */
+    available: false,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an 
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over 
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more 
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another 
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items 
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items 
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop 
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this 
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+   
+    /**
+     * Override the onAvailable method to do what is needed after the initial
+     * position was determined.
+     */
+    onAvailable: function () { 
+    },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {HTMLElement} the html element 
+     */
+    getEl: function() { 
+        if (!this._domRef) {
+            this._domRef = YAHOO.util.Dom.get(this.id); 
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another 
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {HTMLElement} the html element 
+     */
+    getDragEl: function() {
+        return YAHOO.util.Dom.get(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    init: function(id, sGroup, config) {
+        this.initTarget(id, sGroup, config);
+        YAHOO.util.Event.addListener(this.id, "mousedown", 
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    initTarget: function(id, sGroup, config) {
+
+        // configuration attributes 
+        this.config = config || {};
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter.
+        this.handleElId = id;
+
+        YAHOO.util.Event.onAvailable(id, this.handleOnAvailable, this, true);
+
+
+        // the linked element is the element that gets dragged by default
+        this.setDragElId(id); 
+
+        // by default, clicked anchors will not start drag operations. 
+        // @TODO what else should be here?  Probably form fields.
+        this.invalidHandleTypes = { A: "A" };
+        this.invalidHandleIds = {};
+        this.invalidHandleClasses = [];
+
+        this.applyConfig();
+    },
+
+    /**
+     * Applies the configuration parameters that were passed into the constructor.
+     * This is supposed to happen at each level through the inheritance chain.  So
+     * a DDProxy implentation will execute apply config on DDProxy, DD, and 
+     * DragDrop in order to get all of the parameters that are available in
+     * each object.
+     */
+    applyConfig: function() {
+
+        // configurable properties: 
+        //    padding, isTarget, maintainOffset, primaryButtonOnly
+        this.padding           = this.config.padding || [0, 0, 0, 0];
+        this.isTarget          = (this.config.isTarget !== false);
+        this.maintainOffset    = (this.config.maintainOffset);
+        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
+
+    },
+
+    /**
+     * Executed when the linked element is available
+     * @private
+     */
+    handleOnAvailable: function() {
+        this.available = true;
+        this.resetConstraints();
+        this.onAvailable();
+    },
+
+     /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.  
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+        this.deltaSetXY = null;
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All 
+     * instances belong to at least one group, and can belong to as many 
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Remove's this instance from the supplied interaction group
+     * @param {string}  sGroup  The group to drop
+     */
+    removeFromGroup: function(sGroup) {
+        if (this.groups[sGroup]) {
+            delete this.groups[sGroup];
+        }
+
+        this.DDM.removeDDFromGroup(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element 
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be 
+     * used to initiate the drag operation.  An example of this would be if 
+     * you have a content div with text and links.  Clicking anywhere in the 
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element 
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag 
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        YAHOO.util.Event.addListener(id, "mousedown", 
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        YAHOO.util.Event.removeListener(this.id, "mousedown", 
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else 
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e 
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+
+        var EU = YAHOO.util.Event;
+
+        var button = e.which || e.button;
+
+        if (this.primaryButtonOnly && button > 1) {
+            return;
+        }
+
+        if (this.isLocked()) {
+            return;
+        }
+
+        this.DDM.refreshCache(this.groups);
+        // var self = this;
+        // setTimeout( function() { self.DDM.refreshCache(self.groups); }, 0);
+
+        // Only process the event if we really clicked within the linked 
+        // element.  The reason we make this check is that in the case that 
+        // another element was moved between the clicked element and the 
+        // cursor in the time between the mousedown and mouseup events. When 
+        // this happens, the element gets the next mousedown event 
+        // regardless of where on the screen it happened.  
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId || 
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+
+                // set the initial element position
+                this.setStartPosition();
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     * 
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Lets you to specify an element id for a child of a drag handle
+     * that should not initiate a drag
+     * @param {string} id the element id of the element you wish to ignore
+     */
+    addInvalidHandleId: function(id) {
+        this.invalidHandleIds[id] = id;
+    },
+
+    /**
+     * Lets you specify a css class of elements that will not initiate a drag
+     * @param {string} cssClass the class of the elements you wish to ignore
+     */
+    addInvalidHandleClass: function(cssClass) {
+        this.invalidHandleClasses.push(cssClass);
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     * 
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        // this.invalidHandleTypes[type] = null;
+        delete this.invalidHandleTypes[type];
+    },
+    
+    /**
+     * Unsets an invalid handle id
+     * @param {string} the id of the element to re-enable
+     */
+    removeInvalidHandleId: function(id) {
+        delete this.invalidHandleIds[id];
+    },
+
+    /**
+     * Unsets an invalid css class
+     * @param {string} the class of the element(s) you wish to re-enable
+     */
+    removeInvalidHandleClass: function(cssClass) {
+        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
+            if (this.invalidHandleClasses[i] == cssClass) {
+                delete this.invalidHandleClasses[i];
+            }
+        }
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+
+        var valid = true;
+        // var n = (node.nodeName == "#text") ? node.parentNode : node;
+        var nodeName;
+        try {
+            nodeName = node.nodeName.toUpperCase();
+        } catch(e) {
+            nodeName = node.nodeName;
+        }
+        valid = valid && !this.invalidHandleTypes[nodeName];
+        valid = valid && !this.invalidHandleIds[node.id];
+
+        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
+            valid = !YAHOO.util.Dom.hasClass(node, this.invalidHandleClasses[i]);
+        }
+
+
+        return valid;
+
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+        
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in 
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use 
+     * this method to limit the horizontal travel of the element.  Pass in 
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the 
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the 
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+    },
+
+    /**
+     * Clears any constraints applied to this instance.  Also clears ticks
+     * since they can't exist independent of a constraint at this time.
+     */
+    clearConstraints: function() {
+        this.constrainX = false;
+        this.constrainY = false;
+        this.clearTicks();
+    },
+
+    /**
+     * Clears any tick interval defined for this instance
+     */
+    clearTicks: function() {
+        this.xTicks = null;
+        this.yTicks = null;
+        this.xTickSize = 0;
+        this.yTickSize = 0;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set 
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the 
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+        
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+
+        // Maintain offsets if necessary
+        if (this.initPageX || this.initPageX === 0) {
+            // figure out how much this thing has moved
+            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+            this.setInitPosition(dx, dy);
+
+        // This is the first time we have detected the element's position
+        } else {
+            this.setInitPosition();
+        }
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint, 
+                                 this.rightConstraint, 
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint, 
+                                 this.bottomConstraint, 
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify 
+     * that it move a number of pixels at a time.  This method resolves the 
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel, 
+            // so we return the value passed to us.
+            return val; 
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i=0, len=tickArray.length; i<len; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function() {
+        return ("DragDrop " + this.id);
+    }
+
+};
+
+// Only load the library once.  Rewriting the manager class would orphan 
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * Handles the element interaction for all DragDrop items in the 
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop 
+     * implementations.  This class should not be instantiated; all methods 
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first 
+         * dimension is the DragDrop item group, the second the DragDrop 
+         * object.
+         *
+         * @type {string: string}
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine 
+         * if the element that generated the mousedown event is actually the 
+         * handle and not the html element itself.
+         *
+         * @type {string: string}
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to 
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events 
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+        
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+            this.initialized = true;
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the 
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the 
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+
+            this.init();
+
+
+            var EU = YAHOO.util.Event;
+
+            EU.on(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.on(document, "mousemove", this.handleMouseMove, this, true);
+            EU.on(window,   "unload",    this._onUnload, this, true);
+            EU.on(window,   "resize",    this._onResize, this, true);
+            // EU.on(window,   "mouseout",    this._test);
+
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the 
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the 
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a 
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a 
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.  
+         * This is executed in DragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+            
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Removes the supplied dd instance from the supplied group. Executed
+         * by DragDrop.removeFromGroup.
+         * @private
+         */
+        this.removeDDFromGroup = function(oDD, sGroup) {
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+
+            var obj = this.ids[sGroup];
+            if (obj && obj[oDD.id]) {
+                delete obj[oDD.id];
+            }
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in 
+         * DragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing DragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag 
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been 
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item, 
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {DragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {DragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for 
+         * the specifice drag obj
+         *
+         * @param {DragDrop} the drag obj
+         * @param {DragDrop) the target
+         * @return {boolean} true if the target is a legal target for the 
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD, true);
+            for (var i=0, len=targets.length;i<len;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof DragDrop, and the exact subclass of DragDrop.  typeof 
+         * returns "object", oDD.constructor.toString() always returns
+         * "DragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in DragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = DragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been 
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false 
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] && 
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+
+            this.currentTarget = YAHOO.util.Event.getTarget(e);
+
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = YAHOO.util.Event.getPageX(e);
+            this.startY = YAHOO.util.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout( 
+                    function() { 
+                        var DDM = YAHOO.util.DDM;
+                        DDM.startDrag(DDM.startX, DDM.startY); 
+                    }, 
+                    this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold 
+         * time threshold has been met.
+         * 
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked 
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.fireEvents(e, true);
+            } else {
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these 
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                YAHOO.util.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                YAHOO.util.Event.preventDefault(e);
+            }
+        };
+
+        /** 
+         * Internal function to clean up event handlers after the drag 
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+        /** 
+         * Internal function to handle the mousemove event.  Will be invoked 
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the 
+         * user drags objects beyond the window boundary.  Currently we can 
+         * detect this in internet explorer by verifying that the mouse is 
+         * down during the mousemove event.  Firefox doesn't give us the 
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                return true;
+            }
+
+            // var button = e.which || e.button;
+
+            // check for IE mouseup outside of page boundary
+            if (YAHOO.util.Event.isIE && !e.button) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - YAHOO.util.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - YAHOO.util.Event.getPageY(e));
+                if (diffX > this.clickPixelThresh || 
+                            diffY > this.clickPixelThresh) {
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+
+            return true;
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are 
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could 
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = YAHOO.util.Event.getPageX(e);
+            var y = YAHOO.util.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object(s) we were hovering over is no longer 
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+                
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length) {
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                var len = 0;
+                for (i=0, len=outEvts.length; i<len; ++i) {
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+                 
+                // fire enter events
+                for (i=0,len=enterEvts.length; i<len; ++i) {
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+         
+                // fire over events
+                for (i=0,len=overEvts.length; i<len; ++i) {
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0, len=dropEvts.length; i<len; ++i) {
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag 
+         * and drop objects returned by the drag and drop events when we are 
+         * in INTERSECT mode.  It returns either the first object that the 
+         * cursor is over, or the object that has the greatest overlap with 
+         * the dragged element.
+         *
+         * @param  {DragDrop[]} dds The array of drag and drop objects 
+         * targeted
+         * @return {DragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            var len = dds.length;
+
+            if (len == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<len; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the 
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner || 
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the 
+         * drag and drop objects in the specified groups
+         *
+         * @param {Object} groups an associative array of groups to refresh
+         */
+        this.refreshCache = function(groups) {
+            for (sGroup in groups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            // oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+            }
+
+            return false;
+        };
+        
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the DragDrop.padding configured for it
+         *
+         * @param {DragDrop} oDD the drag and drop object to get the 
+         * location for
+         * @return array containing the top left and bottom right points of the 
+         * element 
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            // element will not have an offsetparent if it was removed from the
+            // document or display=none
+            // if (!this.verifyEl(el)) {
+                // return null;
+            // }
+
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = null;
+            try {
+                aPos= YAHOO.util.Dom.getXY(el);
+            } catch (e) { }
+
+            if (!aPos) {
+                return null;
+            }
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         * 
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {DragDrop} oTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oTarget.id];
+            if (!loc || !this.useCache) {
+                loc = this.getLocation(oTarget);
+                this.locationCache[oTarget.id] = loc;
+
+            }
+
+            if (!loc) {
+                return false;
+            }
+
+            oTarget.cursorIsOver = loc.contains( pt );
+
+            // DragDrop is using this as a sanity check for the initial mousedown
+            // in this case we are done.  In POINT mode, if the drag obj has no
+            // contraints, we are also done. Otherwise we need to evaluate the 
+            // location of the target as related to the actual location of the
+            // dragged element.
+            var dc = this.dragCurrent;
+            if (!dc || (!intersect && !dc.constrainX && !dc.constrainY)) {
+                return oTarget.cursorIsOver;
+            }
+
+            oTarget.overlap = null;
+
+            // Get the current location of the drag element, this is the
+            // location of the mouse event less the delta that represents
+            // where the original mousedown happened on the element.  We
+            // need to consider constraints and ticks as well.
+            var pos = dc.getTargetCoord(pt.x, pt.y);
+
+            var el = dc.getDragEl();
+            var curRegion = new YAHOO.util.Region( pos.y, 
+                                                   pos.x + el.offsetWidth,
+                                                   pos.y + el.offsetHeight, 
+                                                   pos.x );
+
+            var overlap = curRegion.intersect(loc);
+
+            if (overlap) {
+                oTarget.overlap = overlap;
+                return (intersect) ? true : oTarget.cursorIsOver;
+            } else {
+                return false;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         * @private
+         */
+        this.unregAll = function() {
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         * @private
+         */
+        this.elementCache = {};
+        
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         * @deprecated
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                oWrapper = this.elementCache[id] = 
+                    new this.ElementWrapper(YAHOO.util.Dom.get(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         * @deprecated
+         */
+        this.getElement = function(id) {
+            return YAHOO.util.Dom.get(id);
+        };
+        
+        /**
+         * Returns the style property for the DOM element (i.e., 
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         * @deprecated
+         */
+        this.getCss = function(id) {
+            var el = YAHOO.util.Dom.get(id);
+            return (el) ? el.style : null;
+        };
+
+        /**
+         * Inner class for cached elements
+         * @private
+         * @deprecated
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         * @deprecated
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         * @deprecated
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el); 
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we 
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky. 
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2, n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string} The value of the style property
+         * @deprecated, use YAHOO.util.Dom.getStyle
+         */
+        this.getStyle = function(el, styleProp) {
+            return YAHOO.util.Dom.getStyle(el, styleProp);
+        };
+
+        /**
+         * Gets the scrollTop
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        /**
+         * Sets the x/y position of an element to the location of the
+         * target element.
+         * @param {HTMLElement} moveEl      The element to move
+         * @param {HTMLElement} targetEl    The position reference element
+         */
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         * @return {int} client height in px
+         * @deprecated
+         */
+        this.getClientHeight = function() {
+            return YAHOO.util.Dom.getClientHeight();
+        };
+
+        /**
+         * Gets the client width
+         * @return {int} client width in px
+         * @deprecated
+         */
+        this.getClientWidth = function() {
+            return YAHOO.util.Dom.getClientWidth();
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         * @private
+         */
+        this._addListeners = function() {
+            if ( YAHOO.util.Event && document ) {
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 1000) {
+                } else {
+                    var DDM = YAHOO.util.DDM;
+                    setTimeout( function() { DDM._addListeners(); }, 10);
+                    if (document && document.body) {
+                        this._timeoutCount += 1;
+                    }
+                }
+            }
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for 
+         * the handle element in order to determine wheter or not it was 
+         * clicked.
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    } ();
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/**
+ * A DragDrop implementation where the linked element follows the 
+ * mouse cursor during a drag.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element 
+ * @param {String} sGroup the group of related DragDrop items
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DD: 
+ *                    scroll
+ */
+YAHOO.util.DD = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+    }
+};
+
+// YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+YAHOO.extend(YAHOO.util.DD, YAHOO.util.DragDrop);
+
+/**
+ * When set to true, the utility automatically tries to scroll the browser
+ * window wehn a drag and drop element is dragged near the viewport boundary.
+ * Defaults to true.
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true; 
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top 
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    // var el = this.getEl();
+    // var aCoord = YAHOO.util.Dom.getXY(el);
+    // var x = iPageX - aCoord[0];
+    // var y = iPageY - aCoord[1];
+    var x = iPageX - this.startPageX;
+    var y = iPageY - this.startPageY;
+    this.setDelta(x, y);
+};
+
+/** 
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in YAHOO.widget.Slider)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event, 
+ * maintaining the cursor location relative to the location on the element 
+ * that was clicked.  Override this if you want to place the element in a 
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    // the first time we do this, we are going to check to make sure
+    // the element has css positioning
+
+    var el = this.getDragEl();
+
+    // if (!this.cssVerified) {
+        // var pos = el.style.position;
+    // }
+
+    this.alignElWithMouse(el, iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event, 
+ * maintaining the cursor location relative to the location on the element 
+ * that was clicked.  Override this if you want to place the element in a 
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+
+    // this.deltaSetXY = null;
+    if (!this.deltaSetXY) {
+        var aCoord = [oCoord.x, oCoord.y];
+        YAHOO.util.Dom.setXY(el, aCoord);
+        var newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
+        var newTop  = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
+
+        this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
+
+    } else {
+        YAHOO.util.Dom.setStyle(el, "left", (oCoord.x + this.deltaSetXY[0]) + "px");
+        YAHOO.util.Dom.setStyle(el, "top",  (oCoord.y + this.deltaSetXY[1]) + "px");
+    }
+    
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the 
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area, 
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce 
+        // clunky scrolling. IE is more sensitive about this ... it needs this 
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the 
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) { 
+            window.scrollTo(sl, st + scrAmt); 
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) { 
+            window.scrollTo(sl, st - scrAmt); 
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) { 
+            window.scrollTo(sl + scrAmt, st); 
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) { 
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+
+    return {x:x, y:y};
+};
+
+YAHOO.util.DD.prototype.applyConfig = function() {
+    YAHOO.util.DD.superclass.applyConfig.call(this);
+    this.scroll = (this.config.scroll !== false);
+};
+
+/** 
+ * Event that fires prior to the onMouseDown event.  Overrides 
+ * YAHOO.util.DragDrop.
+ */
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e), 
+                        YAHOO.util.Event.getPageY(e));
+};
+
+/** 
+ * Event that fires prior to the onDrag event.  Overrides 
+ * YAHOO.util.DragDrop.
+ */
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e), 
+                        YAHOO.util.Event.getPageY(e));
+};
+
+YAHOO.util.DD.prototype.toString = function() {
+    return ("DD " + this.id);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+};
+*/
+
+/**
+ * A DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * References to the "frame" element refer to the single proxy element that
+ * was created to be dragged in place of all DDProxy elements on the
+ * page.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DDProxy in addition to those in DragDrop: 
+ *                   resizeFrame, centerFrame, dragElId
+ */
+YAHOO.util.DDProxy = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+        this.initFrame(); 
+    }
+};
+
+YAHOO.extend(YAHOO.util.DDProxy, YAHOO.util.DD);
+
+/**
+ * The default drag frame div id
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior.
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.prototype.createFrame = function() {
+    var self = this;
+    var body = document.body;
+
+    if (!body || !body.firstChild) {
+        setTimeout( function() { self.createFrame(); }, 50 );
+        return;
+    }
+
+    var div = this.getDragEl();
+
+    if (!div) {
+        div    = document.createElement("div");
+        div.id = this.dragElId;
+        var s  = div.style;
+
+        s.position   = "absolute";
+        s.visibility = "hidden";
+        s.cursor     = "move";
+        s.border     = "2px solid #aaa";
+        s.zIndex     = 999;
+
+        // appendChild can blow up IE if invoked prior to the window load event
+        // while rendering a table.  It is possible there are other scenarios 
+        // that would cause this to happen as well.
+        body.insertBefore(div, body.firstChild);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    // YAHOO.util.DDProxy.createFrame();
+    // this.setDragElId(YAHOO.util.DDProxy.dragElId);
+
+    this.createFrame();
+
+};
+
+YAHOO.util.DDProxy.prototype.applyConfig = function() {
+    YAHOO.util.DDProxy.superclass.applyConfig.call(this);
+
+    this.resizeFrame = (this.config.resizeFrame !== false);
+    this.centerFrame = (this.config.centerFrame);
+    this.setDragElId(this.config.dragElId || YAHOO.util.DDProxy.dragElId);
+
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions 
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var dragEl = this.getDragEl();
+    var s = dragEl.style;
+
+    this._resizeProxy();
+
+    if (this.centerFrame) {
+        this.setDelta( Math.round(parseInt(s.width,  10)/2), 
+                       Math.round(parseInt(s.height, 10)/2) );
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    YAHOO.util.Dom.setStyle(dragEl, "visibility", "visible"); 
+};
+
+YAHOO.util.DDProxy.prototype._resizeProxy = function() {
+    var DOM    = YAHOO.util.Dom;
+    var el     = this.getEl();
+    var dragEl = this.getDragEl();
+
+    if (this.resizeFrame) {
+        var bt = parseInt( DOM.getStyle(dragEl, "borderTopWidth"    ), 10);
+        var br = parseInt( DOM.getStyle(dragEl, "borderRightWidth"  ), 10);
+        var bb = parseInt( DOM.getStyle(dragEl, "borderBottomWidth" ), 10);
+        var bl = parseInt( DOM.getStyle(dragEl, "borderLeftWidth"   ), 10);
+
+        if (isNaN(bt)) { bt = 0; }
+        if (isNaN(br)) { br = 0; }
+        if (isNaN(bb)) { bb = 0; }
+        if (isNaN(bl)) { bl = 0; }
+
+
+        var newWidth  = el.offsetWidth - br - bl;
+        var newHeight = el.offsetHeight - bt - bb;
+
+
+        DOM.setStyle( dragEl, "width",  newWidth  + "px" );
+        DOM.setStyle( dragEl, "height", newHeight + "px" );
+    }
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+    YAHOO.util.Dom.setStyle(this.getDragEl(), "visibility", "hidden"); 
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.  
+// This is so that the default behavior mirrors that of YAHOO.util.DD.  
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    var DOM = YAHOO.util.Dom;
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    // del.style.visibility = "";
+    DOM.setStyle(del, "visibility", ""); 
+
+    // Hide the linked element before the move to get around a Safari 
+    // rendering bug.
+    //lel.style.visibility = "hidden";
+    DOM.setStyle(lel, "visibility", "hidden"); 
+    YAHOO.util.DDM.moveToEl(lel, del);
+    //del.style.visibility = "hidden";
+    DOM.setStyle(del, "visibility", "hidden"); 
+    //lel.style.visibility = "";
+    DOM.setStyle(lel, "visibility", ""); 
+};
+
+YAHOO.util.DDProxy.prototype.toString = function() {
+    return ("DDProxy " + this.id);
+};
+
+/**
+ * A DragDrop implementation that does not move, but can be a drop 
+ * target.  You would get the same result by simply omitting implementation 
+ * for the event callbacks, but this way we reduce the processing cost of the 
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop 
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DDTarget in addition to those in DragDrop: 
+ *                  none
+ */
+ 
+YAHOO.util.DDTarget = function(id, sGroup, config) {
+    if (id) {
+        this.initTarget(id, sGroup, config);
+    }
+};
+
+// YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+YAHOO.extend(YAHOO.util.DDTarget, YAHOO.util.DragDrop);
+
+YAHOO.util.DDTarget.prototype.toString = function() {
+    return ("DDTarget " + this.id);
+};
+

Added: trunk/theme/src/bin/portal-ajax-war/js/event/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/event/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/event/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,55 @@
+
+YUI Library - Event - Release Notes
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via 
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to 
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in 
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method 
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).

Added: trunk/theme/src/bin/portal-ajax-war/js/event/event-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/event/event-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/event/event-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,1232 @@
+
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
+Code licensed under the BSD License:                                                                                                                    
+http://developer.yahoo.net/yui/license.txt                                                                                                              
+version: 0.11.0                                                                                                                                         
+*/ 
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String} type The type of event, which is passed to the callback
+ *                 when the event fires
+ * @param {Object} oScope The context the event will fire from.  "this" will
+ *                 refer to this object in the callback.  Default value: 
+ *                 the window object.  The listener can override this.
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window 
+     * obj
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    // Register with the event utility for automatic cleanup.  Made optional
+    // so that CustomEvent can be used independently of pe.event
+    if (YAHOO.util.Event) { 
+        YAHOO.util.Event.regCE(this);
+    }
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     *   
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " + 
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,                 
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(i);
+        }
+    },
+
+    /**
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        delete this.subscribers[index];
+    },
+
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " + 
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+    /**
+     * The callback that will be execute when the event fires
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this 
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  + 
+           ", override: " +  (this.override || "no") + " }";
+};
+// Only load this library once.  If it is loaded a second time, existing
+// events cannot be detached.
+if (!YAHOO.util.Event) {
+
+/**
+ * @class
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @constructor
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of the custom events that have been defined.  Used for
+         * automatic cleanup
+         * @type array
+         * @private
+         */
+        var customEvents = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200 at 50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a 
+             * parameter to the callback, int constant
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the 
+             * handler.  There is not a capabilities check we can use here.
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.  
+             * capabilities checking didn't seem to work because another 
+             * browser that does not provide the properties have the values 
+             * calculated in a different manner than IE.
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             * @param {string} p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object} p_obj an optional object to be passed back as
+             * a parameter to p_fn.
+             * @param {boolean} p_override If set to true, p_fn will execute
+             * in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id, 
+                                     fn:       p_fn, 
+                                     obj:      p_obj, 
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @param {Object}   el        The html element to assign the 
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be 
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements 
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i], 
+                                       sType, 
+                                       fn, 
+                                       oScope, 
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is 
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we 
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event 
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el, 
+                                                sType, 
+                                                fn, 
+                                                oScope, 
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get 
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events 
+                // prior to automatically unhooking them.  So we hang on to 
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e), 
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    if (legacyIndex == -1) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and 
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] = 
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] = 
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    legacyHandlers[legacyIndex].push(index);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id + 
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+                
+            },
+
+            /**
+             * Shorthand for YAHOO.util.Event.addListener
+             * @type function
+             */
+            // on: this.addListener,
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var index = le[i];
+                    // this.logger.debug(index);
+                    if (index) {
+                        var li = listeners[index];
+                        if ( li && li[this.WFN] ) {
+                            var scope = li[this.ADJ_SCOPE];
+                            var ret = li[this.WFN].call(scope, e);
+                            ok = (ok && ret);
+                        } else {
+                            // This listener was removed, so delete it from
+                            // the array
+                            delete le[i];
+                        }
+                        // this.logger.debug(ok);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied 
+             * signature
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                /*
+                for (var i=0,len=legacyEvents.length; i<len; ++i) {
+                    var le = legacyEvents[i];
+                    if (le && le[0] === el && le[1] === sType) {
+                        return i;
+                    }
+                }
+                return -1;
+                */
+
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") { 
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+
+                return false;
+            },
+                    
+            /**
+             * Removes an event handler
+             *
+             * @param {Object} el the html element or the id of the element to 
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false 
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li && 
+                            li[0] == el && 
+                            li[1] == sType && 
+                            li[2] == fn) {
+                                delete unloadListeners[i];
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+  
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                delete listeners[index];
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a 
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName && 
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target 
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) { 
+                        // can't set the time property  
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+             
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event 
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * @private
+             * Locating the saved event handler data by function ref
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 && 
+                         li[this.FN] == fn  && 
+                         li[this.EL] == el  && 
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already 
+             * have one.
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different 
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also 
+             * fail if the object is an array, but is empty.
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event 
+             * fires, we can no longer use document.getElementById
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * Called by CustomEvent instances to provide a handle to the 
+             * event * that can be removed later on.  Should be package 
+             * protected.
+             * @private
+             */
+            regCE: function(ce) {
+                customEvents.push(ce);
+            },
+
+            /**
+             * @private
+             * hook up any deferred listeners
+             */
+            _load: function(e) {
+                // me.logger = new ygLogger("pe.Event");
+                //me.logger.debug([this.isSafari, this.isOpera, this.isIE]);
+                loadComplete = true;
+            },
+
+            /**
+             * Polling function that runs before the onload event fires, 
+             * attempting to attach to DOM Nodes as soon as they are 
+             * available
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to 
+                // check the page load state prior to trying to bind the 
+                // elements so that we can be certain all elements have been 
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to 
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN], 
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 && 
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        this.removeListener(el, l.type, l.fn, l.index);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @param el {HTMLElement} the element to inspect 
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */           
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el && 
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called 
+             * automatically during the unload event.
+             * @private
+             */
+            _unload: function(e, me) {
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    for (i=0,len=listeners.length; i<len ; ++i) {
+                        l = listeners[i];
+                        if (l) {
+                            this.removeListener(l[this.EL], l[this.TYPE], 
+                                    l[this.FN], i);
+                        }
+                    }
+
+                    this.clearCache();
+                }
+
+                for (i=0,len=customEvents.length; i<len; ++i) {
+                    customEvents[i].unsubscribeAll();
+                    delete customEvents[i];
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+            },
+
+            /**
+             * Returns scrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the 
+             * pageX and pageY in Internet Explorer
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement; db = document.body;
+                if (dd && dd.scrollTop) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            }
+        };
+    } ();
+
+    /**
+     * @private
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, 
+                YAHOO.util.Event, true);
+    }
+
+    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, 
+                YAHOO.util.Event, true);
+
+    YAHOO.util.Event._tryPreloadAttach();
+
+}
+

Added: trunk/theme/src/bin/portal-ajax-war/js/event/event-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/event/event-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/event/event-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1 @@
+/*                                                                                                                                                      Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    Code licensed under the BSD License:                                                                                                                    http://developer.yahoo.net/yui/license.txt                                                                                                              version: 0.11.0                                                                                                                                         */ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(YAHOO.util.Event){YAHOO.util.Event.regCE(this);}if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscrib!
 e:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}delete this.subscribers[_14];},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(f!
 n,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.pro
totype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=[];var _24=0;var _25=[];var _26=[];var _27=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_29,fn,_30,_31){_19[_19.length]=[el,_29,fn,_30,_31];if(_17){_24=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_32){var i=(_32||_32===0)?_32:this.POLL_INTERVAL;var _33=this;var _34=function(){_33._tryPreloadAttach();};this.timeout=setTimeout(_34,i);},onAvailable:function(_35,_36,_37,_38){_25.push({id:_35,fn:_36,obj:_37,override:_38});_24=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_39,fn!
 ,_40,_41){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_39,fn,_40,_41)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_39,fn,_40,_41);return true;}}}if(!el){return false;}if("unload"==_39&&_40!==this){_20[_20.length]=[el,_39,fn,_40,_41];return true;}var _44=(_41)?_40:el;var _45=function(e){return fn.call(_44,YAHOO.util.Event.getEvent(e),_40);};var li=[el,_39,fn,_45,_44];var _48=_18.length;_18[_48]=li;if(this.useLegacyEvent(el,_39)){var _49=this.getLegacyIndex(el,_39);if(_49==-1){_49=_22.length;_26[el.id+_39]=_49;_22[_49]=[el,_39,el["on"+_39]];_23[_49]=[];el["on"+_39]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_49);};}_23[_49].push(_48);}else{if(el.addEventListener){el.addEventListener(_39,_45,false);}else{if(el.attachEvent){el.attachEvent("on"+_39,_45);}}}return true;},fireLegacyEvent:!
 function(e,_50){var ok=true;var le=_23[_50];for(var i=0,len=le.length;
i<len;++i){var _52=le[i];if(_52){var li=_18[_52];if(li&&li[this.WFN]){var _53=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_53,e);ok=(ok&&ret);}else{delete le[i];}}}return ok;},getLegacyIndex:function(el,_55){var key=this.generateId(el)+_55;if(typeof _26[key]=="undefined"){return -1;}else{return _26[key];}},useLegacyEvent:function(el,_57){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_57||"dblclick"==_57){return true;}}}return false;},removeListener:function(el,_58,fn,_59){if(!fn||!fn.call){return false;}if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_58,fn)&&ok);}return ok;}}if("unload"==_58){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_58&&li[2]==fn){delete _20[i];return true;}}return false;}var _60=null;if("undefined"==typeof _59){_59=this._getCacheIndex(el,_58,fn);}if(_59>=0){_60=_18[_59];!
 }if(!el||!_60){return false;}if(el.removeEventListener){el.removeEventListener(_58,_60[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_58,_60[this.WFN]);}}delete _18[_59][this.WFN];delete _18[_59][this.FN];delete _18[_59];return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.t!
 ime){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}ret
urn ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_27;++_27;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementB!
 yId(id);},clearCache:function(){},regCE:function(ce){_21.push(ce);},_load:function(e){_17=true;},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_24>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_25.length;i<len;++i){var _76=_25[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _25[i];}else{_75.push(_76);}}}_24=(_73.length===0&&_75.length===0)?0:_24-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn,l.index);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.!
 childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if
(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e,me){for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _85=(l[this.ADJ_SCOPE])?l[this.SCOPE]:window;l[this.FN].call(_85,this.getEvent(e),l[this.SCOPE]);}}if(_18&&_18.length>0){for(i=0,len=_18.length;i<len;++i){l=_18[i];if(l){this.removeListener(l[this.EL],l[this.TYPE],l[this.FN],i);}}this.clearCache();}for(i=0,len=_21.length;i<len;++i){_21[i].unsubscribeAll();delete _21[i];}for(i=0,len=_22.length;i<len;++i){delete _22[i][0];delete _22[i];}},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement;db=document.body;if(dd&&dd.scrollTop){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.s!
 crollTop,db.scrollLeft];}else{return [0,0];}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event.on(window,"load",YAHOO.util.Event._load,YAHOO.util.Event,true);}YAHOO.util.Event.on(window,"unload",YAHOO.util.Event._unload,YAHOO.util.Event,true);YAHOO.util.Event._tryPreloadAttach();}
\ No newline at end of file

Added: trunk/theme/src/bin/portal-ajax-war/js/event/event.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/event/event.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/event/event.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,1200 @@
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
+Code licensed under the BSD License:                                                                                                                    
+http://developer.yahoo.net/yui/license.txt                                                                                                              
+version: 0.11.0                                                                                                                                         
+*/ 
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String} type The type of event, which is passed to the callback
+ *                 when the event fires
+ * @param {Object} oScope The context the event will fire from.  "this" will
+ *                 refer to this object in the callback.  Default value: 
+ *                 the window object.  The listener can override this.
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window 
+     * obj
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    // Register with the event utility for automatic cleanup.  Made optional
+    // so that CustomEvent can be used independently of pe.event
+    if (YAHOO.util.Event) { 
+        YAHOO.util.Event.regCE(this);
+    }
+
+    if (!this.silent) {
+    }
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     *   
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(i);
+        }
+    },
+
+    /**
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        delete this.subscribers[index];
+    },
+
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " + 
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+    /**
+     * The callback that will be execute when the event fires
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this 
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  + 
+           ", override: " +  (this.override || "no") + " }";
+};
+// Only load this library once.  If it is loaded a second time, existing
+// events cannot be detached.
+if (!YAHOO.util.Event) {
+
+/**
+ * @class
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @constructor
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of the custom events that have been defined.  Used for
+         * automatic cleanup
+         * @type array
+         * @private
+         */
+        var customEvents = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200 at 50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a 
+             * parameter to the callback, int constant
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the 
+             * handler.  There is not a capabilities check we can use here.
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.  
+             * capabilities checking didn't seem to work because another 
+             * browser that does not provide the properties have the values 
+             * calculated in a different manner than IE.
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             * @param {string} p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object} p_obj an optional object to be passed back as
+             * a parameter to p_fn.
+             * @param {boolean} p_override If set to true, p_fn will execute
+             * in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id, 
+                                     fn:       p_fn, 
+                                     obj:      p_obj, 
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @param {Object}   el        The html element to assign the 
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be 
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements 
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i], 
+                                       sType, 
+                                       fn, 
+                                       oScope, 
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is 
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we 
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event 
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el, 
+                                                sType, 
+                                                fn, 
+                                                oScope, 
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get 
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events 
+                // prior to automatically unhooking them.  So we hang on to 
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e), 
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    if (legacyIndex == -1) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and 
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] = 
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] = 
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    legacyHandlers[legacyIndex].push(index);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+                
+            },
+
+            /**
+             * Shorthand for YAHOO.util.Event.addListener
+             * @type function
+             */
+            // on: this.addListener,
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var index = le[i];
+                    if (index) {
+                        var li = listeners[index];
+                        if ( li && li[this.WFN] ) {
+                            var scope = li[this.ADJ_SCOPE];
+                            var ret = li[this.WFN].call(scope, e);
+                            ok = (ok && ret);
+                        } else {
+                            // This listener was removed, so delete it from
+                            // the array
+                            delete le[i];
+                        }
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied 
+             * signature
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                /*
+                for (var i=0,len=legacyEvents.length; i<len; ++i) {
+                    var le = legacyEvents[i];
+                    if (le && le[0] === el && le[1] === sType) {
+                        return i;
+                    }
+                }
+                return -1;
+                */
+
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") { 
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+
+                return false;
+            },
+                    
+            /**
+             * Removes an event handler
+             *
+             * @param {Object} el the html element or the id of the element to 
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false 
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li && 
+                            li[0] == el && 
+                            li[1] == sType && 
+                            li[2] == fn) {
+                                delete unloadListeners[i];
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+  
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                delete listeners[index];
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a 
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName && 
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target 
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) { 
+                        // can't set the time property  
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+             
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event 
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * @private
+             * Locating the saved event handler data by function ref
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 && 
+                         li[this.FN] == fn  && 
+                         li[this.EL] == el  && 
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already 
+             * have one.
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different 
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also 
+             * fail if the object is an array, but is empty.
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event 
+             * fires, we can no longer use document.getElementById
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * Called by CustomEvent instances to provide a handle to the 
+             * event * that can be removed later on.  Should be package 
+             * protected.
+             * @private
+             */
+            regCE: function(ce) {
+                customEvents.push(ce);
+            },
+
+            /**
+             * @private
+             * hook up any deferred listeners
+             */
+            _load: function(e) {
+                loadComplete = true;
+            },
+
+            /**
+             * Polling function that runs before the onload event fires, 
+             * attempting to attach to DOM Nodes as soon as they are 
+             * available
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to 
+                // check the page load state prior to trying to bind the 
+                // elements so that we can be certain all elements have been 
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to 
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN], 
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 && 
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        this.removeListener(el, l.type, l.fn, l.index);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @param el {HTMLElement} the element to inspect 
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */           
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el && 
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called 
+             * automatically during the unload event.
+             * @private
+             */
+            _unload: function(e, me) {
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    for (i=0,len=listeners.length; i<len ; ++i) {
+                        l = listeners[i];
+                        if (l) {
+                            this.removeListener(l[this.EL], l[this.TYPE], 
+                                    l[this.FN], i);
+                        }
+                    }
+
+                    this.clearCache();
+                }
+
+                for (i=0,len=customEvents.length; i<len; ++i) {
+                    customEvents[i].unsubscribeAll();
+                    delete customEvents[i];
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+            },
+
+            /**
+             * Returns scrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the 
+             * pageX and pageY in Internet Explorer
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement; db = document.body;
+                if (dd && dd.scrollTop) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            }
+        };
+    } ();
+
+    /**
+     * @private
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, 
+                YAHOO.util.Event, true);
+    }
+
+    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, 
+                YAHOO.util.Event, true);
+
+    YAHOO.util.Event._tryPreloadAttach();
+
+}
+

Added: trunk/theme/src/bin/portal-ajax-war/js/logger/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/logger/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/logger/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,6 @@
+Logger Release Notes
+
+*** version 0.11.0 ***
+
+* Initial release
+

Added: trunk/theme/src/bin/portal-ajax-war/js/logger/assets/logger.css
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/logger/assets/logger.css	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/logger/assets/logger.css	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,20 @@
+/* logger default styles */
+/* font size is controlled here: default 77% */
+#yui-log {position:absolute;top:1em;right:1em;font-size:77%;text-align:left;}
+/* width is controlled here: default 31em */
+.yui-log {padding:1em;width:31em;background-color:#AAA;border:1px solid black;font-family:monospace;z-index:9000;}
+.yui-log p {margin:1px;padding:.1em;}
+.yui-log button {font-family:monospace;}
+.yui-log .yui-log-hd {margin-top:1em;padding:.5em;background-color:#575757;color:#FFF;}
+/* height is controlled here: default 20em*/
+.yui-log .yui-log-bd {width:100%;height:20em;background-color:#FFF;border:1px solid gray;overflow:auto;}
+.yui-log .yui-log-ft {margin-top:.5em;margin-bottom:1em;}
+.yui-log .yui-log-ft .yui-log-categoryfilters {}
+.yui-log .yui-log-ft .yui-log-sourcefilters {width:100%;border-top:1px solid #575757;margin-top:.75em;padding-top:.75em;}
+.yui-log .yui-log-btns {position:relative;float:right;bottom:.25em;}
+.yui-log .yui-log-filtergrp {margin-right:.5em;}
+.yui-log .info {background-color:#A7CC25;} /* A7CC25 green */
+.yui-log .warn {background-color:#F58516;} /* F58516 orange */
+.yui-log .error {background-color:#E32F0B;} /* E32F0B red */
+.yui-log .time {background-color:#A6C9D7;} /* A6C9D7 blue */
+.yui-log .window {background-color:#F2E886;} /* F2E886 tan */

Added: trunk/theme/src/bin/portal-ajax-war/js/logger/logger-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/logger/logger-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/logger/logger-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,1186 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/**
+ * Singleton providing core logging functionality. Saves logs written through the
+ * global YAHOO.log function or written by LogWriter. Provides access to logs
+ * for reading by LogReader. Log messages are automatically output to Firebug,
+ * if present.
+ *
+ * requires YAHOO.util.Event Event utility
+ */
+YAHOO.widget.Logger = {
+    // Initialize members
+    loggerEnabled: true,
+    _firebugEnabled: true,
+    categories: ["info","warn","error","time","window"],
+    sources: ["global"],
+    _stack: [], // holds all log msgs
+    _startTime: new Date().getTime(), // static start timestamp
+    _lastTime: null // timestamp of last logged message
+};
+
+/***************************************************************************
+ * Events
+ ***************************************************************************/
+/**
+ * Fired when a new category has been created. Subscribers receive the following
+ * array:<br>
+ *     - args[0] The category name
+ */
+YAHOO.widget.Logger.categoryCreateEvent = new YAHOO.util.CustomEvent("categoryCreate", this, true);
+
+/**
+ * Fired when a new source has been named. Subscribers receive the following
+ * array:<br>
+ *     - args[0] The source name
+ */
+YAHOO.widget.Logger.sourceCreateEvent = new YAHOO.util.CustomEvent("sourceCreate", this, true);
+
+/**
+ * Fired when a new log message has been created. Subscribers receive the
+ * following array:<br>
+ *     - args[0] The log message
+ */
+YAHOO.widget.Logger.newLogEvent = new YAHOO.util.CustomEvent("newLog", this, true);
+
+/**
+ * Fired when the Logger has been reset has been created.
+ */
+YAHOO.widget.Logger.logResetEvent = new YAHOO.util.CustomEvent("logReset", this, true);
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+/**
+ * Saves a log message to the stack and fires newLogEvent. If the log message is
+ * assigned to an unknown category, creates a new category. If the log message is
+ * from an unknown source, creates a new source.  If Firebug is enabled,
+ * outputs the log message to Firebug.
+ *
+ * @param {string} sMsg The log message
+ * @param {string} sCategory Category of log message, or null
+ * @param {string} sSource Source of LogWriter, or null if global
+ */
+YAHOO.widget.Logger.log = function(sMsg, sCategory, sSource) {
+    if(this.loggerEnabled) {
+        if(!sCategory) {
+            sCategory = "info"; // default category
+        }
+        else if(this._isNewCategory(sCategory)) {
+            this._createNewCategory(sCategory);
+        }
+        var sClass = "global"; // default source
+        var sDetail = null;
+        if(sSource) {
+            var spaceIndex = sSource.indexOf(" ");
+            if(spaceIndex > 0) {
+                sClass = sSource.substring(0,spaceIndex);// substring until first space
+                sDetail = sSource.substring(spaceIndex,sSource.length);// the rest of the source
+            }
+            else {
+                sClass = sSource;
+            }
+            if(this._isNewSource(sClass)) {
+                this._createNewSource(sClass);
+            }
+        }
+
+        var timestamp = new Date();
+        var logEntry = {
+            time: timestamp,
+            category: sCategory,
+            source: sClass,
+            sourceDetail: sDetail,
+            msg: sMsg
+        };
+
+        this._stack.push(logEntry);
+        this.newLogEvent.fire(logEntry);
+
+        if(this._firebugEnabled) {
+            this._printToFirebug(logEntry);
+        }
+        return true;
+    }
+    else {
+        return false;
+    }
+};
+
+/**
+ * Resets internal stack and startTime, enables Logger, and fires logResetEvent.
+ *
+ */
+YAHOO.widget.Logger.reset = function() {
+    this._stack = [];
+    this._startTime = new Date().getTime();
+    this.loggerEnabled = true;
+    this.log(null, "Logger reset");
+    this.logResetEvent.fire();
+};
+
+/**
+ * Public accessor to internal stack of log messages.
+ *
+ * @return {array} Array of log messages.
+ */
+YAHOO.widget.Logger.getStack = function() {
+    return this._stack;
+};
+
+/**
+ * Public accessor to internal start time.
+ *
+ * @return {date} Internal date of when Logger singleton was initialized.
+ */
+YAHOO.widget.Logger.getStartTime = function() {
+    return this._startTime;
+};
+
+/**
+ * Disables output to the Firebug Firefox extension.
+ */
+YAHOO.widget.Logger.disableFirebug = function() {
+    YAHOO.log("YAHOO.Logger output to Firebug has been disabled.");
+    this._firebugEnabled = false;
+};
+
+/**
+ * Enables output to the Firebug Firefox extension.
+ */
+YAHOO.widget.Logger.enableFirebug = function() {
+    this._firebugEnabled = true;
+    YAHOO.log("YAHOO.Logger output to Firebug has been enabled.");
+};
+
+/***************************************************************************
+ * Private methods
+ ***************************************************************************/
+/**
+ * Creates a new category of log messages and fires categoryCreateEvent.
+ *
+ * @param {string} category Category name
+ * @private
+ */
+YAHOO.widget.Logger._createNewCategory = function(category) {
+    this.categories.push(category);
+    this.categoryCreateEvent.fire(category);
+};
+
+/**
+ * Checks to see if a category has already been created.
+ *
+ * @param {string} category Category name
+ * @return {boolean} Returns true if category is unknown, else returns false
+ * @private
+ */
+YAHOO.widget.Logger._isNewCategory = function(category) {
+    for(var i=0; i < this.categories.length; i++) {
+        if(category == this.categories[i]) {
+            return false;
+        }
+    }
+    return true;
+};
+
+/**
+ * Creates a new source of log messages and fires sourceCreateEvent.
+ *
+ * @param {string} source Source name
+ * @private
+ */
+YAHOO.widget.Logger._createNewSource = function(source) {
+    this.sources.push(source);
+    this.sourceCreateEvent.fire(source);
+};
+
+/**
+ * Checks to see if a source has already been created.
+ *
+ * @param {string} source Source name
+ * @return {boolean} Returns true if source is unknown, else returns false
+ * @private
+ */
+YAHOO.widget.Logger._isNewSource = function(source) {
+    if(source) {
+        for(var i=0; i < this.sources.length; i++) {
+            if(source == this.sources[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
+
+/**
+ * Outputs a log message to Firebug.
+ *
+ * @param {object} entry Log entry object
+ * @private
+ */
+YAHOO.widget.Logger._printToFirebug = function(entry) {
+    if(window.console && console.log) {
+        var category = entry.category;
+        var label = entry.category.substring(0,4).toUpperCase();
+
+        var time = entry.time;
+        if (time.toLocaleTimeString) {
+            var localTime  = time.toLocaleTimeString();
+        }
+        else {
+            localTime = time.toString();
+        }
+
+        var msecs = time.getTime();
+        var elapsedTime = (YAHOO.widget.Logger._lastTime) ?
+            (msecs - YAHOO.widget.Logger._lastTime) : 0;
+        YAHOO.widget.Logger._lastTime = msecs;
+
+        var output = //Firebug doesn't support HTML "<span class='"+category+"'>"+label+"</span> " +
+            localTime + " (" +
+            elapsedTime + "ms): " +
+            entry.source + ": " +
+            entry.msg;
+
+        
+        console.log(output);
+    }
+};
+
+/***************************************************************************
+ * Private event handlers
+ ***************************************************************************/
+/**
+ * Handles logging of messages due to window error events.
+ *
+ * @param {string} msg The error message
+ * @param {string} url URL of the error
+ * @param {string} line Line number of the error
+ * @private
+ */
+YAHOO.widget.Logger._onWindowError = function(msg,url,line) {
+    // Logger is not in scope of this event handler
+    try {
+        YAHOO.widget.Logger.log(msg+' ('+url+', line '+line+')', "window");
+        if(YAHOO.widget.Logger._origOnWindowError) {
+            YAHOO.widget.Logger._origOnWindowError();
+        }
+    }
+    catch(e) {
+        return false;
+    }
+};
+
+/**
+ * Handle native JavaScript errors
+ */
+//NB: Not all browsers support the window.onerror event
+if(window.onerror) {
+    // Save any previously defined handler to call
+    YAHOO.widget.Logger._origOnWindowError = window.onerror;
+}
+window.onerror = YAHOO.widget.Logger._onWindowError;
+
+/**
+ * First log
+ */
+YAHOO.widget.Logger.log("Logger initialized");
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/**
+ * Class providing ability to log messages through YAHOO.widget.Logger from a
+ * named source.
+ *
+ * @constructor
+ * @param {string} sSource Source of LogWriter instance
+ */
+YAHOO.widget.LogWriter = function(sSource) {
+    if(!sSource) {
+        YAHOO.log("Could not instantiate LogWriter due to invalid source.", "error", "LogWriter");
+        return;
+    }
+    this._source = sSource;
+ };
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+ /**
+ * Public accessor to the unique name of the LogWriter instance.
+ *
+ * @return {string} Unique name of the LogWriter instance
+ */
+YAHOO.widget.LogWriter.prototype.toString = function() {
+    return "LogWriter " + this._sSource;
+};
+
+/**
+ * Logs a message attached to the source of the LogWriter.
+ *
+ * @param {string} sMsg The log message
+ * @param {string} sCategory Category name
+ */
+YAHOO.widget.LogWriter.prototype.log = function(sMsg, sCategory) {
+    YAHOO.widget.Logger.log(sMsg, sCategory, this._source);
+};
+
+/**
+ * Public accessor to get the source name.
+ *
+ * @return {string} The LogWriter source
+ */
+YAHOO.widget.LogWriter.prototype.getSource = function() {
+    return this._sSource;
+};
+
+/**
+ * Public accessor to set the source name.
+ *
+ * @param {string} sSource Source of LogWriter instance
+ */
+YAHOO.widget.LogWriter.prototype.setSource = function(sSource) {
+    if(!sSource) {
+        YAHOO.log("Could not set source due to invalid source.", "error", this.toString());
+        return;
+    }
+    else {
+        this._sSource = sSource;
+    }
+};
+/***************************************************************************
+ * Private members
+ ***************************************************************************/
+/**
+ * Source of the log writer instance.
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.LogWriter.prototype._source = null;
+
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * Class providing UI to read messages logged to YAHOO.widget.Logger.
+ *
+ * requires YAHOO.util.Dom DOM utility
+ * requires YAHOO.util.Event Event utility
+ * optional YAHOO.util.DragDrop Drag and drop utility
+ *
+ * @constructor
+ * @param {el or ID} containerEl DOM element object or ID of container to wrap reader UI
+ * @param {object} oConfig Optional object literal of configuration params
+ */
+YAHOO.widget.LogReader = function(containerEl, oConfig) {
+    var oSelf = this;
+
+    // Parse config vars here
+    if (typeof oConfig == "object") {
+        for(var param in oConfig) {
+            this[param] = oConfig[param];
+        }
+    }
+
+    // Attach container...
+    if(containerEl) {
+        if(typeof containerEl == "string") {
+            this._containerEl = document.getElementById(containerEl);
+        }
+        else if(containerEl.tagName) {
+            this._containerEl = containerEl;
+        }
+        this._containerEl.className = "yui-log";
+    }
+    // ...or create container from scratch
+    if(!this._containerEl) {
+        if(YAHOO.widget.LogReader._defaultContainerEl) {
+            this._containerEl =  YAHOO.widget.LogReader._defaultContainerEl;
+        }
+        else {
+            this._containerEl = document.body.appendChild(document.createElement("div"));
+            this._containerEl.id = "yui-log";
+            this._containerEl.className = "yui-log";
+
+            YAHOO.widget.LogReader._defaultContainerEl = this._containerEl;
+        }
+
+        // If implementer has provided container values, trust and set those
+        var containerStyle = this._containerEl.style;
+        if(this.width) {
+            containerStyle.width = this.width;
+        }
+        if(this.left) {
+            containerStyle.left = this.left;
+        }
+        if(this.right) {
+            containerStyle.right = this.right;
+        }
+        if(this.bottom) {
+            containerStyle.bottom = this.bottom;
+        }
+        if(this.top) {
+            containerStyle.top = this.top;
+        }
+        if(this.fontSize) {
+            containerStyle.fontSize = this.fontSize;
+        }
+    }
+
+    if(this._containerEl) {
+        // Create header
+        if(!this._hdEl) {
+            this._hdEl = this._containerEl.appendChild(document.createElement("div"));
+            this._hdEl.id = "yui-log-hd" + YAHOO.widget.LogReader._index;
+            this._hdEl.className = "yui-log-hd";
+
+            this._collapseEl = this._hdEl.appendChild(document.createElement("div"));
+            this._collapseEl.className = "yui-log-btns";
+
+            this._collapseBtn = document.createElement("input");
+            this._collapseBtn.type = "button";
+            this._collapseBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._collapseBtn.className = "yui-log-button";
+            this._collapseBtn.value = "Collapse";
+            this._collapseBtn = this._collapseEl.appendChild(this._collapseBtn);
+            YAHOO.util.Event.addListener(oSelf._collapseBtn,'click',oSelf._onClickCollapseBtn,oSelf);
+
+            this._title = this._hdEl.appendChild(document.createElement("h4"));
+            this._title.innerHTML = "Logger Console";
+
+            // If Drag and Drop utility is available...
+            // ...and this container was created from scratch...
+            // ...then make the header draggable
+            if(YAHOO.util.DD &&
+            (YAHOO.widget.LogReader._defaultContainerEl == this._containerEl)) {
+                var ylog_dd = new YAHOO.util.DD(this._containerEl.id);
+                ylog_dd.setHandleElId(this._hdEl.id);
+                this._hdEl.style.cursor = "move";
+            }
+        }
+        // Ceate console
+        if(!this._consoleEl) {
+            this._consoleEl = this._containerEl.appendChild(document.createElement("div"));
+            this._consoleEl.className = "yui-log-bd";
+            
+            // If implementer has provided console, trust and set those
+            if(this.height) {
+                this._consoleEl.style.height = this.height;
+            }
+        }
+        // Don't create footer if disabled
+        if(!this._ftEl && this.footerEnabled) {
+            this._ftEl = this._containerEl.appendChild(document.createElement("div"));
+            this._ftEl.className = "yui-log-ft";
+
+            this._btnsEl = this._ftEl.appendChild(document.createElement("div"));
+            this._btnsEl.className = "yui-log-btns";
+
+            this._pauseBtn = document.createElement("input");
+            this._pauseBtn.type = "button";
+            this._pauseBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._pauseBtn.className = "yui-log-button";
+            this._pauseBtn.value = "Pause";
+            this._pauseBtn = this._btnsEl.appendChild(this._pauseBtn);
+            YAHOO.util.Event.addListener(oSelf._pauseBtn,'click',oSelf._onClickPauseBtn,oSelf);
+
+            this._clearBtn = document.createElement("input");
+            this._clearBtn.type = "button";
+            this._clearBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._clearBtn.className = "yui-log-button";
+            this._clearBtn.value = "Clear";
+            this._clearBtn = this._btnsEl.appendChild(this._clearBtn);
+            YAHOO.util.Event.addListener(oSelf._clearBtn,'click',oSelf._onClickClearBtn,oSelf);
+
+            this._categoryFiltersEl = this._ftEl.appendChild(document.createElement("div"));
+            this._categoryFiltersEl.className = "yui-log-categoryfilters";
+            this._sourceFiltersEl = this._ftEl.appendChild(document.createElement("div"));
+            this._sourceFiltersEl.className = "yui-log-sourcefilters";
+        }
+    }
+
+    // Initialize buffer
+    if(!this._buffer) {
+        this._buffer = []; // output buffer
+    }
+    YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog, this);
+    this._lastTime = YAHOO.widget.Logger.getStartTime(); // timestamp of last log message to console
+
+    // Initialize category filters
+    this._categoryFilters = [];
+    var catsLen = YAHOO.widget.Logger.categories.length;
+    if(this._categoryFiltersEl) {
+        for(var i=0; i < catsLen; i++) {
+            this._createCategoryCheckbox(YAHOO.widget.Logger.categories[i]);
+        }
+    }
+    // Initialize source filters
+    this._sourceFilters = [];
+    var sourcesLen = YAHOO.widget.Logger.sources.length;
+    if(this._sourceFiltersEl) {
+        for(var j=0; j < sourcesLen; j++) {
+            this._createSourceCheckbox(YAHOO.widget.Logger.sources[j]);
+        }
+    }
+    YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate, this);
+    YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate, this);
+
+    YAHOO.widget.LogReader._index++;
+    this._filterLogs();
+};
+
+/***************************************************************************
+ * Public members
+ ***************************************************************************/
+/**
+ * Whether or not the log reader is enabled to output log messages. Default:
+ * true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.logReaderEnabled = true;
+
+/**
+ * Public member to access CSS width of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.width = null;
+
+/**
+ * Public member to access CSS height of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.height = null;
+
+/**
+ * Public member to access CSS top position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.top = null;
+
+/**
+ * Public member to access CSS left position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.left = null;
+
+/**
+ * Public member to access CSS right position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.right = null;
+
+/**
+ * Public member to access CSS bottom position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.bottom = null;
+
+/**
+ * Public member to access CSS font size of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.fontSize = null;
+
+/**
+ * Whether or not the footer UI is enabled for the log reader. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.footerEnabled = true;
+
+/**
+ * Whether or not output is verbose (more readable). Setting to true will make
+ * output more compact (less readable). Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.verboseOutput = true;
+
+/**
+ * Whether or not newest message is printed on top. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.newestOnTop = true;
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+/**
+ * Pauses output of log messages. While paused, log messages are not lost, but
+ * get saved to a buffer and then output upon resume of log reader.
+ */
+YAHOO.widget.LogReader.prototype.pause = function() {
+    this._timeout = null;
+    this.logReaderEnabled = false;
+};
+
+/**
+ * Resumes output of log messages, including outputting any log messages that
+ * have been saved to buffer while paused.
+ */
+YAHOO.widget.LogReader.prototype.resume = function() {
+    this.logReaderEnabled = true;
+    this._printBuffer();
+};
+
+/**
+ * Hides UI of log reader. Logging functionality is not disrupted.
+ */
+YAHOO.widget.LogReader.prototype.hide = function() {
+    this._containerEl.style.display = "none";
+};
+
+/**
+ * Shows UI of log reader. Logging functionality is not disrupted.
+ */
+YAHOO.widget.LogReader.prototype.show = function() {
+    this._containerEl.style.display = "block";
+};
+
+/**
+ * Updates title to given string.
+ *
+ * @param {string} sTitle String to display in log reader's title bar.
+ */
+YAHOO.widget.LogReader.prototype.setTitle = function(sTitle) {
+    var regEx = />/g;
+    sTitle = sTitle.replace(regEx,"&gt;");
+    regEx = /</g;
+    sTitle = sTitle.replace(regEx,"&lt;");
+    this._title.innerHTML = (sTitle);
+};
+ /***************************************************************************
+ * Private members
+ ***************************************************************************/
+/**
+ * Internal class member to index multiple log reader instances.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.LogReader._index = 0;
+
+/**
+ * A class member shared by all log readers if a container needs to be
+ * created during instantiation. Will be null if a container element never needs to
+ * be created on the fly, such as when the implementer passes in their own element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader._defaultContainerEl = null;
+
+/**
+ * Buffer of log messages for batch output.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._buffer = null;
+
+/**
+ * Date of last output log message.
+ *
+ * @type date
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._lastTime = null;
+
+/**
+ * Batched output timeout ID.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._timeout = null;
+
+/**
+ * Array of filters for log message categories.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._categoryFilters = null;
+
+/**
+ * Array of filters for log message sources.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sourceFilters = null;
+
+/**
+ * Log reader container element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._containerEl = null;
+
+/**
+ * Log reader header element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._hdEl = null;
+
+/**
+ * Log reader collapse element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._collapseEl = null;
+
+/**
+ * Log reader collapse button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._collapseBtn = null;
+
+/**
+ * Log reader title header element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._title = null;
+
+/**
+ * Log reader console element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._consoleEl = null;
+
+/**
+ * Log reader footer element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._ftEl = null;
+
+/**
+ * Log reader buttons container element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._btnsEl = null;
+
+/**
+ * Container element for log reader category filter checkboxes.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._categoryFiltersEl = null;
+
+/**
+ * Container element for log reader source filter checkboxes.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sourceFiltersEl = null;
+
+/**
+ * Log reader pause button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._pauseBtn = null;
+
+/**
+ * lear button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._clearBtn = null;
+/***************************************************************************
+ * Private methods
+ ***************************************************************************/
+/**
+ * Creates the UI for a category filter in the log reader footer element.
+ *
+ * @param {string} category Category name
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._createCategoryCheckbox = function(category) {
+    var oSelf = this;
+    
+    if(this._ftEl) {
+        var parentEl = this._categoryFiltersEl;
+        var filters = this._categoryFilters;
+
+        var filterEl = parentEl.appendChild(document.createElement("span"));
+        filterEl.className = "yui-log-filtergrp";
+            // Append el at the end so IE 5.5 can set "type" attribute
+            // and THEN set checked property
+            var categoryChk = document.createElement("input");
+            categoryChk.id = "yui-log-filter-" + category + YAHOO.widget.LogReader._index;
+            categoryChk.className = "yui-log-filter-" + category;
+            categoryChk.type = "checkbox";
+            categoryChk.category = category;
+            categoryChk = filterEl.appendChild(categoryChk);
+            categoryChk.checked = true;
+
+            // Add this checked filter to the internal array of filters
+            filters.push(category);
+            // Subscribe to the click event
+            YAHOO.util.Event.addListener(categoryChk,'click',oSelf._onCheckCategory,oSelf);
+
+            // Create and class the text label
+            var categoryChkLbl = filterEl.appendChild(document.createElement("label"));
+            categoryChkLbl.htmlFor = categoryChk.id;
+            categoryChkLbl.className = category;
+            categoryChkLbl.innerHTML = category;
+    }
+};
+
+YAHOO.widget.LogReader.prototype._createSourceCheckbox = function(source) {
+    var oSelf = this;
+
+    if(this._ftEl) {
+        var parentEl = this._sourceFiltersEl;
+        var filters = this._sourceFilters;
+
+        var filterEl = parentEl.appendChild(document.createElement("span"));
+        filterEl.className = "yui-log-filtergrp";
+
+        // Append el at the end so IE 5.5 can set "type" attribute
+        // and THEN set checked property
+        var sourceChk = document.createElement("input");
+        sourceChk.id = "yui-log-filter" + source + YAHOO.widget.LogReader._index;
+        sourceChk.className = "yui-log-filter" + source;
+        sourceChk.type = "checkbox";
+        sourceChk.source = source;
+        sourceChk = filterEl.appendChild(sourceChk);
+        sourceChk.checked = true;
+
+        // Add this checked filter to the internal array of filters
+        filters.push(source);
+        // Subscribe to the click event
+        YAHOO.util.Event.addListener(sourceChk,'click',oSelf._onCheckSource,oSelf);
+
+        // Create and class the text label
+        var sourceChkLbl = filterEl.appendChild(document.createElement("label"));
+        sourceChkLbl.htmlFor = sourceChk.id;
+        sourceChkLbl.className = source;
+        sourceChkLbl.innerHTML = source;
+    }
+};
+
+/**
+ * Reprints all log messages in the stack through filters.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._filterLogs = function() {
+    // Reprint stack with new filters
+    if (this._consoleEl !== null) {
+        this._clearConsole();
+        this._printToConsole(YAHOO.widget.Logger.getStack());
+    }
+};
+
+/**
+ * Clears all outputted log messages from the console and resets the time of the
+ * last output log message.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._clearConsole = function() {
+    // Clear the buffer of any pending messages
+    this._timeout = null;
+    this._buffer = [];
+
+    // Reset the rolling timer
+    this._lastTime = YAHOO.widget.Logger.getStartTime();
+
+    var consoleEl = this._consoleEl;
+    while(consoleEl.hasChildNodes()) {
+        consoleEl.removeChild(consoleEl.firstChild);
+    }
+};
+
+/**
+ * Sends buffer of log messages to output and clears buffer.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printBuffer = function() {
+    this._timeout = null;
+
+    if (this._consoleEl !== null) {
+        var entries = [];
+        for (var i=0; i<this._buffer.length; i++) {
+            entries[i] = this._buffer[i];
+        }
+        this._buffer = [];
+        this._printToConsole(entries);
+        if(!this.newestOnTop) {
+            this._consoleEl.scrollTop = this._consoleEl.scrollHeight;
+        }
+    }
+};
+
+/**
+ * Cycles through an array of log messages, and outputs each one to the console
+ * if its category has not been filtered out.
+ *
+ * @param {array} aEntries
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printToConsole = function(aEntries) {
+    var entriesLen = aEntries.length;
+    var sourceFiltersLen = this._sourceFilters.length;
+    var categoryFiltersLen = this._categoryFilters.length;
+    // Iterate through all log entries to print the ones that filter through
+    for(var i=0; i<entriesLen; i++) {
+        var entry = aEntries[i];
+        var category = entry.category;
+        var source = entry.source;
+        var sourceDetail = entry.sourceDetail;
+        var okToPrint = false;
+        var okToFilterCats = false;
+
+        for(var j=0; j<sourceFiltersLen; j++) {
+            if(source == this._sourceFilters[j]) {
+                okToFilterCats = true;
+                break;
+            }
+        }
+        if(okToFilterCats) {
+            for(var k=0; k<categoryFiltersLen; k++) {
+                if(category == this._categoryFilters[k]) {
+                    okToPrint = true;
+                    break;
+                }
+            }
+        }
+        if(okToPrint) {
+            // To format for console, calculate the elapsed time
+            // to be from the last item that passed through the filter,
+            // not the absolute previous item in the stack
+            var label = entry.category.substring(0,4).toUpperCase();
+
+            var time = entry.time;
+            if (time.toLocaleTimeString) {
+                var localTime  = time.toLocaleTimeString();
+            }
+            else {
+                localTime = time.toString();
+            }
+
+            var msecs = time.getTime();
+            var startTime = YAHOO.widget.Logger.getStartTime();
+            var totalTime = msecs - startTime;
+            var elapsedTime = msecs - this._lastTime;
+            this._lastTime = msecs;
+            
+            var verboseOutput = (this.verboseOutput) ? "<br>" : "";
+            var sourceAndDetail = (sourceDetail) ?
+                source + " " + sourceDetail : source;
+
+            var output =  "<span class='"+category+"'>"+label+"</span> " +
+                totalTime + "ms (+" +
+                elapsedTime + ") " + localTime + ": " +
+                sourceAndDetail + ": " +
+                verboseOutput +
+                entry.msg;
+
+            var oNewElement = (this.newestOnTop) ?
+                this._consoleEl.insertBefore(document.createElement("p"),this._consoleEl.firstChild):
+                this._consoleEl.appendChild(document.createElement("p"));
+            oNewElement.innerHTML = output;
+        }
+    }
+};
+
+/***************************************************************************
+ * Private event handlers
+ ***************************************************************************/
+/**
+ * Handles Logger's categoryCreateEvent.
+ *
+ * @param {string} type The event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCategoryCreate = function(type, args, oSelf) {
+    var category = args[0];
+    if(oSelf._ftEl) {
+        oSelf._createCategoryCheckbox(category);
+    }
+};
+
+/**
+ * Handles Logger's sourceCreateEvent.
+ *
+ * @param {string} type The event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onSourceCreate = function(type, args, oSelf) {
+    var source = args[0];
+    if(oSelf._ftEl) {
+        oSelf._createSourceCheckbox(source);
+    }
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckCategory = function(v, oSelf) {
+    var newFilter = this.category;
+    var filtersArray = oSelf._categoryFilters;
+
+    if(!this.checked) { // Remove category from filters
+        for(var i=0; i<filtersArray.length; i++) {
+            if(newFilter == filtersArray[i]) {
+                filtersArray.splice(i, 1);
+                break;
+            }
+        }
+    }
+    else { // Add category to filters
+        filtersArray.push(newFilter);
+    }
+    oSelf._filterLogs();
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckSource = function(v, oSelf) {
+    var newFilter = this.source;
+    var filtersArray = oSelf._sourceFilters;
+    
+    if(!this.checked) { // Remove category from filters
+        for(var i=0; i<filtersArray.length; i++) {
+            if(newFilter == filtersArray[i]) {
+                filtersArray.splice(i, 1);
+                break;
+            }
+        }
+    }
+    else { // Add category to filters
+        filtersArray.push(newFilter);
+    }
+    oSelf._filterLogs();
+};
+
+/**
+ * Handles click events on the collapse button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickCollapseBtn = function(v, oSelf) {
+    var btn = oSelf._collapseBtn;
+    if(btn.value == "Expand") {
+        oSelf._consoleEl.style.display = "block";
+        if(oSelf._ftEl) {
+            oSelf._ftEl.style.display = "block";
+        }
+        btn.value = "Collapse";
+    }
+    else {
+        oSelf._consoleEl.style.display = "none";
+        if(oSelf._ftEl) {
+            oSelf._ftEl.style.display = "none";
+        }
+        btn.value = "Expand";
+    }
+};
+
+/**
+ * Handles click events on the pause button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickPauseBtn = function(v, oSelf) {
+    var btn = oSelf._pauseBtn;
+    if(btn.value == "Resume") {
+        oSelf.resume();
+        btn.value = "Pause";
+    }
+    else {
+        oSelf.pause();
+        btn.value = "Resume";
+    }
+};
+
+/**
+ * Handles click events on the clear button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickClearBtn = function(v, oSelf) {
+    oSelf._clearConsole();
+};
+
+/**
+ * Handles Logger's onNewEvent.
+ *
+ * @param {string} type The click event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onNewLog = function(type, args, oSelf) {
+    var logEntry = args[0];
+    oSelf._buffer.push(logEntry);
+
+    if (oSelf.logReaderEnabled === true && oSelf._timeout === null) {
+        oSelf._timeout = setTimeout(function(){oSelf._printBuffer();}, 100);
+    }
+};
+
+

Added: trunk/theme/src/bin/portal-ajax-war/js/logger/logger-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/logger/logger-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/logger/logger-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+
+
+YAHOO.widget.Logger={loggerEnabled:true,_firebugEnabled:true,categories:["info","warn","error","time","window"],sources:["global"],_stack:[],_startTime:new Date().getTime(),_lastTime:null};YAHOO.widget.Logger.categoryCreateEvent=new YAHOO.util.CustomEvent("categoryCreate",this,true);YAHOO.widget.Logger.sourceCreateEvent=new YAHOO.util.CustomEvent("sourceCreate",this,true);YAHOO.widget.Logger.newLogEvent=new YAHOO.util.CustomEvent("newLog",this,true);YAHOO.widget.Logger.logResetEvent=new YAHOO.util.CustomEvent("logReset",this,true);YAHOO.widget.Logger.log=function(sMsg,sCategory,sSource){if(this.loggerEnabled){if(!sCategory){sCategory="info";}
+else if(this._isNewCategory(sCategory)){this._createNewCategory(sCategory);}
+var sClass="global";var sDetail=null;if(sSource){var spaceIndex=sSource.indexOf(" ");if(spaceIndex>0){sClass=sSource.substring(0,spaceIndex);sDetail=sSource.substring(spaceIndex,sSource.length);}
+else{sClass=sSource;}
+if(this._isNewSource(sClass)){this._createNewSource(sClass);}}
+var timestamp=new Date();var logEntry={time:timestamp,category:sCategory,source:sClass,sourceDetail:sDetail,msg:sMsg};this._stack.push(logEntry);this.newLogEvent.fire(logEntry);if(this._firebugEnabled){this._printToFirebug(logEntry);}
+return true;}
+else{return false;}};YAHOO.widget.Logger.reset=function(){this._stack=[];this._startTime=new Date().getTime();this.loggerEnabled=true;this.log(null,"Logger reset");this.logResetEvent.fire();};YAHOO.widget.Logger.getStack=function(){return this._stack;};YAHOO.widget.Logger.getStartTime=function(){return this._startTime;};YAHOO.widget.Logger.disableFirebug=function(){YAHOO.log("YAHOO.Logger output to Firebug has been disabled.");this._firebugEnabled=false;};YAHOO.widget.Logger.enableFirebug=function(){this._firebugEnabled=true;YAHOO.log("YAHOO.Logger output to Firebug has been enabled.");};YAHOO.widget.Logger._createNewCategory=function(category){this.categories.push(category);this.categoryCreateEvent.fire(category);};YAHOO.widget.Logger._isNewCategory=function(category){for(var i=0;i<this.categories.length;i++){if(category==this.categories[i]){return false;}}
+return true;};YAHOO.widget.Logger._createNewSource=function(source){this.sources.push(source);this.sourceCreateEvent.fire(source);};YAHOO.widget.Logger._isNewSource=function(source){if(source){for(var i=0;i<this.sources.length;i++){if(source==this.sources[i]){return false;}}
+return true;}};YAHOO.widget.Logger._printToFirebug=function(entry){if(window.console&&console.log){var category=entry.category;var label=entry.category.substring(0,4).toUpperCase();var time=entry.time;if(time.toLocaleTimeString){var localTime=time.toLocaleTimeString();}
+else{localTime=time.toString();}
+var msecs=time.getTime();var elapsedTime=(YAHOO.widget.Logger._lastTime)?(msecs-YAHOO.widget.Logger._lastTime):0;YAHOO.widget.Logger._lastTime=msecs;var output=localTime+" ("+
+elapsedTime+"ms): "+
+entry.source+": "+
+entry.msg;console.log(output);}};YAHOO.widget.Logger._onWindowError=function(msg,url,line){try{YAHOO.widget.Logger.log(msg+' ('+url+', line '+line+')',"window");if(YAHOO.widget.Logger._origOnWindowError){YAHOO.widget.Logger._origOnWindowError();}}
+catch(e){return false;}};if(window.onerror){YAHOO.widget.Logger._origOnWindowError=window.onerror;}
+window.onerror=YAHOO.widget.Logger._onWindowError;YAHOO.widget.Logger.log("Logger initialized");YAHOO.widget.LogWriter=function(sSource){if(!sSource){YAHOO.log("Could not instantiate LogWriter due to invalid source.","error","LogWriter");return;}
+this._source=sSource;};YAHOO.widget.LogWriter.prototype.toString=function(){return"LogWriter "+this._sSource;};YAHOO.widget.LogWriter.prototype.log=function(sMsg,sCategory){YAHOO.widget.Logger.log(sMsg,sCategory,this._source);};YAHOO.widget.LogWriter.prototype.getSource=function(){return this._sSource;};YAHOO.widget.LogWriter.prototype.setSource=function(sSource){if(!sSource){YAHOO.log("Could not set source due to invalid source.","error",this.toString());return;}
+else{this._sSource=sSource;}};YAHOO.widget.LogWriter.prototype._source=null;YAHOO.widget.LogReader=function(containerEl,oConfig){var oSelf=this;if(typeof oConfig=="object"){for(var param in oConfig){this[param]=oConfig[param];}}
+if(containerEl){if(typeof containerEl=="string"){this._containerEl=document.getElementById(containerEl);}
+else if(containerEl.tagName){this._containerEl=containerEl;}
+this._containerEl.className="yui-log";}
+if(!this._containerEl){if(YAHOO.widget.LogReader._defaultContainerEl){this._containerEl=YAHOO.widget.LogReader._defaultContainerEl;}
+else{this._containerEl=document.body.appendChild(document.createElement("div"));this._containerEl.id="yui-log";this._containerEl.className="yui-log";YAHOO.widget.LogReader._defaultContainerEl=this._containerEl;}
+var containerStyle=this._containerEl.style;if(this.width){containerStyle.width=this.width;}
+if(this.left){containerStyle.left=this.left;}
+if(this.right){containerStyle.right=this.right;}
+if(this.bottom){containerStyle.bottom=this.bottom;}
+if(this.top){containerStyle.top=this.top;}
+if(this.fontSize){containerStyle.fontSize=this.fontSize;}}
+if(this._containerEl){if(!this._hdEl){this._hdEl=this._containerEl.appendChild(document.createElement("div"));this._hdEl.id="yui-log-hd"+YAHOO.widget.LogReader._index;this._hdEl.className="yui-log-hd";this._collapseEl=this._hdEl.appendChild(document.createElement("div"));this._collapseEl.className="yui-log-btns";this._collapseBtn=document.createElement("input");this._collapseBtn.type="button";this._collapseBtn.style.fontSize=YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");this._collapseBtn.className="yui-log-button";this._collapseBtn.value="Collapse";this._collapseBtn=this._collapseEl.appendChild(this._collapseBtn);YAHOO.util.Event.addListener(oSelf._collapseBtn,'click',oSelf._onClickCollapseBtn,oSelf);this._title=this._hdEl.appendChild(document.createElement("h4"));this._title.innerHTML="Logger Console";if(YAHOO.util.DD&&(YAHOO.widget.LogReader._defaultContainerEl==this._containerEl)){var ylog_dd=new YAHOO.util.DD(this._containerEl.id);ylog_dd.setHandleElId(this._hdE!
 l.id);this._hdEl.style.cursor="move";}}
+if(!this._consoleEl){this._consoleEl=this._containerEl.appendChild(document.createElement("div"));this._consoleEl.className="yui-log-bd";if(this.height){this._consoleEl.style.height=this.height;}}
+if(!this._ftEl&&this.footerEnabled){this._ftEl=this._containerEl.appendChild(document.createElement("div"));this._ftEl.className="yui-log-ft";this._btnsEl=this._ftEl.appendChild(document.createElement("div"));this._btnsEl.className="yui-log-btns";this._pauseBtn=document.createElement("input");this._pauseBtn.type="button";this._pauseBtn.style.fontSize=YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");this._pauseBtn.className="yui-log-button";this._pauseBtn.value="Pause";this._pauseBtn=this._btnsEl.appendChild(this._pauseBtn);YAHOO.util.Event.addListener(oSelf._pauseBtn,'click',oSelf._onClickPauseBtn,oSelf);this._clearBtn=document.createElement("input");this._clearBtn.type="button";this._clearBtn.style.fontSize=YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");this._clearBtn.className="yui-log-button";this._clearBtn.value="Clear";this._clearBtn=this._btnsEl.appendChild(this._clearBtn);YAHOO.util.Event.addListener(oSelf._clearBtn,'click',oSelf._onClickClearBtn,oSelf);t!
 his._categoryFiltersEl=this._ftEl.appendChild(document.createElement("div"));this._categoryFiltersEl.className="yui-log-categoryfilters";this._sourceFiltersEl=this._ftEl.appendChild(document.createElement("div"));this._sourceFiltersEl.className="yui-log-sourcefilters";}}
+if(!this._buffer){this._buffer=[];}
+YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog,this);this._lastTime=YAHOO.widget.Logger.getStartTime();this._categoryFilters=[];var catsLen=YAHOO.widget.Logger.categories.length;if(this._categoryFiltersEl){for(var i=0;i<catsLen;i++){this._createCategoryCheckbox(YAHOO.widget.Logger.categories[i]);}}
+this._sourceFilters=[];var sourcesLen=YAHOO.widget.Logger.sources.length;if(this._sourceFiltersEl){for(var j=0;j<sourcesLen;j++){this._createSourceCheckbox(YAHOO.widget.Logger.sources[j]);}}
+YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate,this);YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate,this);YAHOO.widget.LogReader._index++;this._filterLogs();};YAHOO.widget.LogReader.prototype.logReaderEnabled=true;YAHOO.widget.LogReader.prototype.width=null;YAHOO.widget.LogReader.prototype.height=null;YAHOO.widget.LogReader.prototype.top=null;YAHOO.widget.LogReader.prototype.left=null;YAHOO.widget.LogReader.prototype.right=null;YAHOO.widget.LogReader.prototype.bottom=null;YAHOO.widget.LogReader.prototype.fontSize=null;YAHOO.widget.LogReader.prototype.footerEnabled=true;YAHOO.widget.LogReader.prototype.verboseOutput=true;YAHOO.widget.LogReader.prototype.newestOnTop=true;YAHOO.widget.LogReader.prototype.pause=function(){this._timeout=null;this.logReaderEnabled=false;};YAHOO.widget.LogReader.prototype.resume=function(){this.logReaderEnabled=true;this._printBuffer();};YAHOO.widget.LogReader.prototype.hide=function(){this._containe!
 rEl.style.display="none";};YAHOO.widget.LogReader.prototype.show=function(){this._containerEl.style.display="block";};YAHOO.widget.LogReader.prototype.setTitle=function(sTitle){var regEx=/>/g;sTitle=sTitle.replace(regEx,"&gt;");regEx=/</g;sTitle=sTitle.replace(regEx,"&lt;");this._title.innerHTML=(sTitle);};YAHOO.widget.LogReader._index=0;YAHOO.widget.LogReader._defaultContainerEl=null;YAHOO.widget.LogReader.prototype._buffer=null;YAHOO.widget.LogReader.prototype._lastTime=null;YAHOO.widget.LogReader.prototype._timeout=null;YAHOO.widget.LogReader.prototype._categoryFilters=null;YAHOO.widget.LogReader.prototype._sourceFilters=null;YAHOO.widget.LogReader.prototype._containerEl=null;YAHOO.widget.LogReader.prototype._hdEl=null;YAHOO.widget.LogReader.prototype._collapseEl=null;YAHOO.widget.LogReader.prototype._collapseBtn=null;YAHOO.widget.LogReader.prototype._title=null;YAHOO.widget.LogReader.prototype._consoleEl=null;YAHOO.widget.LogReader.prototype._ftEl=null;YAHOO.widget.LogR!
 eader.prototype._btnsEl=null;YAHOO.widget.LogReader.prototype._categor
yFiltersEl=null;YAHOO.widget.LogReader.prototype._sourceFiltersEl=null;YAHOO.widget.LogReader.prototype._pauseBtn=null;YAHOO.widget.LogReader.prototype._clearBtn=null;YAHOO.widget.LogReader.prototype._createCategoryCheckbox=function(category){var oSelf=this;if(this._ftEl){var parentEl=this._categoryFiltersEl;var filters=this._categoryFilters;var filterEl=parentEl.appendChild(document.createElement("span"));filterEl.className="yui-log-filtergrp";var categoryChk=document.createElement("input");categoryChk.id="yui-log-filter-"+category+YAHOO.widget.LogReader._index;categoryChk.className="yui-log-filter-"+category;categoryChk.type="checkbox";categoryChk.category=category;categoryChk=filterEl.appendChild(categoryChk);categoryChk.checked=true;filters.push(category);YAHOO.util.Event.addListener(categoryChk,'click',oSelf._onCheckCategory,oSelf);var categoryChkLbl=filterEl.appendChild(document.createElement("label"));categoryChkLbl.htmlFor=categoryChk.id;categoryChkLbl.className=cate!
 gory;categoryChkLbl.innerHTML=category;}};YAHOO.widget.LogReader.prototype._createSourceCheckbox=function(source){var oSelf=this;if(this._ftEl){var parentEl=this._sourceFiltersEl;var filters=this._sourceFilters;var filterEl=parentEl.appendChild(document.createElement("span"));filterEl.className="yui-log-filtergrp";var sourceChk=document.createElement("input");sourceChk.id="yui-log-filter"+source+YAHOO.widget.LogReader._index;sourceChk.className="yui-log-filter"+source;sourceChk.type="checkbox";sourceChk.source=source;sourceChk=filterEl.appendChild(sourceChk);sourceChk.checked=true;filters.push(source);YAHOO.util.Event.addListener(sourceChk,'click',oSelf._onCheckSource,oSelf);var sourceChkLbl=filterEl.appendChild(document.createElement("label"));sourceChkLbl.htmlFor=sourceChk.id;sourceChkLbl.className=source;sourceChkLbl.innerHTML=source;}};YAHOO.widget.LogReader.prototype._filterLogs=function(){if(this._consoleEl!==null){this._clearConsole();this._printToConsole(YAHOO.widge!
 t.Logger.getStack());}};YAHOO.widget.LogReader.prototype._clearConsole
=function(){this._timeout=null;this._buffer=[];this._lastTime=YAHOO.widget.Logger.getStartTime();var consoleEl=this._consoleEl;while(consoleEl.hasChildNodes()){consoleEl.removeChild(consoleEl.firstChild);}};YAHOO.widget.LogReader.prototype._printBuffer=function(){this._timeout=null;if(this._consoleEl!==null){var entries=[];for(var i=0;i<this._buffer.length;i++){entries[i]=this._buffer[i];}
+this._buffer=[];this._printToConsole(entries);if(!this.newestOnTop){this._consoleEl.scrollTop=this._consoleEl.scrollHeight;}}};YAHOO.widget.LogReader.prototype._printToConsole=function(aEntries){var entriesLen=aEntries.length;var sourceFiltersLen=this._sourceFilters.length;var categoryFiltersLen=this._categoryFilters.length;for(var i=0;i<entriesLen;i++){var entry=aEntries[i];var category=entry.category;var source=entry.source;var sourceDetail=entry.sourceDetail;var okToPrint=false;var okToFilterCats=false;for(var j=0;j<sourceFiltersLen;j++){if(source==this._sourceFilters[j]){okToFilterCats=true;break;}}
+if(okToFilterCats){for(var k=0;k<categoryFiltersLen;k++){if(category==this._categoryFilters[k]){okToPrint=true;break;}}}
+if(okToPrint){var label=entry.category.substring(0,4).toUpperCase();var time=entry.time;if(time.toLocaleTimeString){var localTime=time.toLocaleTimeString();}
+else{localTime=time.toString();}
+var msecs=time.getTime();var startTime=YAHOO.widget.Logger.getStartTime();var totalTime=msecs-startTime;var elapsedTime=msecs-this._lastTime;this._lastTime=msecs;var verboseOutput=(this.verboseOutput)?"<br>":"";var sourceAndDetail=(sourceDetail)?source+" "+sourceDetail:source;var output="<span class='"+category+"'>"+label+"</span> "+
+totalTime+"ms (+"+
+elapsedTime+") "+localTime+": "+
+sourceAndDetail+": "+
+verboseOutput+
+entry.msg;var oNewElement=(this.newestOnTop)?this._consoleEl.insertBefore(document.createElement("p"),this._consoleEl.firstChild):this._consoleEl.appendChild(document.createElement("p"));oNewElement.innerHTML=output;}}};YAHOO.widget.LogReader.prototype._onCategoryCreate=function(type,args,oSelf){var category=args[0];if(oSelf._ftEl){oSelf._createCategoryCheckbox(category);}};YAHOO.widget.LogReader.prototype._onSourceCreate=function(type,args,oSelf){var source=args[0];if(oSelf._ftEl){oSelf._createSourceCheckbox(source);}};YAHOO.widget.LogReader.prototype._onCheckCategory=function(v,oSelf){var newFilter=this.category;var filtersArray=oSelf._categoryFilters;if(!this.checked){for(var i=0;i<filtersArray.length;i++){if(newFilter==filtersArray[i]){filtersArray.splice(i,1);break;}}}
+else{filtersArray.push(newFilter);}
+oSelf._filterLogs();};YAHOO.widget.LogReader.prototype._onCheckSource=function(v,oSelf){var newFilter=this.source;var filtersArray=oSelf._sourceFilters;if(!this.checked){for(var i=0;i<filtersArray.length;i++){if(newFilter==filtersArray[i]){filtersArray.splice(i,1);break;}}}
+else{filtersArray.push(newFilter);}
+oSelf._filterLogs();};YAHOO.widget.LogReader.prototype._onClickCollapseBtn=function(v,oSelf){var btn=oSelf._collapseBtn;if(btn.value=="Expand"){oSelf._consoleEl.style.display="block";if(oSelf._ftEl){oSelf._ftEl.style.display="block";}
+btn.value="Collapse";}
+else{oSelf._consoleEl.style.display="none";if(oSelf._ftEl){oSelf._ftEl.style.display="none";}
+btn.value="Expand";}};YAHOO.widget.LogReader.prototype._onClickPauseBtn=function(v,oSelf){var btn=oSelf._pauseBtn;if(btn.value=="Resume"){oSelf.resume();btn.value="Pause";}
+else{oSelf.pause();btn.value="Resume";}};YAHOO.widget.LogReader.prototype._onClickClearBtn=function(v,oSelf){oSelf._clearConsole();};YAHOO.widget.LogReader.prototype._onNewLog=function(type,args,oSelf){var logEntry=args[0];oSelf._buffer.push(logEntry);if(oSelf.logReaderEnabled===true&&oSelf._timeout===null){oSelf._timeout=setTimeout(function(){oSelf._printBuffer();},100);}};
\ No newline at end of file

Added: trunk/theme/src/bin/portal-ajax-war/js/logger/logger.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/logger/logger.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/logger/logger.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,1186 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/**
+ * Singleton providing core logging functionality. Saves logs written through the
+ * global YAHOO.log function or written by LogWriter. Provides access to logs
+ * for reading by LogReader. Log messages are automatically output to Firebug,
+ * if present.
+ *
+ * requires YAHOO.util.Event Event utility
+ */
+YAHOO.widget.Logger = {
+    // Initialize members
+    loggerEnabled: true,
+    _firebugEnabled: true,
+    categories: ["info","warn","error","time","window"],
+    sources: ["global"],
+    _stack: [], // holds all log msgs
+    _startTime: new Date().getTime(), // static start timestamp
+    _lastTime: null // timestamp of last logged message
+};
+
+/***************************************************************************
+ * Events
+ ***************************************************************************/
+/**
+ * Fired when a new category has been created. Subscribers receive the following
+ * array:<br>
+ *     - args[0] The category name
+ */
+YAHOO.widget.Logger.categoryCreateEvent = new YAHOO.util.CustomEvent("categoryCreate", this, true);
+
+/**
+ * Fired when a new source has been named. Subscribers receive the following
+ * array:<br>
+ *     - args[0] The source name
+ */
+YAHOO.widget.Logger.sourceCreateEvent = new YAHOO.util.CustomEvent("sourceCreate", this, true);
+
+/**
+ * Fired when a new log message has been created. Subscribers receive the
+ * following array:<br>
+ *     - args[0] The log message
+ */
+YAHOO.widget.Logger.newLogEvent = new YAHOO.util.CustomEvent("newLog", this, true);
+
+/**
+ * Fired when the Logger has been reset has been created.
+ */
+YAHOO.widget.Logger.logResetEvent = new YAHOO.util.CustomEvent("logReset", this, true);
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+/**
+ * Saves a log message to the stack and fires newLogEvent. If the log message is
+ * assigned to an unknown category, creates a new category. If the log message is
+ * from an unknown source, creates a new source.  If Firebug is enabled,
+ * outputs the log message to Firebug.
+ *
+ * @param {string} sMsg The log message
+ * @param {string} sCategory Category of log message, or null
+ * @param {string} sSource Source of LogWriter, or null if global
+ */
+YAHOO.widget.Logger.log = function(sMsg, sCategory, sSource) {
+    if(this.loggerEnabled) {
+        if(!sCategory) {
+            sCategory = "info"; // default category
+        }
+        else if(this._isNewCategory(sCategory)) {
+            this._createNewCategory(sCategory);
+        }
+        var sClass = "global"; // default source
+        var sDetail = null;
+        if(sSource) {
+            var spaceIndex = sSource.indexOf(" ");
+            if(spaceIndex > 0) {
+                sClass = sSource.substring(0,spaceIndex);// substring until first space
+                sDetail = sSource.substring(spaceIndex,sSource.length);// the rest of the source
+            }
+            else {
+                sClass = sSource;
+            }
+            if(this._isNewSource(sClass)) {
+                this._createNewSource(sClass);
+            }
+        }
+
+        var timestamp = new Date();
+        var logEntry = {
+            time: timestamp,
+            category: sCategory,
+            source: sClass,
+            sourceDetail: sDetail,
+            msg: sMsg
+        };
+
+        this._stack.push(logEntry);
+        this.newLogEvent.fire(logEntry);
+
+        if(this._firebugEnabled) {
+            this._printToFirebug(logEntry);
+        }
+        return true;
+    }
+    else {
+        return false;
+    }
+};
+
+/**
+ * Resets internal stack and startTime, enables Logger, and fires logResetEvent.
+ *
+ */
+YAHOO.widget.Logger.reset = function() {
+    this._stack = [];
+    this._startTime = new Date().getTime();
+    this.loggerEnabled = true;
+    this.log(null, "Logger reset");
+    this.logResetEvent.fire();
+};
+
+/**
+ * Public accessor to internal stack of log messages.
+ *
+ * @return {array} Array of log messages.
+ */
+YAHOO.widget.Logger.getStack = function() {
+    return this._stack;
+};
+
+/**
+ * Public accessor to internal start time.
+ *
+ * @return {date} Internal date of when Logger singleton was initialized.
+ */
+YAHOO.widget.Logger.getStartTime = function() {
+    return this._startTime;
+};
+
+/**
+ * Disables output to the Firebug Firefox extension.
+ */
+YAHOO.widget.Logger.disableFirebug = function() {
+    YAHOO.log("YAHOO.Logger output to Firebug has been disabled.");
+    this._firebugEnabled = false;
+};
+
+/**
+ * Enables output to the Firebug Firefox extension.
+ */
+YAHOO.widget.Logger.enableFirebug = function() {
+    this._firebugEnabled = true;
+    YAHOO.log("YAHOO.Logger output to Firebug has been enabled.");
+};
+
+/***************************************************************************
+ * Private methods
+ ***************************************************************************/
+/**
+ * Creates a new category of log messages and fires categoryCreateEvent.
+ *
+ * @param {string} category Category name
+ * @private
+ */
+YAHOO.widget.Logger._createNewCategory = function(category) {
+    this.categories.push(category);
+    this.categoryCreateEvent.fire(category);
+};
+
+/**
+ * Checks to see if a category has already been created.
+ *
+ * @param {string} category Category name
+ * @return {boolean} Returns true if category is unknown, else returns false
+ * @private
+ */
+YAHOO.widget.Logger._isNewCategory = function(category) {
+    for(var i=0; i < this.categories.length; i++) {
+        if(category == this.categories[i]) {
+            return false;
+        }
+    }
+    return true;
+};
+
+/**
+ * Creates a new source of log messages and fires sourceCreateEvent.
+ *
+ * @param {string} source Source name
+ * @private
+ */
+YAHOO.widget.Logger._createNewSource = function(source) {
+    this.sources.push(source);
+    this.sourceCreateEvent.fire(source);
+};
+
+/**
+ * Checks to see if a source has already been created.
+ *
+ * @param {string} source Source name
+ * @return {boolean} Returns true if source is unknown, else returns false
+ * @private
+ */
+YAHOO.widget.Logger._isNewSource = function(source) {
+    if(source) {
+        for(var i=0; i < this.sources.length; i++) {
+            if(source == this.sources[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
+
+/**
+ * Outputs a log message to Firebug.
+ *
+ * @param {object} entry Log entry object
+ * @private
+ */
+YAHOO.widget.Logger._printToFirebug = function(entry) {
+    if(window.console && console.log) {
+        var category = entry.category;
+        var label = entry.category.substring(0,4).toUpperCase();
+
+        var time = entry.time;
+        if (time.toLocaleTimeString) {
+            var localTime  = time.toLocaleTimeString();
+        }
+        else {
+            localTime = time.toString();
+        }
+
+        var msecs = time.getTime();
+        var elapsedTime = (YAHOO.widget.Logger._lastTime) ?
+            (msecs - YAHOO.widget.Logger._lastTime) : 0;
+        YAHOO.widget.Logger._lastTime = msecs;
+
+        var output = //Firebug doesn't support HTML "<span class='"+category+"'>"+label+"</span> " +
+            localTime + " (" +
+            elapsedTime + "ms): " +
+            entry.source + ": " +
+            entry.msg;
+
+        
+        console.log(output);
+    }
+};
+
+/***************************************************************************
+ * Private event handlers
+ ***************************************************************************/
+/**
+ * Handles logging of messages due to window error events.
+ *
+ * @param {string} msg The error message
+ * @param {string} url URL of the error
+ * @param {string} line Line number of the error
+ * @private
+ */
+YAHOO.widget.Logger._onWindowError = function(msg,url,line) {
+    // Logger is not in scope of this event handler
+    try {
+        YAHOO.widget.Logger.log(msg+' ('+url+', line '+line+')', "window");
+        if(YAHOO.widget.Logger._origOnWindowError) {
+            YAHOO.widget.Logger._origOnWindowError();
+        }
+    }
+    catch(e) {
+        return false;
+    }
+};
+
+/**
+ * Handle native JavaScript errors
+ */
+//NB: Not all browsers support the window.onerror event
+if(window.onerror) {
+    // Save any previously defined handler to call
+    YAHOO.widget.Logger._origOnWindowError = window.onerror;
+}
+window.onerror = YAHOO.widget.Logger._onWindowError;
+
+/**
+ * First log
+ */
+YAHOO.widget.Logger.log("Logger initialized");
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/**
+ * Class providing ability to log messages through YAHOO.widget.Logger from a
+ * named source.
+ *
+ * @constructor
+ * @param {string} sSource Source of LogWriter instance
+ */
+YAHOO.widget.LogWriter = function(sSource) {
+    if(!sSource) {
+        YAHOO.log("Could not instantiate LogWriter due to invalid source.", "error", "LogWriter");
+        return;
+    }
+    this._source = sSource;
+ };
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+ /**
+ * Public accessor to the unique name of the LogWriter instance.
+ *
+ * @return {string} Unique name of the LogWriter instance
+ */
+YAHOO.widget.LogWriter.prototype.toString = function() {
+    return "LogWriter " + this._sSource;
+};
+
+/**
+ * Logs a message attached to the source of the LogWriter.
+ *
+ * @param {string} sMsg The log message
+ * @param {string} sCategory Category name
+ */
+YAHOO.widget.LogWriter.prototype.log = function(sMsg, sCategory) {
+    YAHOO.widget.Logger.log(sMsg, sCategory, this._source);
+};
+
+/**
+ * Public accessor to get the source name.
+ *
+ * @return {string} The LogWriter source
+ */
+YAHOO.widget.LogWriter.prototype.getSource = function() {
+    return this._sSource;
+};
+
+/**
+ * Public accessor to set the source name.
+ *
+ * @param {string} sSource Source of LogWriter instance
+ */
+YAHOO.widget.LogWriter.prototype.setSource = function(sSource) {
+    if(!sSource) {
+        YAHOO.log("Could not set source due to invalid source.", "error", this.toString());
+        return;
+    }
+    else {
+        this._sSource = sSource;
+    }
+};
+/***************************************************************************
+ * Private members
+ ***************************************************************************/
+/**
+ * Source of the log writer instance.
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.LogWriter.prototype._source = null;
+
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * Class providing UI to read messages logged to YAHOO.widget.Logger.
+ *
+ * requires YAHOO.util.Dom DOM utility
+ * requires YAHOO.util.Event Event utility
+ * optional YAHOO.util.DragDrop Drag and drop utility
+ *
+ * @constructor
+ * @param {el or ID} containerEl DOM element object or ID of container to wrap reader UI
+ * @param {object} oConfig Optional object literal of configuration params
+ */
+YAHOO.widget.LogReader = function(containerEl, oConfig) {
+    var oSelf = this;
+
+    // Parse config vars here
+    if (typeof oConfig == "object") {
+        for(var param in oConfig) {
+            this[param] = oConfig[param];
+        }
+    }
+
+    // Attach container...
+    if(containerEl) {
+        if(typeof containerEl == "string") {
+            this._containerEl = document.getElementById(containerEl);
+        }
+        else if(containerEl.tagName) {
+            this._containerEl = containerEl;
+        }
+        this._containerEl.className = "yui-log";
+    }
+    // ...or create container from scratch
+    if(!this._containerEl) {
+        if(YAHOO.widget.LogReader._defaultContainerEl) {
+            this._containerEl =  YAHOO.widget.LogReader._defaultContainerEl;
+        }
+        else {
+            this._containerEl = document.body.appendChild(document.createElement("div"));
+            this._containerEl.id = "yui-log";
+            this._containerEl.className = "yui-log";
+
+            YAHOO.widget.LogReader._defaultContainerEl = this._containerEl;
+        }
+
+        // If implementer has provided container values, trust and set those
+        var containerStyle = this._containerEl.style;
+        if(this.width) {
+            containerStyle.width = this.width;
+        }
+        if(this.left) {
+            containerStyle.left = this.left;
+        }
+        if(this.right) {
+            containerStyle.right = this.right;
+        }
+        if(this.bottom) {
+            containerStyle.bottom = this.bottom;
+        }
+        if(this.top) {
+            containerStyle.top = this.top;
+        }
+        if(this.fontSize) {
+            containerStyle.fontSize = this.fontSize;
+        }
+    }
+
+    if(this._containerEl) {
+        // Create header
+        if(!this._hdEl) {
+            this._hdEl = this._containerEl.appendChild(document.createElement("div"));
+            this._hdEl.id = "yui-log-hd" + YAHOO.widget.LogReader._index;
+            this._hdEl.className = "yui-log-hd";
+
+            this._collapseEl = this._hdEl.appendChild(document.createElement("div"));
+            this._collapseEl.className = "yui-log-btns";
+
+            this._collapseBtn = document.createElement("input");
+            this._collapseBtn.type = "button";
+            this._collapseBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._collapseBtn.className = "yui-log-button";
+            this._collapseBtn.value = "Collapse";
+            this._collapseBtn = this._collapseEl.appendChild(this._collapseBtn);
+            YAHOO.util.Event.addListener(oSelf._collapseBtn,'click',oSelf._onClickCollapseBtn,oSelf);
+
+            this._title = this._hdEl.appendChild(document.createElement("h4"));
+            this._title.innerHTML = "Logger Console";
+
+            // If Drag and Drop utility is available...
+            // ...and this container was created from scratch...
+            // ...then make the header draggable
+            if(YAHOO.util.DD &&
+            (YAHOO.widget.LogReader._defaultContainerEl == this._containerEl)) {
+                var ylog_dd = new YAHOO.util.DD(this._containerEl.id);
+                ylog_dd.setHandleElId(this._hdEl.id);
+                this._hdEl.style.cursor = "move";
+            }
+        }
+        // Ceate console
+        if(!this._consoleEl) {
+            this._consoleEl = this._containerEl.appendChild(document.createElement("div"));
+            this._consoleEl.className = "yui-log-bd";
+            
+            // If implementer has provided console, trust and set those
+            if(this.height) {
+                this._consoleEl.style.height = this.height;
+            }
+        }
+        // Don't create footer if disabled
+        if(!this._ftEl && this.footerEnabled) {
+            this._ftEl = this._containerEl.appendChild(document.createElement("div"));
+            this._ftEl.className = "yui-log-ft";
+
+            this._btnsEl = this._ftEl.appendChild(document.createElement("div"));
+            this._btnsEl.className = "yui-log-btns";
+
+            this._pauseBtn = document.createElement("input");
+            this._pauseBtn.type = "button";
+            this._pauseBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._pauseBtn.className = "yui-log-button";
+            this._pauseBtn.value = "Pause";
+            this._pauseBtn = this._btnsEl.appendChild(this._pauseBtn);
+            YAHOO.util.Event.addListener(oSelf._pauseBtn,'click',oSelf._onClickPauseBtn,oSelf);
+
+            this._clearBtn = document.createElement("input");
+            this._clearBtn.type = "button";
+            this._clearBtn.style.fontSize = YAHOO.util.Dom.getStyle(this._containerEl,"fontSize");
+            this._clearBtn.className = "yui-log-button";
+            this._clearBtn.value = "Clear";
+            this._clearBtn = this._btnsEl.appendChild(this._clearBtn);
+            YAHOO.util.Event.addListener(oSelf._clearBtn,'click',oSelf._onClickClearBtn,oSelf);
+
+            this._categoryFiltersEl = this._ftEl.appendChild(document.createElement("div"));
+            this._categoryFiltersEl.className = "yui-log-categoryfilters";
+            this._sourceFiltersEl = this._ftEl.appendChild(document.createElement("div"));
+            this._sourceFiltersEl.className = "yui-log-sourcefilters";
+        }
+    }
+
+    // Initialize buffer
+    if(!this._buffer) {
+        this._buffer = []; // output buffer
+    }
+    YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog, this);
+    this._lastTime = YAHOO.widget.Logger.getStartTime(); // timestamp of last log message to console
+
+    // Initialize category filters
+    this._categoryFilters = [];
+    var catsLen = YAHOO.widget.Logger.categories.length;
+    if(this._categoryFiltersEl) {
+        for(var i=0; i < catsLen; i++) {
+            this._createCategoryCheckbox(YAHOO.widget.Logger.categories[i]);
+        }
+    }
+    // Initialize source filters
+    this._sourceFilters = [];
+    var sourcesLen = YAHOO.widget.Logger.sources.length;
+    if(this._sourceFiltersEl) {
+        for(var j=0; j < sourcesLen; j++) {
+            this._createSourceCheckbox(YAHOO.widget.Logger.sources[j]);
+        }
+    }
+    YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate, this);
+    YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate, this);
+
+    YAHOO.widget.LogReader._index++;
+    this._filterLogs();
+};
+
+/***************************************************************************
+ * Public members
+ ***************************************************************************/
+/**
+ * Whether or not the log reader is enabled to output log messages. Default:
+ * true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.logReaderEnabled = true;
+
+/**
+ * Public member to access CSS width of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.width = null;
+
+/**
+ * Public member to access CSS height of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.height = null;
+
+/**
+ * Public member to access CSS top position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.top = null;
+
+/**
+ * Public member to access CSS left position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.left = null;
+
+/**
+ * Public member to access CSS right position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.right = null;
+
+/**
+ * Public member to access CSS bottom position of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.bottom = null;
+
+/**
+ * Public member to access CSS font size of the log reader container.
+ *
+ * @type string
+ */
+YAHOO.widget.LogReader.prototype.fontSize = null;
+
+/**
+ * Whether or not the footer UI is enabled for the log reader. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.footerEnabled = true;
+
+/**
+ * Whether or not output is verbose (more readable). Setting to true will make
+ * output more compact (less readable). Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.verboseOutput = true;
+
+/**
+ * Whether or not newest message is printed on top. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.LogReader.prototype.newestOnTop = true;
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+/**
+ * Pauses output of log messages. While paused, log messages are not lost, but
+ * get saved to a buffer and then output upon resume of log reader.
+ */
+YAHOO.widget.LogReader.prototype.pause = function() {
+    this._timeout = null;
+    this.logReaderEnabled = false;
+};
+
+/**
+ * Resumes output of log messages, including outputting any log messages that
+ * have been saved to buffer while paused.
+ */
+YAHOO.widget.LogReader.prototype.resume = function() {
+    this.logReaderEnabled = true;
+    this._printBuffer();
+};
+
+/**
+ * Hides UI of log reader. Logging functionality is not disrupted.
+ */
+YAHOO.widget.LogReader.prototype.hide = function() {
+    this._containerEl.style.display = "none";
+};
+
+/**
+ * Shows UI of log reader. Logging functionality is not disrupted.
+ */
+YAHOO.widget.LogReader.prototype.show = function() {
+    this._containerEl.style.display = "block";
+};
+
+/**
+ * Updates title to given string.
+ *
+ * @param {string} sTitle String to display in log reader's title bar.
+ */
+YAHOO.widget.LogReader.prototype.setTitle = function(sTitle) {
+    var regEx = />/g;
+    sTitle = sTitle.replace(regEx,"&gt;");
+    regEx = /</g;
+    sTitle = sTitle.replace(regEx,"&lt;");
+    this._title.innerHTML = (sTitle);
+};
+ /***************************************************************************
+ * Private members
+ ***************************************************************************/
+/**
+ * Internal class member to index multiple log reader instances.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.LogReader._index = 0;
+
+/**
+ * A class member shared by all log readers if a container needs to be
+ * created during instantiation. Will be null if a container element never needs to
+ * be created on the fly, such as when the implementer passes in their own element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader._defaultContainerEl = null;
+
+/**
+ * Buffer of log messages for batch output.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._buffer = null;
+
+/**
+ * Date of last output log message.
+ *
+ * @type date
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._lastTime = null;
+
+/**
+ * Batched output timeout ID.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._timeout = null;
+
+/**
+ * Array of filters for log message categories.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._categoryFilters = null;
+
+/**
+ * Array of filters for log message sources.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sourceFilters = null;
+
+/**
+ * Log reader container element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._containerEl = null;
+
+/**
+ * Log reader header element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._hdEl = null;
+
+/**
+ * Log reader collapse element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._collapseEl = null;
+
+/**
+ * Log reader collapse button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._collapseBtn = null;
+
+/**
+ * Log reader title header element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._title = null;
+
+/**
+ * Log reader console element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._consoleEl = null;
+
+/**
+ * Log reader footer element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._ftEl = null;
+
+/**
+ * Log reader buttons container element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._btnsEl = null;
+
+/**
+ * Container element for log reader category filter checkboxes.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._categoryFiltersEl = null;
+
+/**
+ * Container element for log reader source filter checkboxes.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sourceFiltersEl = null;
+
+/**
+ * Log reader pause button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._pauseBtn = null;
+
+/**
+ * lear button element.
+ *
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._clearBtn = null;
+/***************************************************************************
+ * Private methods
+ ***************************************************************************/
+/**
+ * Creates the UI for a category filter in the log reader footer element.
+ *
+ * @param {string} category Category name
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._createCategoryCheckbox = function(category) {
+    var oSelf = this;
+    
+    if(this._ftEl) {
+        var parentEl = this._categoryFiltersEl;
+        var filters = this._categoryFilters;
+
+        var filterEl = parentEl.appendChild(document.createElement("span"));
+        filterEl.className = "yui-log-filtergrp";
+            // Append el at the end so IE 5.5 can set "type" attribute
+            // and THEN set checked property
+            var categoryChk = document.createElement("input");
+            categoryChk.id = "yui-log-filter-" + category + YAHOO.widget.LogReader._index;
+            categoryChk.className = "yui-log-filter-" + category;
+            categoryChk.type = "checkbox";
+            categoryChk.category = category;
+            categoryChk = filterEl.appendChild(categoryChk);
+            categoryChk.checked = true;
+
+            // Add this checked filter to the internal array of filters
+            filters.push(category);
+            // Subscribe to the click event
+            YAHOO.util.Event.addListener(categoryChk,'click',oSelf._onCheckCategory,oSelf);
+
+            // Create and class the text label
+            var categoryChkLbl = filterEl.appendChild(document.createElement("label"));
+            categoryChkLbl.htmlFor = categoryChk.id;
+            categoryChkLbl.className = category;
+            categoryChkLbl.innerHTML = category;
+    }
+};
+
+YAHOO.widget.LogReader.prototype._createSourceCheckbox = function(source) {
+    var oSelf = this;
+
+    if(this._ftEl) {
+        var parentEl = this._sourceFiltersEl;
+        var filters = this._sourceFilters;
+
+        var filterEl = parentEl.appendChild(document.createElement("span"));
+        filterEl.className = "yui-log-filtergrp";
+
+        // Append el at the end so IE 5.5 can set "type" attribute
+        // and THEN set checked property
+        var sourceChk = document.createElement("input");
+        sourceChk.id = "yui-log-filter" + source + YAHOO.widget.LogReader._index;
+        sourceChk.className = "yui-log-filter" + source;
+        sourceChk.type = "checkbox";
+        sourceChk.source = source;
+        sourceChk = filterEl.appendChild(sourceChk);
+        sourceChk.checked = true;
+
+        // Add this checked filter to the internal array of filters
+        filters.push(source);
+        // Subscribe to the click event
+        YAHOO.util.Event.addListener(sourceChk,'click',oSelf._onCheckSource,oSelf);
+
+        // Create and class the text label
+        var sourceChkLbl = filterEl.appendChild(document.createElement("label"));
+        sourceChkLbl.htmlFor = sourceChk.id;
+        sourceChkLbl.className = source;
+        sourceChkLbl.innerHTML = source;
+    }
+};
+
+/**
+ * Reprints all log messages in the stack through filters.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._filterLogs = function() {
+    // Reprint stack with new filters
+    if (this._consoleEl !== null) {
+        this._clearConsole();
+        this._printToConsole(YAHOO.widget.Logger.getStack());
+    }
+};
+
+/**
+ * Clears all outputted log messages from the console and resets the time of the
+ * last output log message.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._clearConsole = function() {
+    // Clear the buffer of any pending messages
+    this._timeout = null;
+    this._buffer = [];
+
+    // Reset the rolling timer
+    this._lastTime = YAHOO.widget.Logger.getStartTime();
+
+    var consoleEl = this._consoleEl;
+    while(consoleEl.hasChildNodes()) {
+        consoleEl.removeChild(consoleEl.firstChild);
+    }
+};
+
+/**
+ * Sends buffer of log messages to output and clears buffer.
+ *
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printBuffer = function() {
+    this._timeout = null;
+
+    if (this._consoleEl !== null) {
+        var entries = [];
+        for (var i=0; i<this._buffer.length; i++) {
+            entries[i] = this._buffer[i];
+        }
+        this._buffer = [];
+        this._printToConsole(entries);
+        if(!this.newestOnTop) {
+            this._consoleEl.scrollTop = this._consoleEl.scrollHeight;
+        }
+    }
+};
+
+/**
+ * Cycles through an array of log messages, and outputs each one to the console
+ * if its category has not been filtered out.
+ *
+ * @param {array} aEntries
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printToConsole = function(aEntries) {
+    var entriesLen = aEntries.length;
+    var sourceFiltersLen = this._sourceFilters.length;
+    var categoryFiltersLen = this._categoryFilters.length;
+    // Iterate through all log entries to print the ones that filter through
+    for(var i=0; i<entriesLen; i++) {
+        var entry = aEntries[i];
+        var category = entry.category;
+        var source = entry.source;
+        var sourceDetail = entry.sourceDetail;
+        var okToPrint = false;
+        var okToFilterCats = false;
+
+        for(var j=0; j<sourceFiltersLen; j++) {
+            if(source == this._sourceFilters[j]) {
+                okToFilterCats = true;
+                break;
+            }
+        }
+        if(okToFilterCats) {
+            for(var k=0; k<categoryFiltersLen; k++) {
+                if(category == this._categoryFilters[k]) {
+                    okToPrint = true;
+                    break;
+                }
+            }
+        }
+        if(okToPrint) {
+            // To format for console, calculate the elapsed time
+            // to be from the last item that passed through the filter,
+            // not the absolute previous item in the stack
+            var label = entry.category.substring(0,4).toUpperCase();
+
+            var time = entry.time;
+            if (time.toLocaleTimeString) {
+                var localTime  = time.toLocaleTimeString();
+            }
+            else {
+                localTime = time.toString();
+            }
+
+            var msecs = time.getTime();
+            var startTime = YAHOO.widget.Logger.getStartTime();
+            var totalTime = msecs - startTime;
+            var elapsedTime = msecs - this._lastTime;
+            this._lastTime = msecs;
+            
+            var verboseOutput = (this.verboseOutput) ? "<br>" : "";
+            var sourceAndDetail = (sourceDetail) ?
+                source + " " + sourceDetail : source;
+
+            var output =  "<span class='"+category+"'>"+label+"</span> " +
+                totalTime + "ms (+" +
+                elapsedTime + ") " + localTime + ": " +
+                sourceAndDetail + ": " +
+                verboseOutput +
+                entry.msg;
+
+            var oNewElement = (this.newestOnTop) ?
+                this._consoleEl.insertBefore(document.createElement("p"),this._consoleEl.firstChild):
+                this._consoleEl.appendChild(document.createElement("p"));
+            oNewElement.innerHTML = output;
+        }
+    }
+};
+
+/***************************************************************************
+ * Private event handlers
+ ***************************************************************************/
+/**
+ * Handles Logger's categoryCreateEvent.
+ *
+ * @param {string} type The event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCategoryCreate = function(type, args, oSelf) {
+    var category = args[0];
+    if(oSelf._ftEl) {
+        oSelf._createCategoryCheckbox(category);
+    }
+};
+
+/**
+ * Handles Logger's sourceCreateEvent.
+ *
+ * @param {string} type The event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onSourceCreate = function(type, args, oSelf) {
+    var source = args[0];
+    if(oSelf._ftEl) {
+        oSelf._createSourceCheckbox(source);
+    }
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckCategory = function(v, oSelf) {
+    var newFilter = this.category;
+    var filtersArray = oSelf._categoryFilters;
+
+    if(!this.checked) { // Remove category from filters
+        for(var i=0; i<filtersArray.length; i++) {
+            if(newFilter == filtersArray[i]) {
+                filtersArray.splice(i, 1);
+                break;
+            }
+        }
+    }
+    else { // Add category to filters
+        filtersArray.push(newFilter);
+    }
+    oSelf._filterLogs();
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckSource = function(v, oSelf) {
+    var newFilter = this.source;
+    var filtersArray = oSelf._sourceFilters;
+    
+    if(!this.checked) { // Remove category from filters
+        for(var i=0; i<filtersArray.length; i++) {
+            if(newFilter == filtersArray[i]) {
+                filtersArray.splice(i, 1);
+                break;
+            }
+        }
+    }
+    else { // Add category to filters
+        filtersArray.push(newFilter);
+    }
+    oSelf._filterLogs();
+};
+
+/**
+ * Handles click events on the collapse button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickCollapseBtn = function(v, oSelf) {
+    var btn = oSelf._collapseBtn;
+    if(btn.value == "Expand") {
+        oSelf._consoleEl.style.display = "block";
+        if(oSelf._ftEl) {
+            oSelf._ftEl.style.display = "block";
+        }
+        btn.value = "Collapse";
+    }
+    else {
+        oSelf._consoleEl.style.display = "none";
+        if(oSelf._ftEl) {
+            oSelf._ftEl.style.display = "none";
+        }
+        btn.value = "Expand";
+    }
+};
+
+/**
+ * Handles click events on the pause button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickPauseBtn = function(v, oSelf) {
+    var btn = oSelf._pauseBtn;
+    if(btn.value == "Resume") {
+        oSelf.resume();
+        btn.value = "Pause";
+    }
+    else {
+        oSelf.pause();
+        btn.value = "Resume";
+    }
+};
+
+/**
+ * Handles click events on the clear button.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickClearBtn = function(v, oSelf) {
+    oSelf._clearConsole();
+};
+
+/**
+ * Handles Logger's onNewEvent.
+ *
+ * @param {string} type The click event
+ * @param {array} args Data passed from event firer
+ * @param {object} oSelf The log reader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onNewLog = function(type, args, oSelf) {
+    var logEntry = args[0];
+    oSelf._buffer.push(logEntry);
+
+    if (oSelf.logReaderEnabled === true && oSelf._timeout === null) {
+        oSelf._timeout = setTimeout(function(){oSelf._printBuffer();}, 100);
+    }
+};
+
+

Added: trunk/theme/src/bin/portal-ajax-war/js/portal/PortalDD.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/portal/PortalDD.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/portal/PortalDD.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,207 @@
+log = new YAHOO.widget.LogWriter("portalDnD");
+
+var borderBefore = "";
+var borderTopBefore = "";
+var ajaxEnabled = true;
+
+var borderSet = false;
+
+var ajaxURI = "/dndRenderer/ajax";
+
+var host = "";
+
+function setAjaxEnabled(enabled) {
+	ajaxEnabled = enabled;
+}
+
+function getBorder(id) {
+    log.log("getBorder...", "info");	
+
+	YAHOO.util.Dom.setStyle(id, "border-top", "0px");
+	YAHOO.util.Dom.setStyle(id, "border", "0px");
+    borderBefore = "";
+    borderTopBefore = "";
+    borderSet = false;
+}
+
+function setBorder(id) {
+	if (!borderSet) {
+    	borderTopBefore = YAHOO.util.Dom.getStyle(id, "border-top");
+    	borderBefore = YAHOO.util.Dom.getStyle(id, "border");
+    	borderSet = true;
+    }
+    
+    //YAHOO.util.Dom.setStyle(id, "border-top", "2px solid red");
+    //YAHOO.util.Dom.setStyle(id, "border-top", "2px dashed red");
+    YAHOO.util.Dom.setStyle(id, "border", "2px dashed green");
+    
+}
+
+function persitNewPosition(positionNo, windowId, oldRegionId, newRegionId) {
+	postData = "action=PERSIST&positionNo="+encodeURI(positionNo)+"&windowId="+encodeURI(windowId)+"&oldRegionId="+encodeURI(oldRegionId)+"&newRegionId="+encodeURI(newRegionId);
+	
+	log.log(postData);
+	invokeAjax(postData);
+}
+
+function invokeAjax(postData) {
+	if (ajaxEnabled) {
+	    var handleSuccess = function(o){ 
+		 
+		    if(o.responseText !== undefined){ 
+		        log.log("Transaction id: " + o.tId); 
+		        log.log("HTTP status: " + o.status); 
+		        log.log("Status code message: " + o.statusText); 
+		        log.log("<li>HTTP headers: <ul>" + o.getAllResponseHeaders + "</ul></li>"); 
+		        log.log("Servlet response: " + o.responseText); 
+		        log.log("Argument object: " + o.argument); 
+		    } 
+		} 
+		
+		var handleFailure = function(o) {
+			log.log("Failure: " + o);
+		}
+		 
+		var callback = 
+		{ 
+		  success:handleSuccess, 
+		  failure: handleFailure, 
+		  argument: [] 
+		}; 
+		
+		var request = YAHOO.util.Connect.asyncRequest('POST', host+ajaxURI, callback, postData);
+	}
+}
+
+YAHOO.util.PortalDD = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+        this.initFrame();
+    }
+};
+
+YAHOO.extend(YAHOO.util.PortalDD, YAHOO.util.DDProxy);
+
+YAHOO.util.PortalDD.prototype.onDragOver = function(e, id) {
+    YAHOO.util.PortalDD.superclass.onDragOver.call(this, e, id);
+    
+    // draw a border around dropto portlet
+    setBorder(id);
+}
+
+YAHOO.util.PortalDD.prototype.onDragOut = function(e, id) {
+    YAHOO.util.PortalDD.superclass.onDragOut.call(this, e, id);
+    
+    // remove the border around dropto portlet
+    getBorder(id);
+}
+
+YAHOO.util.PortalDD.prototype.onDragDrop = function(e, id) {
+    log.log("in PortalDD onDragDrop", "info");
+    
+    // remove the border around dropto portlet
+    getBorder(id);
+    
+    var el = this.getEl();
+	var droped = document.getElementById(id);
+	
+	var thisParent = el.parentNode;
+	var dropedParent = droped.parentNode;
+
+	// show region droper if needed
+	if (thisParent.childNodes.length == 2) {
+		var regToDrop = document.getElementById(thisParent.dropToRegion);
+	
+		YAHOO.util.Dom.setStyle(regToDrop, "display", "block");
+		YAHOO.util.Dom.setStyle(regToDrop, "visibility", "");
+	}
+    
+	thisParent.removeChild(el);
+	dropedParent.appendChild(el);
+	
+	// hide region droper if needed
+	if (dropedParent.childNodes.length == 2) {
+		var regToDrop = document.getElementById(dropedParent.dropToRegion);
+	
+		YAHOO.util.Dom.setStyle(regToDrop, "display", "none");
+		YAHOO.util.Dom.setStyle(regToDrop, "visibility", "hidden");
+	} 
+	log.log("AFTER Parent: " + el.parentNode + "(" + el.parentNode.id +")"+" droped: " + droped.parentNode + "(" + droped.parentNode.id +")");
+	
+	log.log( "position: " + YAHOO.util.Dom.getStyle(el, "position"));
+	YAHOO.util.Dom.setStyle(el, "position", "static");
+	
+	var nodeList = dropedParent.childNodes;
+	
+	var adding = false;YAHOO.util.PortalDD
+	
+	// move down all the nodes under the portlet (including dropto portlet)
+	var i = 0;
+	while ((nodeList.item(i) != el) && (i < nodeList.length)) {
+		var nextNode = nodeList.item(i);
+		if (!adding && nextNode == droped) {
+			adding = true;
+		}
+		
+		if (adding) {
+			dropedParent.appendChild(nextNode);
+		}
+		else {
+			i++;
+		}
+	}
+	
+	if (nodeList.item(0).id.indexOf("regionDrop") == 0) {
+		i--;
+	}
+	
+	log.log("new position: "+i+ " " + this.windowId);
+	persitNewPosition(i, this.windowId, thisParent.regionId, dropedParent.regionId);
+};
+
+YAHOO.util.PortalDD.prototype.endDrag = function(e) {
+	// PortalDD changes 
+	// Don't move the portlet - it'll be placed by the browser
+	// Just remove the proxy frame
+	
+    var DOM = YAHOO.util.Dom;
+    this.logger.log(this.id + " endDrag");
+    //var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    // del.style.visibility = "";
+    DOM.setStyle(del, "visibility", ""); 
+
+    // Hide the linked element before the move to get around a Safari 
+    // rendering bug.
+    //lel.style.visibility = "hidden";
+    //DOM.setStyle(lel, "visibility", "hidden"); 
+    //YAHOO.util.DDM.moveToEl(lel, del);
+    //del.style.visibility = "hidden";
+    DOM.setStyle(del, "visibility", "hidden"); 
+    //lel.style.visibility = "";
+    //DOM.setStyle(lel, "visibility", ""); 
+};
+
+// cleans up regionDD renderer from some crap wrongly intepreted by a browser
+function cleanUpDocument(id) {
+	var region = document.getElementById(id);
+	var nodeList = region.childNodes;
+/*	
+	// move down all the nodes under the portlet (including dropto portlet)
+	var i = 0;
+	while (i < nodeList.length) {
+		var nextNode = nodeList.item(i);
+		
+		log.log(nextNode, "warn");
+		if (nextNode instanceof Text) {
+			log.log("next one: "+id+" "+ i);
+			region.removeChild(nextNode);
+		}
+		else {
+			i++;
+		}
+	}
+*/
+}

Added: trunk/theme/src/bin/portal-ajax-war/js/yahoo/README
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/yahoo/README	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/yahoo/README	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,10 @@
+YAHOO Global Namespace - Release Notes
+
+0.11.0
+   * Added YAHOO.extend, which provides an easy way to assign the prototype,
+     constructor, and superclass properties inheritance properties.  It also
+     prevents the constructor of the superclass from being exectuted twice.
+
+0.10.0
+   * Added YAHOO.log that provides a safe way to plumb logging statements in
+     code that will work if the logging component isn't available.

Added: trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-debug.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-debug.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-debug.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,85 @@
+
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
+Code licensed under the BSD License:                                                                                                                    
+http://developer.yahoo.net/yui/license.txt                                                                                                              
+version: 0.11.0                                                                                                                                         
+*/ 
+
+/**
+ * The Yahoo global namespace
+ * @constructor
+ */
+var YAHOO = window.YAHOO || {};
+
+/**
+ * Returns the namespace specified and creates it if it doesn't exist
+ *
+ * YAHOO.namespace("property.package");
+ * YAHOO.namespace("YAHOO.property.package");
+ *
+ * Either of the above would create YAHOO.property, then
+ * YAHOO.property.package
+ *
+ * @param  {String} ns The name of the namespace
+ * @return {Object}    A reference to the namespace object
+ */
+YAHOO.namespace = function(ns) {
+
+    if (!ns || !ns.length) {
+        return null;
+    }
+
+    var levels = ns.split(".");
+    var nsobj = YAHOO;
+
+    // YAHOO is implied, so it is ignored if it is included
+    for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
+        nsobj[levels[i]] = nsobj[levels[i]] || {};
+        nsobj = nsobj[levels[i]];
+    }
+
+    return nsobj;
+};
+
+/**
+ * Uses YAHOO.widget.Logger to output a log message, if the widget is available.
+ *
+ * @param  {string}  sMsg       The message to log.
+ * @param  {string}  sCategory  The log category for the message.  Default
+ *                              categories are "info", "warn", "error", time".
+ *                              Custom categories can be used as well. (opt)
+ * @param  {string}  sSource    The source of the the message (opt)
+ * @return {boolean}            True if the log operation was successful.
+ */
+YAHOO.log = function(sMsg, sCategory, sSource) {
+    var l = YAHOO.widget.Logger;
+    if(l && l.log) {
+        return l.log(sMsg, sCategory, sSource);
+    } else {
+        return false;
+    }
+};
+
+/**
+ * Utility to set up the prototype, constructor and superclass properties to
+ * support an inheritance strategy that can chain constructors and methods.
+ *
+ * @param {Function} subclass   the object to modify
+ * @param {Function} superclass the object to inherit
+ */
+YAHOO.extend = function(subclass, superclass) {
+    var f = function() {};
+    f.prototype = superclass.prototype;
+    subclass.prototype = new f();
+    subclass.prototype.constructor = subclass;
+    subclass.superclass = superclass.prototype;
+    if (superclass.prototype.constructor == Object.prototype.constructor) {
+        superclass.prototype.constructor = superclass;
+    }
+};
+
+YAHOO.namespace("util");
+YAHOO.namespace("widget");
+YAHOO.namespace("example");
+

Added: trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-min.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-min.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo-min.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1 @@
+/*                                                                                                                                                      Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    Code licensed under the BSD License:                                                                                                                    http://developer.yahoo.net/yui/license.txt                                                                                                              version: 0.11.0                                                                                                                                         */ var YAHOO=window.YAHOO||{};YAHOO.namespace=function(ns){if(!ns||!ns.length){return null;}var _2=ns.split(".");var _3=YAHOO;for(var i=(_2[0]=="YAHOO")?1:0;i<_2.length;++i){_3[_2[i]]=_3[_2[i]]||{};_3=_3[_2[i]];}return _3;};YAHO!
 O.log=function(_5,_6,_7){var l=YAHOO.widget.Logger;if(l&&l.log){return l.log(_5,_6,_7);}else{return false;}};YAHOO.extend=function(_9,_10){var f=function(){};f.prototype=_10.prototype;_9.prototype=new f();_9.prototype.constructor=_9;_9.superclass=_10.prototype;if(_10.prototype.constructor==Object.prototype.constructor){_10.prototype.constructor=_10;}};YAHOO.namespace("util");YAHOO.namespace("widget");YAHOO.namespace("example");
\ No newline at end of file

Added: trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo.js
===================================================================
--- trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo.js	2006-09-13 20:07:58 UTC (rev 5193)
+++ trunk/theme/src/bin/portal-ajax-war/js/yahoo/yahoo.js	2006-09-13 20:09:38 UTC (rev 5194)
@@ -0,0 +1,84 @@
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
+Code licensed under the BSD License:                                                                                                                    
+http://developer.yahoo.net/yui/license.txt                                                                                                              
+version: 0.11.0                                                                                                                                         
+*/ 
+
+/**
+ * The Yahoo global namespace
+ * @constructor
+ */
+var YAHOO = window.YAHOO || {};
+
+/**
+ * Returns the namespace specified and creates it if it doesn't exist
+ *
+ * YAHOO.namespace("property.package");
+ * YAHOO.namespace("YAHOO.property.package");
+ *
+ * Either of the above would create YAHOO.property, then
+ * YAHOO.property.package
+ *
+ * @param  {String} ns The name of the namespace
+ * @return {Object}    A reference to the namespace object
+ */
+YAHOO.namespace = function(ns) {
+
+    if (!ns || !ns.length) {
+        return null;
+    }
+
+    var levels = ns.split(".");
+    var nsobj = YAHOO;
+
+    // YAHOO is implied, so it is ignored if it is included
+    for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
+        nsobj[levels[i]] = nsobj[levels[i]] || {};
+        nsobj = nsobj[levels[i]];
+    }
+
+    return nsobj;
+};
+
+/**
+ * Uses YAHOO.widget.Logger to output a log message, if the widget is available.
+ *
+ * @param  {string}  sMsg       The message to log.
+ * @param  {string}  sCategory  The log category for the message.  Default
+ *                              categories are "info", "warn", "error", time".
+ *                              Custom categories can be used as well. (opt)
+ * @param  {string}  sSource    The source of the the message (opt)
+ * @return {boolean}            True if the log operation was successful.
+ */
+YAHOO.log = function(sMsg, sCategory, sSource) {
+    var l = YAHOO.widget.Logger;
+    if(l && l.log) {
+        return l.log(sMsg, sCategory, sSource);
+    } else {
+        return false;
+    }
+};
+
+/**
+ * Utility to set up the prototype, constructor and superclass properties to
+ * support an inheritance strategy that can chain constructors and methods.
+ *
+ * @param {Function} subclass   the object to modify
+ * @param {Function} superclass the object to inherit
+ */
+YAHOO.extend = function(subclass, superclass) {
+    var f = function() {};
+    f.prototype = superclass.prototype;
+    subclass.prototype = new f();
+    subclass.prototype.constructor = subclass;
+    subclass.superclass = superclass.prototype;
+    if (superclass.prototype.constructor == Object.prototype.constructor) {
+        superclass.prototype.constructor = superclass;
+    }
+};
+
+YAHOO.namespace("util");
+YAHOO.namespace("widget");
+YAHOO.namespace("example");
+




More information about the jboss-svn-commits mailing list