Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / lib / yui / connection / connection.js
blob249773e8e74c3af8ae8d6a181a6f9dd43995b03b
1 /*
2 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 0.12.2
6 */
7 /**
8  * The Connection Manager provides a simplified interface to the XMLHttpRequest
9  * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
10  * interactive states and server response, returning the results to a pre-defined
11  * callback you create.
12  *
13  * @namespace YAHOO.util
14  * @module connection
15  * @requires yahoo
16  */
18 /**
19  * The Connection Manager singleton provides methods for creating and managing
20  * asynchronous transactions.
21  *
22  * @class Connect
23  */
24 YAHOO.util.Connect =
26   /**
27    * @description Array of MSFT ActiveX ids for XMLHttpRequest.
28    * @property _msxml_progid
29    * @private
30    * @static
31    * @type array
32    */
33         _msxml_progid:[
34                 'MSXML2.XMLHTTP.3.0',
35                 'MSXML2.XMLHTTP',
36                 'Microsoft.XMLHTTP'
37                 ],
39   /**
40    * @description Object literal of HTTP header(s)
41    * @property _http_header
42    * @private
43    * @static
44    * @type object
45    */
46         _http_header:{},
48   /**
49    * @description Determines if HTTP headers are set.
50    * @property _has_http_headers
51    * @private
52    * @static
53    * @type boolean
54    */
55         _has_http_headers:false,
57  /**
58   * @description Determines if a default header of
59   * Content-Type of 'application/x-www-form-urlencoded'
60   * will be added to any client HTTP headers sent for POST
61   * transactions.
62   * @property _use_default_post_header
63   * @private
64   * @static
65   * @type boolean
66   */
67     _use_default_post_header:true,
69  /**
70   * @description Determines if a default header of
71   * Content-Type of 'application/x-www-form-urlencoded'
72   * will be added to any client HTTP headers sent for POST
73   * transactions.
74   * @property _default_post_header
75   * @private
76   * @static
77   * @type boolean
78   */
79     _default_post_header:'application/x-www-form-urlencoded',
81  /**
82   * @description Property modified by setForm() to determine if the data
83   * should be submitted as an HTML form.
84   * @property _isFormSubmit
85   * @private
86   * @static
87   * @type boolean
88   */
89     _isFormSubmit:false,
91  /**
92   * @description Property modified by setForm() to determine if a file(s)
93   * upload is expected.
94   * @property _isFileUpload
95   * @private
96   * @static
97   * @type boolean
98   */
99     _isFileUpload:false,
101  /**
102   * @description Property modified by setForm() to set a reference to the HTML
103   * form node if the desired action is file upload.
104   * @property _formNode
105   * @private
106   * @static
107   * @type object
108   */
109     _formNode:null,
111  /**
112   * @description Property modified by setForm() to set the HTML form data
113   * for each transaction.
114   * @property _sFormData
115   * @private
116   * @static
117   * @type string
118   */
119     _sFormData:null,
121  /**
122   * @description Collection of polling references to the polling mechanism in handleReadyState.
123   * @property _poll
124   * @private
125   * @static
126   * @type object
127   */
128     _poll:{},
130  /**
131   * @description Queue of timeout values for each transaction callback with a defined timeout value.
132   * @property _timeOut
133   * @private
134   * @static
135   * @type object
136   */
137     _timeOut:{},
139   /**
140    * @description The polling frequency, in milliseconds, for HandleReadyState.
141    * when attempting to determine a transaction's XHR readyState.
142    * The default is 50 milliseconds.
143    * @property _polling_interval
144    * @private
145    * @static
146    * @type int
147    */
148      _polling_interval:50,
150   /**
151    * @description A transaction counter that increments the transaction id for each transaction.
152    * @property _transaction_id
153    * @private
154    * @static
155    * @type int
156    */
157      _transaction_id:0,
159   /**
160    * @description Member to add an ActiveX id to the existing xml_progid array.
161    * In the event(unlikely) a new ActiveX id is introduced, it can be added
162    * without internal code modifications.
163    * @method setProgId
164    * @public
165    * @static
166    * @param {string} id The ActiveX id to be added to initialize the XHR object.
167    * @return void
168    */
169         setProgId:function(id)
170         {
171                 this._msxml_progid.unshift(id);
172         },
174   /**
175    * @description Member to enable or disable the default POST header.
176    * @method setDefaultPostHeader
177    * @public
178    * @static
179    * @param {boolean} b Set and use default header - true or false .
180    * @return void
181    */
182         setDefaultPostHeader:function(b)
183         {
184                 this._use_default_post_header = b;
185         },
187   /**
188    * @description Member to modify the default polling interval.
189    * @method setPollingInterval
190    * @public
191    * @static
192    * @param {int} i The polling interval in milliseconds.
193    * @return void
194    */
195         setPollingInterval:function(i)
196         {
197                 if(typeof i == 'number' && isFinite(i)){
198                         this._polling_interval = i;
199                 }
200         },
202   /**
203    * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
204    * the XMLHttpRequest instance and the transaction id.
205    * @method createXhrObject
206    * @private
207    * @static
208    * @param {int} transactionId Property containing the transaction id for this transaction.
209    * @return object
210    */
211         createXhrObject:function(transactionId)
212         {
213                 var obj,http;
214                 try
215                 {
216                         // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
217                         http = new XMLHttpRequest();
218                         //  Object literal with http and tId properties
219                         obj = { conn:http, tId:transactionId };
220                 }
221                 catch(e)
222                 {
223                         for(var i=0; i<this._msxml_progid.length; ++i){
224                                 try
225                                 {
226                                         // Instantiates XMLHttpRequest for IE and assign to http.
227                                         http = new ActiveXObject(this._msxml_progid[i]);
228                                         //  Object literal with conn and tId properties
229                                         obj = { conn:http, tId:transactionId };
230                                         break;
231                                 }
232                                 catch(e){}
233                         }
234                 }
235                 finally
236                 {
237                         return obj;
238                 }
239         },
241   /**
242    * @description This method is called by asyncRequest to create a
243    * valid connection object for the transaction.  It also passes a
244    * transaction id and increments the transaction id counter.
245    * @method getConnectionObject
246    * @private
247    * @static
248    * @return {object}
249    */
250         getConnectionObject:function()
251         {
252                 var o;
253                 var tId = this._transaction_id;
255                 try
256                 {
257                         o = this.createXhrObject(tId);
258                         if(o){
259                                 this._transaction_id++;
260                         }
261                 }
262                 catch(e){}
263                 finally
264                 {
265                         return o;
266                 }
267         },
269   /**
270    * @description Method for initiating an asynchronous request via the XHR object.
271    * @method asyncRequest
272    * @public
273    * @static
274    * @param {string} method HTTP transaction method
275    * @param {string} uri Fully qualified path of resource
276    * @param {callback} callback User-defined callback function or object
277    * @param {string} postData POST body
278    * @return {object} Returns the connection object
279    */
280         asyncRequest:function(method, uri, callback, postData)
281         {
282                 var o = this.getConnectionObject();
284                 if(!o){
285                         return null;
286                 }
287                 else{
288                         if(this._isFormSubmit){
289                                 if(this._isFileUpload){
290                                         this.uploadFile(o.tId, callback, uri, postData);
291                                         this.releaseObject(o);
293                                         return;
294                                 }
296                                 //If the specified HTTP method is GET, setForm() will return an
297                                 //encoded string that is concatenated to the uri to
298                                 //create a querystring.
299                                 if(method == 'GET'){
300                                         if(this._sFormData.length != 0){
301                                                 // If the URI already contains a querystring, append an ampersand
302                                                 // and then concatenate _sFormData to the URI.
303                                                 uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
304                                         }
305                                         else{
306                                                 uri += "?" + this._sFormData;
307                                         }
308                                 }
309                                 else if(method == 'POST'){
310                                         //If POST data exist in addition to the HTML form data,
311                                         //it will be concatenated to the form data.
312                                         postData = postData?this._sFormData + "&" + postData:this._sFormData;
313                                 }
314                         }
316                         o.conn.open(method, uri, true);
318                         if(this._isFormSubmit || (postData && this._use_default_post_header)){
319                                 this.initHeader('Content-Type', this._default_post_header);
320                                 if(this._isFormSubmit){
321                                         this.resetFormState();
322                                 }
323                         }
325                         if(this._has_http_headers){
326                                 this.setHeader(o);
327                         }
329                         this.handleReadyState(o, callback);
330                         o.conn.send(postData || null);
332                         return o;
333                 }
334         },
336   /**
337    * @description This method serves as a timer that polls the XHR object's readyState
338    * property during a transaction, instead of binding a callback to the
339    * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
340    * will process the response, and the timer will be cleared.
341    * @method handleReadyState
342    * @private
343    * @static
344    * @param {object} o The connection object
345    * @param {callback} callback The user-defined callback object
346    * @return {void}
347    */
348     handleReadyState:function(o, callback)
349     {
350                 var oConn = this;
352                 if(callback && callback.timeout){
353                         this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
354                 }
356                 this._poll[o.tId] = window.setInterval(
357                         function(){
358                                 if(o.conn && o.conn.readyState == 4){
359                                         window.clearInterval(oConn._poll[o.tId]);
360                                         delete oConn._poll[o.tId];
362                                         if(callback && callback.timeout){
363                                                 delete oConn._timeOut[o.tId];
364                                         }
366                                         oConn.handleTransactionResponse(o, callback);
367                                 }
368                         }
369                 ,this._polling_interval);
370     },
372   /**
373    * @description This method attempts to interpret the server response and
374    * determine whether the transaction was successful, or if an error or
375    * exception was encountered.
376    * @method handleTransactionResponse
377    * @private
378    * @static
379    * @param {object} o The connection object
380    * @param {object} callback The sser-defined callback object
381    * @param {boolean} isAbort Determines if the transaction was aborted.
382    * @return {void}
383    */
384     handleTransactionResponse:function(o, callback, isAbort)
385     {
386                 // If no valid callback is provided, then do not process any callback handling.
387                 if(!callback){
388                         this.releaseObject(o);
389                         return;
390                 }
392                 var httpStatus, responseObject;
394                 try
395                 {
396                         if(o.conn.status !== undefined && o.conn.status != 0){
397                                 httpStatus = o.conn.status;
398                         }
399                         else{
400                                 httpStatus = 13030;
401                         }
402                 }
403                 catch(e){
404                         // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
405                         // when the o object's status and statusText properties are
406                         // unavailable, and a query attempt throws an exception.
407                         httpStatus = 13030;
408                 }
410                 if(httpStatus >= 200 && httpStatus < 300){
411                         try
412                         {
413                                 responseObject = this.createResponseObject(o, callback.argument);
414                                 if(callback.success){
415                                         if(!callback.scope){
416                                                 callback.success(responseObject);
417                                         }
418                                         else{
419                                                 // If a scope property is defined, the callback will be fired from
420                                                 // the context of the object.
421                                                 callback.success.apply(callback.scope, [responseObject]);
422                                         }
423                                 }
424                         }
425                         catch(e){}
426                 }
427                 else{
428                         try
429                         {
430                                 switch(httpStatus){
431                                         // The following cases are wininet.dll error codes that may be encountered.
432                                         case 12002: // Server timeout
433                                         case 12029: // 12029 to 12031 correspond to dropped connections.
434                                         case 12030:
435                                         case 12031:
436                                         case 12152: // Connection closed by server.
437                                         case 13030: // See above comments for variable status.
438                                                 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
439                                                 if(callback.failure){
440                                                         if(!callback.scope){
441                                                                 callback.failure(responseObject);
442                                                         }
443                                                         else{
444                                                                 callback.failure.apply(callback.scope, [responseObject]);
445                                                         }
446                                                 }
447                                                 break;
448                                         default:
449                                                 responseObject = this.createResponseObject(o, callback.argument);
450                                                 if(callback.failure){
451                                                         if(!callback.scope){
452                                                                 callback.failure(responseObject);
453                                                         }
454                                                         else{
455                                                                 callback.failure.apply(callback.scope, [responseObject]);
456                                                         }
457                                                 }
458                                 }
459                         }
460                         catch(e){}
461                 }
463                 this.releaseObject(o);
464                 responseObject = null;
465     },
467   /**
468    * @description This method evaluates the server response, creates and returns the results via
469    * its properties.  Success and failure cases will differ in the response
470    * object's property values.
471    * @method createResponseObject
472    * @private
473    * @static
474    * @param {object} o The connection object
475    * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
476    * @return {object}
477    */
478     createResponseObject:function(o, callbackArg)
479     {
480                 var obj = {};
481                 var headerObj = {};
483                 try
484                 {
485                         var headerStr = o.conn.getAllResponseHeaders();
486                         var header = headerStr.split('\n');
487                         for(var i=0; i<header.length; i++){
488                                 var delimitPos = header[i].indexOf(':');
489                                 if(delimitPos != -1){
490                                         headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
491                                 }
492                         }
493                 }
494                 catch(e){}
496                 obj.tId = o.tId;
497                 obj.status = o.conn.status;
498                 obj.statusText = o.conn.statusText;
499                 obj.getResponseHeader = headerObj;
500                 obj.getAllResponseHeaders = headerStr;
501                 obj.responseText = o.conn.responseText;
502                 obj.responseXML = o.conn.responseXML;
504                 if(typeof callbackArg !== undefined){
505                         obj.argument = callbackArg;
506                 }
508                 return obj;
509     },
511   /**
512    * @description If a transaction cannot be completed due to dropped or closed connections,
513    * there may be not be enough information to build a full response object.
514    * The failure callback will be fired and this specific condition can be identified
515    * by a status property value of 0.
516    *
517    * If an abort was successful, the status property will report a value of -1.
518    *
519    * @method createExceptionObject
520    * @private
521    * @static
522    * @param {int} tId The Transaction Id
523    * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
524    * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
525    * @return {object}
526    */
527     createExceptionObject:function(tId, callbackArg, isAbort)
528     {
529                 var COMM_CODE = 0;
530                 var COMM_ERROR = 'communication failure';
531                 var ABORT_CODE = -1;
532                 var ABORT_ERROR = 'transaction aborted';
534                 var obj = {};
536                 obj.tId = tId;
537                 if(isAbort){
538                         obj.status = ABORT_CODE;
539                         obj.statusText = ABORT_ERROR;
540                 }
541                 else{
542                         obj.status = COMM_CODE;
543                         obj.statusText = COMM_ERROR;
544                 }
546                 if(callbackArg){
547                         obj.argument = callbackArg;
548                 }
550                 return obj;
551     },
553   /**
554    * @description Public method that stores the custom HTTP headers for each transaction.
555    * @method initHeader
556    * @public
557    * @static
558    * @param {string} label The HTTP header label
559    * @param {string} value The HTTP header value
560    * @return {void}
561    */
562         initHeader:function(label,value)
563         {
564                 if(this._http_header[label] === undefined){
565                         this._http_header[label] = value;
566                 }
567                 else{
568                         // Concatenate multiple values, comma-delimited,
569                         // for the same header label,
570                         this._http_header[label] =  value + "," + this._http_header[label];
571                 }
573                 this._has_http_headers = true;
574         },
576   /**
577    * @description Accessor that sets the HTTP headers for each transaction.
578    * @method setHeader
579    * @private
580    * @static
581    * @param {object} o The connection object for the transaction.
582    * @return {void}
583    */
584         setHeader:function(o)
585         {
586                 for(var prop in this._http_header){
587                         if(this._http_header.hasOwnProperty(prop)){
588                                 o.conn.setRequestHeader(prop, this._http_header[prop]);
589                         }
590                 }
591                 delete this._http_header;
593                 this._http_header = {};
594                 this._has_http_headers = false;
595         },
597   /**
598    * @description This method assembles the form label and value pairs and
599    * constructs an encoded string.
600    * asyncRequest() will automatically initialize the
601    * transaction with a HTTP header Content-Type of
602    * application/x-www-form-urlencoded.
603    * @method setForm
604    * @public
605    * @static
606    * @param {string || object} form id or name attribute, or form object.
607    * @param {string} optional boolean to indicate SSL environment.
608    * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
609    * @return {string} string of the HTML form field name and value pairs..
610    */
611         setForm:function(formId, isUpload, secureUri)
612         {
613                 this.resetFormState();
614                 var oForm;
615                 if(typeof formId == 'string'){
616                         // Determine if the argument is a form id or a form name.
617                         // Note form name usage is deprecated but supported
618                         // here for legacy reasons.
619                         oForm = (document.getElementById(formId) || document.forms[formId]);
620                 }
621                 else if(typeof formId == 'object'){
622                         // Treat argument as an HTML form object.
623                         oForm = formId;
624                 }
625                 else{
626                         return;
627                 }
629                 // If the isUpload argument is true, setForm will call createFrame to initialize
630                 // an iframe as the form target.
631                 //
632                 // The argument secureURI is also required by IE in SSL environments
633                 // where the secureURI string is a fully qualified HTTP path, used to set the source
634                 // of the iframe, to a stub resource in the same domain.
635                 if(isUpload){
637                         // Create iframe in preparation for file upload.
638                         this.createFrame(secureUri?secureUri:null);
640                         // Set form reference and file upload properties to true.
641                         this._isFormSubmit = true;
642                         this._isFileUpload = true;
643                         this._formNode = oForm;
645                         return;
646                 }
648                 var oElement, oName, oValue, oDisabled;
649                 var hasSubmit = false;
651                 // Iterate over the form elements collection to construct the
652                 // label-value pairs.
653                 for (var i=0; i<oForm.elements.length; i++){
654                         oElement = oForm.elements[i];
655                         oDisabled = oForm.elements[i].disabled;
656                         oName = oForm.elements[i].name;
657                         oValue = oForm.elements[i].value;
659                         // Do not submit fields that are disabled or
660                         // do not have a name attribute value.
661                         if(!oDisabled && oName)
662                         {
663                                 switch (oElement.type)
664                                 {
665                                         case 'select-one':
666                                         case 'select-multiple':
667                                                 for(var j=0; j<oElement.options.length; j++){
668                                                         if(oElement.options[j].selected){
669                                                                 if(window.ActiveXObject){
670                                                                         this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
671                                                                 }
672                                                                 else{
673                                                                         this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
674                                                                 }
676                                                         }
677                                                 }
678                                                 break;
679                                         case 'radio':
680                                         case 'checkbox':
681                                                 if(oElement.checked){
682                                                         this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
683                                                 }
684                                                 break;
685                                         case 'file':
686                                                 // stub case as XMLHttpRequest will only send the file path as a string.
687                                         case undefined:
688                                                 // stub case for fieldset element which returns undefined.
689                                         case 'reset':
690                                                 // stub case for input type reset button.
691                                         case 'button':
692                                                 // stub case for input type button elements.
693                                                 break;
694                                         case 'submit':
695                                                 if(hasSubmit == false){
696                                                         this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
697                                                         hasSubmit = true;
698                                                 }
699                                                 break;
700                                         default:
701                                                 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
702                                                 break;
703                                 }
704                         }
705                 }
707                 this._isFormSubmit = true;
708                 this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
710                 return this._sFormData;
711         },
713   /**
714    * @description Resets HTML form properties when an HTML form or HTML form
715    * with file upload transaction is sent.
716    * @method resetFormState
717    * @private
718    * @static
719    * @return {void}
720    */
721         resetFormState:function(){
722                 this._isFormSubmit = false;
723                 this._isFileUpload = false;
724                 this._formNode = null;
725                 this._sFormData = "";
726         },
728   /**
729    * @description Creates an iframe to be used for form file uploads.  It is remove from the
730    * document upon completion of the upload transaction.
731    * @method createFrame
732    * @private
733    * @static
734    * @param {string} secureUri Optional qualified path of iframe resource for SSL in IE.
735    * @return {void}
736    */
737         createFrame:function(secureUri){
739                 // IE does not allow the setting of id and name attributes as object
740                 // properties via createElement().  A different iframe creation
741                 // pattern is required for IE.
742                 var frameId = 'yuiIO' + this._transaction_id;
743                 if(window.ActiveXObject){
744                         var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
746                         // IE will throw a security exception in an SSL environment if the
747                         // iframe source is undefined.
748                         if(typeof secureUri == 'boolean'){
749                                 io.src = 'javascript:false';
750                         }
751                         else if(typeof secureURI == 'string'){
752                                 // Deprecated
753                                 io.src = secureUri;
754                         }
755                 }
756                 else{
757                         var io = document.createElement('iframe');
758                         io.id = frameId;
759                         io.name = frameId;
760                 }
762                 io.style.position = 'absolute';
763                 io.style.top = '-1000px';
764                 io.style.left = '-1000px';
766                 document.body.appendChild(io);
767         },
769   /**
770    * @description Parses the POST data and creates hidden form elements
771    * for each key-value, and appends them to the HTML form object.
772    * @method appendPostData
773    * @private
774    * @static
775    * @param {string} postData The HTTP POST data
776    * @return {array} formElements Collection of hidden fields.
777    */
778         appendPostData:function(postData)
779         {
780                 var formElements = [];
781                 var postMessage = postData.split('&');
782                 for(var i=0; i < postMessage.length; i++){
783                         var delimitPos = postMessage[i].indexOf('=');
784                         if(delimitPos != -1){
785                                 formElements[i] = document.createElement('input');
786                                 formElements[i].type = 'hidden';
787                                 formElements[i].name = postMessage[i].substring(0,delimitPos);
788                                 formElements[i].value = postMessage[i].substring(delimitPos+1);
789                                 this._formNode.appendChild(formElements[i]);
790                         }
791                 }
793                 return formElements;
794         },
796   /**
797    * @description Uploads HTML form, including files/attachments, to the
798    * iframe created in createFrame.
799    * @method uploadFile
800    * @private
801    * @static
802    * @param {int} id The transaction id.
803    * @param {object} callback - User-defined callback object.
804    * @param {string} uri Fully qualified path of resource.
805    * @return {void}
806    */
807         uploadFile:function(id, callback, uri, postData){
809                 // Each iframe has an id prefix of "yuiIO" followed
810                 // by the unique transaction id.
811                 var frameId = 'yuiIO' + id;
812                 var io = document.getElementById(frameId);
814                 // Initialize the HTML form properties in case they are
815                 // not defined in the HTML form.
816                 this._formNode.action = uri;
817                 this._formNode.method = 'POST';
818                 this._formNode.target = frameId;
820                 if(this._formNode.encoding){
821                         // IE does not respect property enctype for HTML forms.
822                         // Instead use property encoding.
823                         this._formNode.encoding = 'multipart/form-data';
824                 }
825                 else{
826                         this._formNode.enctype = 'multipart/form-data';
827                 }
829                 if(postData){
830                         var oElements = this.appendPostData(postData);
831                 }
833                 this._formNode.submit();
835                 if(oElements && oElements.length > 0){
836                         try
837                         {
838                                 for(var i=0; i < oElements.length; i++){
839                                         this._formNode.removeChild(oElements[i]);
840                                 }
841                         }
842                         catch(e){}
843                 }
845                 // Reset HTML form status properties.
846                 this.resetFormState();
848                 // Create the upload callback handler that fires when the iframe
849                 // receives the load event.  Subsequently, the event handler is detached
850                 // and the iframe removed from the document.
852                 var uploadCallback = function()
853                 {
854                         var obj = {};
855                         obj.tId = id;
856                         obj.argument = callback.argument;
858                         try
859                         {
860                                 obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
861                                 obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
862                         }
863                         catch(e){}
865                         if(callback.upload){
866                                 if(!callback.scope){
867                                         callback.upload(obj);
868                                 }
869                                 else{
870                                         callback.upload.apply(callback.scope, [obj]);
871                                 }
872                         }
874                         if(YAHOO.util.Event){
875                                 YAHOO.util.Event.removeListener(io, "load", uploadCallback);
876                         }
877                         else if(window.detachEvent){
878                                 io.detachEvent('onload', uploadCallback);
879                         }
880                         else{
881                                 io.removeEventListener('load', uploadCallback, false);
882                         }
883                         setTimeout(function(){ document.body.removeChild(io); }, 100);
884                 };
887                 // Bind the onload handler to the iframe to detect the file upload response.
888                 if(YAHOO.util.Event){
889                         YAHOO.util.Event.addListener(io, "load", uploadCallback);
890                 }
891                 else if(window.attachEvent){
892                         io.attachEvent('onload', uploadCallback);
893                 }
894                 else{
895                         io.addEventListener('load', uploadCallback, false);
896                 }
897         },
899   /**
900    * @description Method to terminate a transaction, if it has not reached readyState 4.
901    * @method abort
902    * @public
903    * @static
904    * @param {object} o The connection object returned by asyncRequest.
905    * @param {object} callback  User-defined callback object.
906    * @param {string} isTimeout boolean to indicate if abort was a timeout.
907    * @return {boolean}
908    */
909         abort:function(o, callback, isTimeout)
910         {
911                 if(this.isCallInProgress(o)){
912                         o.conn.abort();
913                         window.clearInterval(this._poll[o.tId]);
914                         delete this._poll[o.tId];
915                         if(isTimeout){
916                                 delete this._timeOut[o.tId];
917                         }
919                         this.handleTransactionResponse(o, callback, true);
921                         return true;
922                 }
923                 else{
924                         return false;
925                 }
926         },
928   /**
929    * Public method to check if the transaction is still being processed.
930    *
931    * @method isCallInProgress
932    * @public
933    * @static
934    * @param {object} o The connection object returned by asyncRequest
935    * @return {boolean}
936    */
937         isCallInProgress:function(o)
938         {
939                 // if the XHR object assigned to the transaction has not been dereferenced,
940                 // then check its readyState status.  Otherwise, return false.
941                 if(o.conn){
942                         return o.conn.readyState != 4 && o.conn.readyState != 0;
943                 }
944                 else{
945                         //The XHR object has been destroyed.
946                         return false;
947                 }
948         },
950   /**
951    * @description Dereference the XHR instance and the connection object after the transaction is completed.
952    * @method releaseObject
953    * @private
954    * @static
955    * @param {object} o The connection object
956    * @return {void}
957    */
958         releaseObject:function(o)
959         {
960                 //dereference the XHR instance.
961                 o.conn = null;
962                 //dereference the connection object.
963                 o = null;
964         }