Index: openacs-4/packages/ajaxhelper/www/resources/yui/connection/connection.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ajaxhelper/www/resources/yui/connection/connection.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/ajaxhelper/www/resources/yui/connection/connection.js 25 Dec 2006 16:40:01 -0000 1.2 +++ openacs-4/packages/ajaxhelper/www/resources/yui/connection/connection.js 8 Sep 2007 14:22:01 -0000 1.3 @@ -1,960 +1,1359 @@ -/* -Copyright (c) 2006, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 0.12.1 -*/ - -/** - * @description - * 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. - * - * @namespace YAHOO.util - * @module Connection - * @Class Connect - */ -YAHOO.util.Connect = -{ - /** - * @description Array of MSFT ActiveX ids for XMLHttpRequest. - * @property _msxml_progid - * @private - * @static - * @type array - */ - _msxml_progid:[ - 'MSXML2.XMLHTTP.3.0', - 'MSXML2.XMLHTTP', - 'Microsoft.XMLHTTP' - ], - - /** - * @description Object literal of HTTP header(s) - * @property _http_header - * @private - * @static - * @type object - */ - _http_header:{}, - - /** - * @description Determines if HTTP headers are set. - * @property _has_http_headers - * @private - * @static - * @type boolean - */ - _has_http_headers:false, - - /** - * @description 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. - * @property _use_default_post_header - * @private - * @static - * @type boolean - */ - _use_default_post_header:true, - - /** - * @description 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. - * @property _default_post_header - * @private - * @static - * @type boolean - */ - _default_post_header:'application/x-www-form-urlencoded', - - /** - * @description Property modified by setForm() to determine if the data - * should be submitted as an HTML form. - * @property _isFormSubmit - * @private - * @static - * @type boolean - */ - _isFormSubmit:false, - - /** - * @description Property modified by setForm() to determine if a file(s) - * upload is expected. - * @property _isFileUpload - * @private - * @static - * @type boolean - */ - _isFileUpload:false, - - /** - * @description Property modified by setForm() to set a reference to the HTML - * form node if the desired action is file upload. - * @property _formNode - * @private - * @static - * @type object - */ - _formNode:null, - - /** - * @description Property modified by setForm() to set the HTML form data - * for each transaction. - * @property _sFormData - * @private - * @static - * @type string - */ - _sFormData:null, - - /** - * @description Collection of polling references to the polling mechanism in handleReadyState. - * @property _poll - * @private - * @static - * @type object - */ - _poll:{}, - - /** - * @description Queue of timeout values for each transaction callback with a defined timeout value. - * @property _timeOut - * @private - * @static - * @type object - */ - _timeOut:{}, - - /** - * @description The polling frequency, in milliseconds, for HandleReadyState. - * when attempting to determine a transaction's XHR readyState. - * The default is 50 milliseconds. - * @property _polling_interval - * @private - * @static - * @type int - */ - _polling_interval:50, - - /** - * @description A transaction counter that increments the transaction id for each transaction. - * @property _transaction_id - * @private - * @static - * @type int - */ - _transaction_id:0, - - /** - * @description 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. - * @method setProgId - * @public - * @static - * @param {string} id The ActiveX id to be added to initialize the XHR object. - * @return void - */ - setProgId:function(id) - { - this._msxml_progid.unshift(id); - }, - - /** - * @description Member to enable or disable the default POST header. - * @method setDefaultPostHeader - * @public - * @static - * @param {boolean} b Set and use default header - true or false . - * @return void - */ - setDefaultPostHeader:function(b) - { - this._use_default_post_header = b; - }, - - /** - * @description Member to modify the default polling interval. - * @method setPollingInterval - * @public - * @static - * @param {int} i The polling interval in milliseconds. - * @return void - */ - setPollingInterval:function(i) - { - if(typeof i == 'number' && isFinite(i)){ - this._polling_interval = i; - } - }, - - /** - * @description Instantiates a XMLHttpRequest object and returns an object with two properties: - * the XMLHttpRequest instance and the transaction id. - * @method createXhrObject - * @private - * @static - * @param {int} transactionId Property containing the transaction id for this transaction. - * @return 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= 200 && httpStatus < 300){ - try - { - 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]); - } - } - } - catch(e){} - } - else{ - try - { - switch(httpStatus){ - // The following cases are wininet.dll error codes that may be encountered. - case 12002: // Server timeout - case 12029: // 12029 to 12031 correspond to dropped connections. - case 12030: - case 12031: - case 12152: // Connection closed by server. - case 13030: // See above comments for variable status. - responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false)); - 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]); - } - } - } - } - catch(e){} - } - - this.releaseObject(o); - responseObject = null; - }, - - /** - * @description 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. - * @method createResponseObject - * @private - * @static - * @param {object} o The connection object - * @param {callbackArg} callbackArg The 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'); - - // IE will throw a security exception in an SSL environment if the - // iframe source is undefined. - if(typeof secureUri == 'boolean'){ - io.src = 'javascript:false'; - } - else if(typeof secureURI == 'string'){ - // Deprecated - io.src = secureUri; - } - } - else{ - var io = document.createElement('iframe'); - io.id = frameId; - io.name = frameId; - } - - io.style.position = 'absolute'; - io.style.top = '-1000px'; - io.style.left = '-1000px'; - - document.body.appendChild(io); - }, - - /** - * @description Parses the POST data and creates hidden form elements - * for each key-value, and appends them to the HTML form object. - * @method appendPostData - * @private - * @static - * @param {string} postData The HTTP POST data - * @return {array} formElements Collection of hidden fields. - */ - appendPostData:function(postData) - { - var formElements = []; - var postMessage = postData.split('&'); - for(var i=0; i < postMessage.length; i++){ - var delimitPos = postMessage[i].indexOf('='); - if(delimitPos != -1){ - formElements[i] = document.createElement('input'); - formElements[i].type = 'hidden'; - formElements[i].name = postMessage[i].substring(0,delimitPos); - formElements[i].value = postMessage[i].substring(delimitPos+1); - this._formNode.appendChild(formElements[i]); - } - } - - return formElements; - }, - - /** - * @description Uploads HTML form, including files/attachments, to the - * iframe created in createFrame. - * @method uploadFile - * @private - * @static - * @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, postData){ - - // Each iframe has an id prefix of "yuiIO" followed - // by the unique transaction id. - var frameId = 'yuiIO' + id; - var io = document.getElementById(frameId); - - // Initialize the HTML form properties in case they are - // not defined in the HTML form. - this._formNode.action = uri; - this._formNode.method = 'POST'; - this._formNode.target = frameId; - - if(this._formNode.encoding){ - // IE does not respect property enctype for HTML forms. - // Instead use property encoding. - this._formNode.encoding = 'multipart/form-data'; - } - else{ - this._formNode.enctype = 'multipart/form-data'; - } - - if(postData){ - var oElements = this.appendPostData(postData); - } - - this._formNode.submit(); - - if(oElements && oElements.length > 0){ - try - { - for(var i=0; i < oElements.length; i++){ - this._formNode.removeChild(oElements[i]); - } - } - catch(e){} - } - - // Reset HTML form status properties. - this.resetFormState(); - - // 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 obj = {}; - obj.tId = id; - obj.argument = callback.argument; - - try - { - obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null; - obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document; - } - catch(e){} - - if(callback.upload){ - if(!callback.scope){ - callback.upload(obj); - } - else{ - callback.upload.apply(callback.scope, [obj]); - } - } - - if(YAHOO.util.Event){ - YAHOO.util.Event.removeListener(io, "load", uploadCallback); - } - else if(window.detachEvent){ - io.detachEvent('onload', uploadCallback); - } - else{ - io.removeEventListener('load', uploadCallback, false); - } - setTimeout(function(){ document.body.removeChild(io); }, 100); - }; - - - // Bind the onload handler to the iframe to detect the file upload response. - if(YAHOO.util.Event){ - YAHOO.util.Event.addListener(io, "load", uploadCallback); - } - else if(window.attachEvent){ - io.attachEvent('onload', uploadCallback); - } - else{ - io.addEventListener('load', uploadCallback, false); - } - }, - - /** - * @description Method to terminate a transaction, if it has not reached readyState 4. - * @method abort - * @public - * @static - * @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 {boolean} - */ - abort:function(o, callback, isTimeout) - { - if(this.isCallInProgress(o)){ - o.conn.abort(); - window.clearInterval(this._poll[o.tId]); - delete this._poll[o.tId]; - if(isTimeout){ - delete this._timeOut[o.tId]; - } - - this.handleTransactionResponse(o, callback, true); - - return true; - } - else{ - return false; - } - }, - - /** - * Public method to check if the transaction is still being processed. - * - * @method isCallInProgress - * @public - * @static - * @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; - } - }, - - /** - * @description Dereference the XHR instance and the connection object after the transaction is completed. - * @method releaseObject - * @private - * @static - * @param {object} o The connection object - * @return {void} - */ - releaseObject:function(o) - { - //dereference the XHR instance. - o.conn = null; - //dereference the connection object. - o = null; - } -}; \ No newline at end of file +/* +Copyright (c) 2007, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.3.0 +*/ +/** + * 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. + * + * @namespace YAHOO.util + * @module connection + * @requires yahoo + * @requires event + */ + +/** + * The Connection Manager singleton provides methods for creating and managing + * asynchronous transactions. + * + * @class Connect + */ + +YAHOO.util.Connect = +{ + /** + * @description Array of MSFT ActiveX ids for XMLHttpRequest. + * @property _msxml_progid + * @private + * @static + * @type array + */ + _msxml_progid:[ + 'MSXML2.XMLHTTP.3.0', + 'MSXML2.XMLHTTP', + 'Microsoft.XMLHTTP' + ], + + /** + * @description Object literal of HTTP header(s) + * @property _http_header + * @private + * @static + * @type object + */ + _http_headers:{}, + + /** + * @description Determines if HTTP headers are set. + * @property _has_http_headers + * @private + * @static + * @type boolean + */ + _has_http_headers:false, + + /** + * @description 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. + * @property _use_default_post_header + * @private + * @static + * @type boolean + */ + _use_default_post_header:true, + + /** + * @description Determines if a default header of + * Content-Type of 'application/x-www-form-urlencoded' + * will be added to client HTTP headers sent for POST + * transactions. + * @property _default_post_header + * @private + * @static + * @type boolean + */ + _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8', + + /** + * @description Determines if a default header of + * 'X-Requested-With: XMLHttpRequest' + * will be added to each transaction. + * @property _use_default_xhr_header + * @private + * @static + * @type boolean + */ + _use_default_xhr_header:true, + + /** + * @description The default header value for the label + * "X-Requested-With". This is sent with each + * transaction, by default, to identify the + * request as being made by YUI Connection Manager. + * @property _default_xhr_header + * @private + * @static + * @type boolean + */ + _default_xhr_header:'XMLHttpRequest', + + /** + * @description Determines if custom, default headers + * are set for each transaction. + * @property _has_default_header + * @private + * @static + * @type boolean + */ + _has_default_headers:true, + + /** + * @description Determines if custom, default headers + * are set for each transaction. + * @property _has_default_header + * @private + * @static + * @type boolean + */ + _default_headers:{}, + + /** + * @description Property modified by setForm() to determine if the data + * should be submitted as an HTML form. + * @property _isFormSubmit + * @private + * @static + * @type boolean + */ + _isFormSubmit:false, + + /** + * @description Property modified by setForm() to determine if a file(s) + * upload is expected. + * @property _isFileUpload + * @private + * @static + * @type boolean + */ + _isFileUpload:false, + + /** + * @description Property modified by setForm() to set a reference to the HTML + * form node if the desired action is file upload. + * @property _formNode + * @private + * @static + * @type object + */ + _formNode:null, + + /** + * @description Property modified by setForm() to set the HTML form data + * for each transaction. + * @property _sFormData + * @private + * @static + * @type string + */ + _sFormData:null, + + /** + * @description Collection of polling references to the polling mechanism in handleReadyState. + * @property _poll + * @private + * @static + * @type object + */ + _poll:{}, + + /** + * @description Queue of timeout values for each transaction callback with a defined timeout value. + * @property _timeOut + * @private + * @static + * @type object + */ + _timeOut:{}, + + /** + * @description The polling frequency, in milliseconds, for HandleReadyState. + * when attempting to determine a transaction's XHR readyState. + * The default is 50 milliseconds. + * @property _polling_interval + * @private + * @static + * @type int + */ + _polling_interval:50, + + /** + * @description A transaction counter that increments the transaction id for each transaction. + * @property _transaction_id + * @private + * @static + * @type int + */ + _transaction_id:0, + + /** + * @description Tracks the name-value pair of the "clicked" submit button if multiple submit + * buttons are present in an HTML form; and, if YAHOO.util.Event is available. + * @property _submitElementValue + * @private + * @static + * @type string + */ + _submitElementValue:null, + + /** + * @description Determines whether YAHOO.util.Event is available and returns true or false. + * If true, an event listener is bound at the document level to trap click events that + * resolve to a target type of "Submit". This listener will enable setForm() to determine + * the clicked "Submit" value in a multi-Submit button, HTML form. + * @property _hasSubmitListener + * @private + * @static + */ + _hasSubmitListener:(function() + { + if(YAHOO.util.Event){ + YAHOO.util.Event.addListener( + document, + 'click', + function(e){ + var obj = YAHOO.util.Event.getTarget(e); + if(obj.type == 'submit'){ + YAHOO.util.Connect._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value); + } + }); + return true; + } + return false; + })(), + + /** + * @description Custom event that fires at the start of a transaction + * @property startEvent + * @private + * @static + * @type CustomEvent + */ + startEvent: new YAHOO.util.CustomEvent('start'), + + /** + * @description Custom event that fires when a transaction response has completed. + * @property completeEvent + * @private + * @static + * @type CustomEvent + */ + completeEvent: new YAHOO.util.CustomEvent('complete'), + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 2xx range. + * @property successEvent + * @private + * @static + * @type CustomEvent + */ + successEvent: new YAHOO.util.CustomEvent('success'), + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 4xx/5xx range. + * @property failureEvent + * @private + * @static + * @type CustomEvent + */ + failureEvent: new YAHOO.util.CustomEvent('failure'), + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 4xx/5xx range. + * @property failureEvent + * @private + * @static + * @type CustomEvent + */ + uploadEvent: new YAHOO.util.CustomEvent('upload'), + + /** + * @description Custom event that fires when a transaction is successfully aborted. + * @property abortEvent + * @private + * @static + * @type CustomEvent + */ + abortEvent: new YAHOO.util.CustomEvent('abort'), + + /** + * @description A reference table that maps callback custom events members to its specific + * event name. + * @property _customEvents + * @private + * @static + * @type object + */ + _customEvents: + { + onStart:['startEvent', 'start'], + onComplete:['completeEvent', 'complete'], + onSuccess:['successEvent', 'success'], + onFailure:['failureEvent', 'failure'], + onUpload:['uploadEvent', 'upload'], + onAbort:['abortEvent', 'abort'] + }, + + /** + * @description 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. + * @method setProgId + * @public + * @static + * @param {string} id The ActiveX id to be added to initialize the XHR object. + * @return void + */ + setProgId:function(id) + { + this._msxml_progid.unshift(id); + }, + + /** + * @description Member to enable or disable the default POST header. + * @method setDefaultPostHeader + * @public + * @static + * @param {boolean} b Set and use default header - true or false . + * @return void + */ + setDefaultPostHeader:function(b) + { + this._use_default_post_header = b; + }, + + /** + * @description Member to enable or disable the default POST header. + * @method setDefaultXhrHeader + * @public + * @static + * @param {boolean} b Set and use default header - true or false . + * @return void + */ + setDefaultXhrHeader:function(b) + { + this._use_default_xhr_header = b; + }, + + /** + * @description Member to modify the default polling interval. + * @method setPollingInterval + * @public + * @static + * @param {int} i The polling interval in milliseconds. + * @return void + */ + setPollingInterval:function(i) + { + if(typeof i == 'number' && isFinite(i)){ + this._polling_interval = i; + } + }, + + /** + * @description Instantiates a XMLHttpRequest object and returns an object with two properties: + * the XMLHttpRequest instance and the transaction id. + * @method createXhrObject + * @private + * @static + * @param {int} transactionId Property containing the transaction id for this transaction. + * @return 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= 200 && httpStatus < 300 || httpStatus === 1223){ + 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]); + } + } + + // Fire global custom event -- successEvent + this.successEvent.fire(responseObject); + + if(o.successEvent){ + // Fire transaction custom event -- successEvent + o.successEvent.fire(responseObject); + } + } + else{ + switch(httpStatus){ + // The following cases are wininet.dll error codes that may be encountered. + case 12002: // Server timeout + case 12029: // 12029 to 12031 correspond to dropped connections. + case 12030: + case 12031: + case 12152: // Connection closed by server. + case 13030: // See above comments for variable status. + responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false)); + 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]); + } + } + } + + // Fire global custom event -- failureEvent + this.failureEvent.fire(responseObject); + + if(o.failureEvent){ + // Fire transaction custom event -- failureEvent + o.failureEvent.fire(responseObject); + } + + } + + this.releaseObject(o); + responseObject = null; + }, + + /** + * @description 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. + * @method createResponseObject + * @private + * @static + * @param {object} o The connection object + * @param {callbackArg} callbackArg The 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'); + + // IE will throw a security exception in an SSL environment if the + // iframe source is undefined. + if(typeof secureUri == 'boolean'){ + io.src = 'javascript:false'; + } + else if(typeof secureURI == 'string'){ + // Deprecated + io.src = secureUri; + } + } + else{ + io = document.createElement('iframe'); + io.id = frameId; + io.name = frameId; + } + + io.style.position = 'absolute'; + io.style.top = '-1000px'; + io.style.left = '-1000px'; + + document.body.appendChild(io); + }, + + /** + * @description Parses the POST data and creates hidden form elements + * for each key-value, and appends them to the HTML form object. + * @method appendPostData + * @private + * @static + * @param {string} postData The HTTP POST data + * @return {array} formElements Collection of hidden fields. + */ + appendPostData:function(postData) + { + var formElements = []; + var postMessage = postData.split('&'); + for(var i=0; i < postMessage.length; i++){ + var delimitPos = postMessage[i].indexOf('='); + if(delimitPos != -1){ + formElements[i] = document.createElement('input'); + formElements[i].type = 'hidden'; + formElements[i].name = postMessage[i].substring(0,delimitPos); + formElements[i].value = postMessage[i].substring(delimitPos+1); + this._formNode.appendChild(formElements[i]); + } + } + + return formElements; + }, + + /** + * @description Uploads HTML form, inclusive of files/attachments, using the + * iframe created in createFrame to facilitate the transaction. + * @method uploadFile + * @private + * @static + * @param {int} id The transaction id. + * @param {object} callback User-defined callback object. + * @param {string} uri Fully qualified path of resource. + * @param {string} postData POST data to be submitted in addition to HTML form. + * @return {void} + */ + uploadFile:function(o, callback, uri, postData){ + + // Each iframe has an id prefix of "yuiIO" followed + // by the unique transaction id. + var frameId = 'yuiIO' + o.tId; + var uploadEncoding = 'multipart/form-data'; + var io = document.getElementById(frameId); + var oConn = this; + + // Track original HTML form attribute values. + var rawFormAttributes = + { + action:this._formNode.getAttribute('action'), + method:this._formNode.getAttribute('method'), + target:this._formNode.getAttribute('target') + }; + + // Initialize the HTML form properties in case they are + // not defined in the HTML form. + this._formNode.setAttribute('action', uri); + this._formNode.setAttribute('method', 'POST'); + this._formNode.setAttribute('target', frameId); + + if(this._formNode.encoding){ + // IE does not respect property enctype for HTML forms. + // Instead it uses the property - "encoding". + this._formNode.setAttribute('encoding', uploadEncoding); + } + else{ + this._formNode.setAttribute('enctype', uploadEncoding); + } + + if(postData){ + var oElements = this.appendPostData(postData); + } + + // Start file upload. + this._formNode.submit(); + + // Fire global custom event -- startEvent + this.startEvent.fire(o); + + if(o.startEvent){ + // Fire transaction custom event -- startEvent + o.startEvent.fire(o); + } + + // Start polling if a callback is present and the timeout + // property has been defined. + if(callback && callback.timeout){ + this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout); + } + + // Remove HTML elements created by appendPostData + if(oElements && oElements.length > 0){ + for(var i=0; i < oElements.length; i++){ + this._formNode.removeChild(oElements[i]); + } + } + + // Restore HTML form attributes to their original + // values prior to file upload. + for(var prop in rawFormAttributes){ + if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){ + if(rawFormAttributes[prop]){ + this._formNode.setAttribute(prop, rawFormAttributes[prop]); + } + else{ + this._formNode.removeAttribute(prop); + } + } + } + + // Reset HTML form state properties. + this.resetFormState(); + + // 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() + { + if(callback && callback.timeout){ + window.clearTimeout(oConn._timeOut[o.tId]); + delete oConn._timeOut[o.tId]; + } + + // Fire global custom event -- completeEvent + oConn.completeEvent.fire(o); + + if(o.completeEvent){ + // Fire transaction custom event -- completeEvent + o.completeEvent.fire(o); + } + + var obj = {}; + obj.tId = o.tId; + obj.argument = callback.argument; + + try + { + // responseText and responseXML will be populated with the same data from the iframe. + // Since the HTTP headers cannot be read from the iframe + obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent; + obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document; + } + catch(e){} + + if(callback && callback.upload){ + if(!callback.scope){ + callback.upload(obj); + } + else{ + callback.upload.apply(callback.scope, [obj]); + } + } + + // Fire global custom event -- completeEvent + oConn.uploadEvent.fire(obj); + + if(o.uploadEvent){ + // Fire transaction custom event -- completeEvent + o.uploadEvent.fire(obj); + } + + if(YAHOO.util.Event){ + YAHOO.util.Event.removeListener(io, "load", uploadCallback); + } + else if(window.detachEvent){ + io.detachEvent('onload', uploadCallback); + } + else{ + io.removeEventListener('load', uploadCallback, false); + } + setTimeout( + function(){ + document.body.removeChild(io); + oConn.releaseObject(o); + }, 100); + }; + + // Bind the onload handler to the iframe to detect the file upload response. + if(YAHOO.util.Event){ + YAHOO.util.Event.addListener(io, "load", uploadCallback); + } + else if(window.attachEvent){ + io.attachEvent('onload', uploadCallback); + } + else{ + io.addEventListener('load', uploadCallback, false); + } + }, + + /** + * @description Method to terminate a transaction, if it has not reached readyState 4. + * @method abort + * @public + * @static + * @param {object} o The connection object returned by asyncRequest. + * @param {object} callback User-defined callback object. + * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout. + * @return {boolean} + */ + abort:function(o, callback, isTimeout) + { + var abortStatus; + + if(o.conn){ + if(this.isCallInProgress(o)){ + // Issue abort request + o.conn.abort(); + + window.clearInterval(this._poll[o.tId]); + delete this._poll[o.tId]; + + if(isTimeout){ + window.clearTimeout(this._timeOut[o.tId]); + delete this._timeOut[o.tId]; + } + + abortStatus = true; + } + } + else if(o.isUpload === true){ + var frameId = 'yuiIO' + o.tId; + var io = document.getElementById(frameId); + + if(io){ + // Destroy the iframe facilitating the transaction. + document.body.removeChild(io); + + if(isTimeout){ + window.clearTimeout(this._timeOut[o.tId]); + delete this._timeOut[o.tId]; + } + + abortStatus = true; + } + } + else{ + abortStatus = false; + } + + if(abortStatus === true){ + // Fire global custom event -- abortEvent + this.abortEvent.fire(o); + + if(o.abortEvent){ + // Fire transaction custom event -- abortEvent + o.abortEvent.fire(o); + } + + this.handleTransactionResponse(o, callback, true); + } + else{ + } + + return abortStatus; + }, + + /** + * Public method to check if the transaction is still being processed. + * + * @method isCallInProgress + * @public + * @static + * @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 && o.conn){ + return o.conn.readyState !== 4 && o.conn.readyState !== 0; + } + else if(o && o.isUpload === true){ + var frameId = 'yuiIO' + o.tId; + return document.getElementById(frameId)?true:false; + } + else{ + return false; + } + }, + + /** + * @description Dereference the XHR instance and the connection object after the transaction is completed. + * @method releaseObject + * @private + * @static + * @param {object} o The connection object + * @return {void} + */ + releaseObject:function(o) + { + //dereference the XHR instance. + if(o.conn){ + o.conn = null; + } + //dereference the connection object. + o = null; + } +}; + +YAHOO.register("connection", YAHOO.util.Connect, {version: "2.3.0", build: "442"});