[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&®ion.right<=this.right&®ion.top>=this.top&®ion.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,">");
+ regEx = /</g;
+ sTitle = sTitle.replace(regEx,"<");
+ 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,">");regEx=/</g;sTitle=sTitle.replace(regEx,"<");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,">");
+ regEx = /</g;
+ sTitle = sTitle.replace(regEx,"<");
+ 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