|
Lift Framework example source code file (connection.js)
The Lift Framework connection.js source code/* Copyright (c) 2008, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.6.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:[ 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.3.0', 'MSXML2.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 The default header used for POST transactions. * @property _default_post_header * @private * @static * @type boolean */ _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8', /** * @description The default header used for transactions involving the * use of HTML forms. * @property _default_form_header * @private * @static * @type boolean */ _default_form_header:'application/x-www-form-urlencoded', /** * @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.nodeName.toLowerCase() == 'input' && (obj.type && obj.type.toLowerCase() == '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 override the default POST header. * @method setDefaultPostHeader * @public * @static * @param {boolean} b Set and use default header - true or false . * @return void */ setDefaultPostHeader:function(b) { if(typeof b == 'string'){ this._default_post_header = b; } else if(typeof b == 'boolean'){ this._use_default_post_header = b; } }, /** * @description Member to override the default transaction header.. * @method setDefaultXhrHeader * @public * @static * @param {boolean} b Set and use default header - true or false . * @return void */ setDefaultXhrHeader:function(b) { if(typeof b == 'string'){ this._default_xhr_header = b; } else{ 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<this._msxml_progid.length; ++i){ try { // Instantiates XMLHttpRequest for IE and assign to http http = new ActiveXObject(this._msxml_progid[i]); // Object literal with conn and tId properties obj = { conn:http, tId:transactionId }; break; } catch(e2){} } } finally { return obj; } }, /** * @description 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. * @method getConnectionObject * @private * @static * @return {object} */ getConnectionObject:function(isFileUpload) { var o; var tId = this._transaction_id; try { if(!isFileUpload){ o = this.createXhrObject(tId); } else{ o = {}; o.tId = tId; o.isUpload = true; } if(o){ this._transaction_id++; } } catch(e){} finally { return o; } }, /** * @description Method for initiating an asynchronous request via the XHR object. * @method asyncRequest * @public * @static * @param {string} method HTTP transaction method * @param {string} uri Fully qualified path of resource * @param {callback} 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._isFileUpload)?this.getConnectionObject(true):this.getConnectionObject(); var args = (callback && callback.argument)?callback.argument:null; if(!o){ return null; } else{ // Intialize any transaction-specific custom events, if provided. if(callback && callback.customevents){ this.initCustomEvents(o, callback); } if(this._isFormSubmit){ if(this._isFileUpload){ this.uploadFile(o, callback, uri, postData); return o; } // 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.toUpperCase() == 'GET'){ if(this._sFormData.length !== 0){ // If the URI already contains a querystring, append an ampersand // and then concatenate _sFormData to the URI. uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData; } } else if(method.toUpperCase() == 'POST'){ // If POST data exist in addition to the HTML form data, // it will be concatenated to the form data. postData = postData?this._sFormData + "&" + postData:this._sFormData; } } if(method.toUpperCase() == 'GET' && (callback && callback.cache === false)){ // If callback.cache is defined and set to false, a // timestamp value will be added to the querystring. uri += ((uri.indexOf('?') == -1)?'?':'&') + "rnd=" + new Date().valueOf().toString(); } o.conn.open(method, uri, true); // Each transaction will automatically include a custom header of // "X-Requested-With: XMLHttpRequest" to identify the request as // having originated from Connection Manager. if(this._use_default_xhr_header){ if(!this._default_headers['X-Requested-With']){ this.initHeader('X-Requested-With', this._default_xhr_header, true); } } //If the transaction method is POST and the POST header value is set to true //or a custom value, initalize the Content-Type header to this value. if((method.toUpperCase() === 'POST' && this._use_default_post_header) && this._isFormSubmit === false){ this.initHeader('Content-Type', this._default_post_header); } //Initialize all default and custom HTTP headers, if(this._has_default_headers || this._has_http_headers){ this.setHeader(o); } this.handleReadyState(o, callback); o.conn.send(postData || ''); // Reset the HTML form data and state properties as // soon as the data are submitted. if(this._isFormSubmit === true){ this.resetFormState(); } // Fire global custom event -- startEvent this.startEvent.fire(o, args); if(o.startEvent){ // Fire transaction custom event -- startEvent o.startEvent.fire(o, args); } return o; } }, /** * @description This method creates and subscribes custom events, * specific to each transaction * @method initCustomEvents * @private * @static * @param {object} o The connection object * @param {callback} callback The user-defined callback object * @return {void} */ initCustomEvents:function(o, callback) { var prop; // Enumerate through callback.customevents members and bind/subscribe // events that match in the _customEvents table. for(prop in callback.customevents){ if(this._customEvents[prop][0]){ // Create the custom event o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null); // Subscribe the custom event o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]); } } }, /** * @description 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. * @method handleReadyState * @private * @static * @param {object} o The connection object * @param {callback} callback The user-defined callback object * @return {void} */ handleReadyState:function(o, callback) { var oConn = this; var args = (callback && callback.argument)?callback.argument:null; if(callback && callback.timeout){ this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout); } this._poll[o.tId] = window.setInterval( function(){ if(o.conn && o.conn.readyState === 4){ // Clear the polling interval for the transaction // and remove the reference from _poll. window.clearInterval(oConn._poll[o.tId]); delete oConn._poll[o.tId]; if(callback && callback.timeout){ window.clearTimeout(oConn._timeOut[o.tId]); delete oConn._timeOut[o.tId]; } // Fire global custom event -- completeEvent oConn.completeEvent.fire(o, args); if(o.completeEvent){ // Fire transaction custom event -- completeEvent o.completeEvent.fire(o, args); } oConn.handleTransactionResponse(o, callback); } } ,this._polling_interval); }, /** * @description This method attempts to interpret the server response and * determine whether the transaction was successful, or if an error or * exception was encountered. * @method handleTransactionResponse * @private * @static * @param {object} o The connection object * @param {object} callback The user-defined callback object * @param {boolean} isAbort Determines if the transaction was terminated via abort(). * @return {void} */ handleTransactionResponse:function(o, callback, isAbort) { var httpStatus, responseObject; var args = (callback && callback.argument)?callback.argument:null; try { if(o.conn.status !== undefined && o.conn.status !== 0){ httpStatus = o.conn.status; } else{ httpStatus = 13030; } } catch(e){ // 13030 is a custom code to indicate the condition -- in Mozilla/FF -- // when the XHR object's status and statusText properties are // unavailable, and a query attempt throws an exception. httpStatus = 13030; } if(httpStatus >= 200 && httpStatus < 300 || httpStatus === 1223){ responseObject = this.createResponseObject(o, args); if(callback && 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, args, (isAbort?isAbort:false)); if(callback && callback.failure){ if(!callback.scope){ callback.failure(responseObject); } else{ callback.failure.apply(callback.scope, [responseObject]); } } break; default: responseObject = this.createResponseObject(o, args); if(callback && 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<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; // Normalize IE's response to HTTP 204 when Win error 1223. obj.status = (o.conn.status == 1223)?204:o.conn.status; // Normalize IE's statusText to "No Content" instead of "Unknown". obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText; obj.getResponseHeader = headerObj; obj.getAllResponseHeaders = headerStr; obj.responseText = o.conn.responseText; obj.responseXML = o.conn.responseXML; if(callbackArg){ obj.argument = callbackArg; } return obj; }, /** * @description 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. * * @method createExceptionObject * @private * @static * @param {int} tId The Transaction Id * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback * @param {boolean} isAbort Determines if the exception case is caused by a transaction 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; }, /** * @description Method that initializes the custom HTTP headers for the each transaction. * @method initHeader * @public * @static * @param {string} label The HTTP header label * @param {string} value The HTTP header value * @param {string} isDefault Determines if the specific header is a default header * automatically sent with each transaction. * @return {void} */ initHeader:function(label, value, isDefault) { var headerObj = (isDefault)?this._default_headers:this._http_headers; headerObj[label] = value; if(isDefault){ this._has_default_headers = true; } else{ this._has_http_headers = true; } }, /** * @description Accessor that sets the HTTP headers for each transaction. * @method setHeader * @private * @static * @param {object} o The connection object for the transaction. * @return {void} */ setHeader:function(o) { var prop; if(this._has_default_headers){ for(prop in this._default_headers){ if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){ o.conn.setRequestHeader(prop, this._default_headers[prop]); } } } if(this._has_http_headers){ for(prop in this._http_headers){ if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){ o.conn.setRequestHeader(prop, this._http_headers[prop]); } } delete this._http_headers; this._http_headers = {}; this._has_http_headers = false; } }, /** * @description Resets the default HTTP headers object * @method resetDefaultHeaders * @public * @static * @return {void} */ resetDefaultHeaders:function(){ delete this._default_headers; this._default_headers = {}; this._has_default_headers = false; }, /** * @description This method assembles the form label and value pairs and * constructs an encoded string. * asyncRequest() will automatically initialize the transaction with a * a HTTP header Content-Type of application/x-www-form-urlencoded. * @method setForm * @public * @static * @param {string || object} form id or name attribute, or form object. * @param {boolean} optional enable file upload. * @param {boolean} optional enable file upload over SSL in IE only. * @return {string} string of the HTML form field name and value pairs.. */ setForm:function(formId, isUpload, secureUri) { var oForm, oElement, oName, oValue, oDisabled, hasSubmit = false, data = [], item = 0, i,len,j,jlen,opt; this.resetFormState(); 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. oForm = (document.getElementById(formId) || document.forms[formId]); } else if(typeof formId == 'object'){ // Treat argument as an HTML form object. 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){ // Create iframe in preparation for file upload. this.createFrame(secureUri?secureUri:null); // Set form reference and file upload properties to true. this._isFormSubmit = true; this._isFileUpload = true; this._formNode = oForm; return; } // Iterate over the form elements collection to construct the // label-value pairs. for (i=0,len=oForm.elements.length; i<len; ++i){ oElement = oForm.elements[i]; oDisabled = oElement.disabled; oName = oElement.name; // Do not submit fields that are disabled or // do not have a name attribute value. if(!oDisabled && oName) { oName = encodeURIComponent(oName)+'='; oValue = encodeURIComponent(oElement.value); switch(oElement.type) { // Safari, Opera, FF all default opt.value from .text if // value attribute not specified in markup case 'select-one': if (oElement.selectedIndex > -1) { opt = oElement.options[oElement.selectedIndex]; data[item++] = oName + encodeURIComponent( (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text); } break; case 'select-multiple': if (oElement.selectedIndex > -1) { for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){ opt = oElement.options[j]; if (opt.selected) { data[item++] = oName + encodeURIComponent( (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text); } } } break; case 'radio': case 'checkbox': if(oElement.checked){ data[item++] = oName + 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){ if(this._hasSubmitListener && this._submitElementValue){ data[item++] = this._submitElementValue; } else{ data[item++] = oName + oValue; } hasSubmit = true; } break; default: data[item++] = oName + oValue; } } } this._isFormSubmit = true; this._sFormData = data.join('&'); this.initHeader('Content-Type', this._default_form_header); return this._sFormData; }, /** * @description Resets HTML form properties when an HTML form or HTML form * with file upload transaction is sent. * @method resetFormState * @private * @static * @return {void} */ resetFormState:function(){ this._isFormSubmit = false; this._isFileUpload = false; this._formNode = null; this._sFormData = ""; }, /** * @description Creates an iframe to be used for form file uploads. It is remove from the * document upon completion of the upload transaction. * @method createFrame * @private * @static * @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 object // properties via createElement(). A different iframe creation // pattern is required for IE. var frameId = 'yuiIO' + this._transaction_id; var io; if(YAHOO.env.ua.ie){ io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />'); // 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{ 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 = [], postMessage = postData.split('&'), i, delimitPos; for(i=0; i < postMessage.length; i++){ delimitPos = postMessage[i].indexOf('='); if(delimitPos != -1){ formElements[i] = document.createElement('input'); formElements[i].type = 'hidden'; formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos)); formElements[i].value = decodeURIComponent(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, uploadEncoding = 'multipart/form-data', io = document.getElementById(frameId), oConn = this, args = (callback && callback.argument)?callback.argument:null, oElements,i,prop,obj; // 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(YAHOO.env.ua.ie){ // 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){ oElements = this.appendPostData(postData); } // Start file upload. this._formNode.submit(); // Fire global custom event -- startEvent this.startEvent.fire(o, args); if(o.startEvent){ // Fire transaction custom event -- startEvent o.startEvent.fire(o, args); } // 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(i=0; i < oElements.length; i++){ this._formNode.removeChild(oElements[i]); } } // Restore HTML form attributes to their original // values prior to file upload. for(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, args); if(o.completeEvent){ // Fire transaction custom event -- completeEvent o.completeEvent.fire(o, args); } obj = { tId : o.tId, 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 -- uploadEvent oConn.uploadEvent.fire(obj); if(o.uploadEvent){ // Fire transaction custom event -- uploadEvent o.uploadEvent.fire(obj); } YAHOO.util.Event.removeListener(io, "load", uploadCallback); setTimeout( function(){ document.body.removeChild(io); oConn.releaseObject(o); }, 100); }; // Bind the onload handler to the iframe to detect the file upload response. YAHOO.util.Event.addListener(io, "load", uploadCallback); }, /** * @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; var args = (callback && callback.argument)?callback.argument:null; if(o && 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 && o.isUpload === true){ var frameId = 'yuiIO' + o.tId; var io = document.getElementById(frameId); if(io){ // Remove all listeners on the iframe prior to // its destruction. YAHOO.util.Event.removeListener(io, "load"); // 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, args); if(o.abortEvent){ // Fire transaction custom event -- abortEvent o.abortEvent.fire(o, args); } this.handleTransactionResponse(o, callback, true); } return abortStatus; }, /** * @description Determines 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) { if(o && o.conn){ //dereference the XHR instance. o.conn = null; //dereference the connection object. o = null; } } }; YAHOO.register("connection", YAHOO.util.Connect, {version: "2.6.0", build: "1321"}); Other Lift Framework examples (source code examples)Here is a short list of links related to this Lift Framework connection.js source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.