]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blob - wradmin/static/yui/connection/connection.js
Rename public directory to static.
[philipp/winterrodeln/wradmin.git] / wradmin / static / yui / connection / connection.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.7.0
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  * @requires event
17  */
18
19 /**
20  * The Connection Manager singleton provides methods for creating and managing
21  * asynchronous transactions.
22  *
23  * @class Connect
24  */
25
26 YAHOO.util.Connect =
27 {
28   /**
29    * @description Array of MSFT ActiveX ids for XMLHttpRequest.
30    * @property _msxml_progid
31    * @private
32    * @static
33    * @type array
34    */
35         _msxml_progid:[
36                 'Microsoft.XMLHTTP',
37                 'MSXML2.XMLHTTP.3.0',
38                 'MSXML2.XMLHTTP'
39                 ],
40
41   /**
42    * @description Object literal of HTTP header(s)
43    * @property _http_header
44    * @private
45    * @static
46    * @type object
47    */
48         _http_headers:{},
49
50   /**
51    * @description Determines if HTTP headers are set.
52    * @property _has_http_headers
53    * @private
54    * @static
55    * @type boolean
56    */
57         _has_http_headers:false,
58
59  /**
60   * @description Determines if a default header of
61   * Content-Type of 'application/x-www-form-urlencoded'
62   * will be added to any client HTTP headers sent for POST
63   * transactions.
64   * @property _use_default_post_header
65   * @private
66   * @static
67   * @type boolean
68   */
69     _use_default_post_header:true,
70
71  /**
72   * @description The default header used for POST transactions.
73   * @property _default_post_header
74   * @private
75   * @static
76   * @type boolean
77   */
78     _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8',
79
80  /**
81   * @description The default header used for transactions involving the
82   * use of HTML forms.
83   * @property _default_form_header
84   * @private
85   * @static
86   * @type boolean
87   */
88     _default_form_header:'application/x-www-form-urlencoded',
89
90  /**
91   * @description Determines if a default header of
92   * 'X-Requested-With: XMLHttpRequest'
93   * will be added to each transaction.
94   * @property _use_default_xhr_header
95   * @private
96   * @static
97   * @type boolean
98   */
99     _use_default_xhr_header:true,
100
101  /**
102   * @description The default header value for the label
103   * "X-Requested-With".  This is sent with each
104   * transaction, by default, to identify the
105   * request as being made by YUI Connection Manager.
106   * @property _default_xhr_header
107   * @private
108   * @static
109   * @type boolean
110   */
111     _default_xhr_header:'XMLHttpRequest',
112
113  /**
114   * @description Determines if custom, default headers
115   * are set for each transaction.
116   * @property _has_default_header
117   * @private
118   * @static
119   * @type boolean
120   */
121     _has_default_headers:true,
122
123  /**
124   * @description Determines if custom, default headers
125   * are set for each transaction.
126   * @property _has_default_header
127   * @private
128   * @static
129   * @type boolean
130   */
131     _default_headers:{},
132
133  /**
134   * @description Property modified by setForm() to determine if the data
135   * should be submitted as an HTML form.
136   * @property _isFormSubmit
137   * @private
138   * @static
139   * @type boolean
140   */
141     _isFormSubmit:false,
142
143  /**
144   * @description Property modified by setForm() to determine if a file(s)
145   * upload is expected.
146   * @property _isFileUpload
147   * @private
148   * @static
149   * @type boolean
150   */
151     _isFileUpload:false,
152
153  /**
154   * @description Property modified by setForm() to set a reference to the HTML
155   * form node if the desired action is file upload.
156   * @property _formNode
157   * @private
158   * @static
159   * @type object
160   */
161     _formNode:null,
162
163  /**
164   * @description Property modified by setForm() to set the HTML form data
165   * for each transaction.
166   * @property _sFormData
167   * @private
168   * @static
169   * @type string
170   */
171     _sFormData:null,
172
173  /**
174   * @description Collection of polling references to the polling mechanism in handleReadyState.
175   * @property _poll
176   * @private
177   * @static
178   * @type object
179   */
180     _poll:{},
181
182  /**
183   * @description Queue of timeout values for each transaction callback with a defined timeout value.
184   * @property _timeOut
185   * @private
186   * @static
187   * @type object
188   */
189     _timeOut:{},
190
191   /**
192    * @description The polling frequency, in milliseconds, for HandleReadyState.
193    * when attempting to determine a transaction's XHR readyState.
194    * The default is 50 milliseconds.
195    * @property _polling_interval
196    * @private
197    * @static
198    * @type int
199    */
200      _polling_interval:50,
201
202   /**
203    * @description A transaction counter that increments the transaction id for each transaction.
204    * @property _transaction_id
205    * @private
206    * @static
207    * @type int
208    */
209      _transaction_id:0,
210
211   /**
212    * @description Tracks the name-value pair of the "clicked" submit button if multiple submit
213    * buttons are present in an HTML form; and, if YAHOO.util.Event is available.
214    * @property _submitElementValue
215    * @private
216    * @static
217    * @type string
218    */
219          _submitElementValue:null,
220
221   /**
222    * @description Determines whether YAHOO.util.Event is available and returns true or false.
223    * If true, an event listener is bound at the document level to trap click events that
224    * resolve to a target type of "Submit".  This listener will enable setForm() to determine
225    * the clicked "Submit" value in a multi-Submit button, HTML form.
226    * @property _hasSubmitListener
227    * @private
228    * @static
229    */
230          _hasSubmitListener:(function()
231          {
232                 if(YAHOO.util.Event){
233                         YAHOO.util.Event.addListener(
234                                 document,
235                                 'click',
236                                 function(e){
237                                         var obj = YAHOO.util.Event.getTarget(e),
238                                                 name = obj.nodeName.toLowerCase();
239                                         if((name === 'input' || name === 'button') && (obj.type && obj.type.toLowerCase() == 'submit')){
240                                                 YAHOO.util.Connect._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
241                                         }
242                                 });
243                         return true;
244             }
245             return false;
246          })(),
247
248   /**
249    * @description Custom event that fires at the start of a transaction
250    * @property startEvent
251    * @private
252    * @static
253    * @type CustomEvent
254    */
255         startEvent: new YAHOO.util.CustomEvent('start'),
256
257   /**
258    * @description Custom event that fires when a transaction response has completed.
259    * @property completeEvent
260    * @private
261    * @static
262    * @type CustomEvent
263    */
264         completeEvent: new YAHOO.util.CustomEvent('complete'),
265
266   /**
267    * @description Custom event that fires when handleTransactionResponse() determines a
268    * response in the HTTP 2xx range.
269    * @property successEvent
270    * @private
271    * @static
272    * @type CustomEvent
273    */
274         successEvent: new YAHOO.util.CustomEvent('success'),
275
276   /**
277    * @description Custom event that fires when handleTransactionResponse() determines a
278    * response in the HTTP 4xx/5xx range.
279    * @property failureEvent
280    * @private
281    * @static
282    * @type CustomEvent
283    */
284         failureEvent: new YAHOO.util.CustomEvent('failure'),
285
286   /**
287    * @description Custom event that fires when handleTransactionResponse() determines a
288    * response in the HTTP 4xx/5xx range.
289    * @property failureEvent
290    * @private
291    * @static
292    * @type CustomEvent
293    */
294         uploadEvent: new YAHOO.util.CustomEvent('upload'),
295
296   /**
297    * @description Custom event that fires when a transaction is successfully aborted.
298    * @property abortEvent
299    * @private
300    * @static
301    * @type CustomEvent
302    */
303         abortEvent: new YAHOO.util.CustomEvent('abort'),
304
305   /**
306    * @description A reference table that maps callback custom events members to its specific
307    * event name.
308    * @property _customEvents
309    * @private
310    * @static
311    * @type object
312    */
313         _customEvents:
314         {
315                 onStart:['startEvent', 'start'],
316                 onComplete:['completeEvent', 'complete'],
317                 onSuccess:['successEvent', 'success'],
318                 onFailure:['failureEvent', 'failure'],
319                 onUpload:['uploadEvent', 'upload'],
320                 onAbort:['abortEvent', 'abort']
321         },
322
323   /**
324    * @description Member to add an ActiveX id to the existing xml_progid array.
325    * In the event(unlikely) a new ActiveX id is introduced, it can be added
326    * without internal code modifications.
327    * @method setProgId
328    * @public
329    * @static
330    * @param {string} id The ActiveX id to be added to initialize the XHR object.
331    * @return void
332    */
333         setProgId:function(id)
334         {
335                 this._msxml_progid.unshift(id);
336         },
337
338   /**
339    * @description Member to override the default POST header.
340    * @method setDefaultPostHeader
341    * @public
342    * @static
343    * @param {boolean} b Set and use default header - true or false .
344    * @return void
345    */
346         setDefaultPostHeader:function(b)
347         {
348                 if(typeof b == 'string'){
349                         this._default_post_header = b;
350                 }
351                 else if(typeof b == 'boolean'){
352                         this._use_default_post_header = b;
353                 }
354         },
355
356   /**
357    * @description Member to override the default transaction header..
358    * @method setDefaultXhrHeader
359    * @public
360    * @static
361    * @param {boolean} b Set and use default header - true or false .
362    * @return void
363    */
364         setDefaultXhrHeader:function(b)
365         {
366                 if(typeof b == 'string'){
367                         this._default_xhr_header = b;
368                 }
369                 else{
370                         this._use_default_xhr_header = b;
371                 }
372         },
373
374   /**
375    * @description Member to modify the default polling interval.
376    * @method setPollingInterval
377    * @public
378    * @static
379    * @param {int} i The polling interval in milliseconds.
380    * @return void
381    */
382         setPollingInterval:function(i)
383         {
384                 if(typeof i == 'number' && isFinite(i)){
385                         this._polling_interval = i;
386                 }
387         },
388
389   /**
390    * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
391    * the XMLHttpRequest instance and the transaction id.
392    * @method createXhrObject
393    * @private
394    * @static
395    * @param {int} transactionId Property containing the transaction id for this transaction.
396    * @return object
397    */
398         createXhrObject:function(transactionId)
399         {
400                 var obj,http;
401                 try
402                 {
403                         // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
404                         http = new XMLHttpRequest();
405                         //  Object literal with http and tId properties
406                         obj = { conn:http, tId:transactionId };
407                 }
408                 catch(e)
409                 {
410                         for(var i=0; i<this._msxml_progid.length; ++i){
411                                 try
412                                 {
413                                         // Instantiates XMLHttpRequest for IE and assign to http
414                                         http = new ActiveXObject(this._msxml_progid[i]);
415                                         //  Object literal with conn and tId properties
416                                         obj = { conn:http, tId:transactionId };
417                                         break;
418                                 }
419                                 catch(e2){}
420                         }
421                 }
422                 finally
423                 {
424                         return obj;
425                 }
426         },
427
428   /**
429    * @description This method is called by asyncRequest to create a
430    * valid connection object for the transaction.  It also passes a
431    * transaction id and increments the transaction id counter.
432    * @method getConnectionObject
433    * @private
434    * @static
435    * @return {object}
436    */
437         getConnectionObject:function(isFileUpload)
438         {
439                 var o;
440                 var tId = this._transaction_id;
441
442                 try
443                 {
444                         if(!isFileUpload){
445                                 o = this.createXhrObject(tId);
446                         }
447                         else{
448                                 o = {};
449                                 o.tId = tId;
450                                 o.isUpload = true;
451                         }
452
453                         if(o){
454                                 this._transaction_id++;
455                         }
456                 }
457                 catch(e){}
458                 finally
459                 {
460                         return o;
461                 }
462         },
463
464   /**
465    * @description Method for initiating an asynchronous request via the XHR object.
466    * @method asyncRequest
467    * @public
468    * @static
469    * @param {string} method HTTP transaction method
470    * @param {string} uri Fully qualified path of resource
471    * @param {callback} callback User-defined callback function or object
472    * @param {string} postData POST body
473    * @return {object} Returns the connection object
474    */
475         asyncRequest:function(method, uri, callback, postData)
476         {
477                 var o = (this._isFileUpload)?this.getConnectionObject(true):this.getConnectionObject();
478                 var args = (callback && callback.argument)?callback.argument:null;
479
480                 if(!o){
481                         return null;
482                 }
483                 else{
484
485                         // Intialize any transaction-specific custom events, if provided.
486                         if(callback && callback.customevents){
487                                 this.initCustomEvents(o, callback);
488                         }
489
490                         if(this._isFormSubmit){
491                                 if(this._isFileUpload){
492                                         this.uploadFile(o, callback, uri, postData);
493                                         return o;
494                                 }
495
496                                 // If the specified HTTP method is GET, setForm() will return an
497                                 // encoded string that is concatenated to the uri to
498                                 // create a querystring.
499                                 if(method.toUpperCase() == 'GET'){
500                                         if(this._sFormData.length !== 0){
501                                                 // If the URI already contains a querystring, append an ampersand
502                                                 // and then concatenate _sFormData to the URI.
503                                                 uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
504                                         }
505                                 }
506                                 else if(method.toUpperCase() == 'POST'){
507                                         // If POST data exist in addition to the HTML form data,
508                                         // it will be concatenated to the form data.
509                                         postData = postData?this._sFormData + "&" + postData:this._sFormData;
510                                 }
511                         }
512
513                         if(method.toUpperCase() == 'GET' && (callback && callback.cache === false)){
514                                 // If callback.cache is defined and set to false, a
515                                 // timestamp value will be added to the querystring.
516                                 uri += ((uri.indexOf('?') == -1)?'?':'&') + "rnd=" + new Date().valueOf().toString();
517                         }
518
519                         o.conn.open(method, uri, true);
520
521                         // Each transaction will automatically include a custom header of
522                         // "X-Requested-With: XMLHttpRequest" to identify the request as
523                         // having originated from Connection Manager.
524                         if(this._use_default_xhr_header){
525                                 if(!this._default_headers['X-Requested-With']){
526                                         this.initHeader('X-Requested-With', this._default_xhr_header, true);
527                                 }
528                         }
529
530                         //If the transaction method is POST and the POST header value is set to true
531                         //or a custom value, initalize the Content-Type header to this value.
532                         if((method.toUpperCase() === 'POST' && this._use_default_post_header) && this._isFormSubmit === false){
533                                 this.initHeader('Content-Type', this._default_post_header);
534                         }
535
536                         //Initialize all default and custom HTTP headers,
537                         if(this._has_default_headers || this._has_http_headers){
538                                 this.setHeader(o);
539                         }
540
541                         this.handleReadyState(o, callback);
542                         o.conn.send(postData || '');
543
544
545                         // Reset the HTML form data and state properties as
546                         // soon as the data are submitted.
547                         if(this._isFormSubmit === true){
548                                 this.resetFormState();
549                         }
550
551                         // Fire global custom event -- startEvent
552                         this.startEvent.fire(o, args);
553
554                         if(o.startEvent){
555                                 // Fire transaction custom event -- startEvent
556                                 o.startEvent.fire(o, args);
557                         }
558
559                         return o;
560                 }
561         },
562
563   /**
564    * @description This method creates and subscribes custom events,
565    * specific to each transaction
566    * @method initCustomEvents
567    * @private
568    * @static
569    * @param {object} o The connection object
570    * @param {callback} callback The user-defined callback object
571    * @return {void}
572    */
573         initCustomEvents:function(o, callback)
574         {
575                 var prop;
576                 // Enumerate through callback.customevents members and bind/subscribe
577                 // events that match in the _customEvents table.
578                 for(prop in callback.customevents){
579                         if(this._customEvents[prop][0]){
580                                 // Create the custom event
581                                 o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null);
582
583                                 // Subscribe the custom event
584                                 o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]);
585                         }
586                 }
587         },
588
589   /**
590    * @description This method serves as a timer that polls the XHR object's readyState
591    * property during a transaction, instead of binding a callback to the
592    * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
593    * will process the response, and the timer will be cleared.
594    * @method handleReadyState
595    * @private
596    * @static
597    * @param {object} o The connection object
598    * @param {callback} callback The user-defined callback object
599    * @return {void}
600    */
601
602     handleReadyState:function(o, callback)
603
604     {
605                 var oConn = this;
606                 var args = (callback && callback.argument)?callback.argument:null;
607
608                 if(callback && callback.timeout){
609                         this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
610                 }
611
612                 this._poll[o.tId] = window.setInterval(
613                         function(){
614                                 if(o.conn && o.conn.readyState === 4){
615
616                                         // Clear the polling interval for the transaction
617                                         // and remove the reference from _poll.
618                                         window.clearInterval(oConn._poll[o.tId]);
619                                         delete oConn._poll[o.tId];
620
621                                         if(callback && callback.timeout){
622                                                 window.clearTimeout(oConn._timeOut[o.tId]);
623                                                 delete oConn._timeOut[o.tId];
624                                         }
625
626                                         // Fire global custom event -- completeEvent
627                                         oConn.completeEvent.fire(o, args);
628
629                                         if(o.completeEvent){
630                                                 // Fire transaction custom event -- completeEvent
631                                                 o.completeEvent.fire(o, args);
632                                         }
633
634                                         oConn.handleTransactionResponse(o, callback);
635                                 }
636                         }
637                 ,this._polling_interval);
638     },
639
640   /**
641    * @description This method attempts to interpret the server response and
642    * determine whether the transaction was successful, or if an error or
643    * exception was encountered.
644    * @method handleTransactionResponse
645    * @private
646    * @static
647    * @param {object} o The connection object
648    * @param {object} callback The user-defined callback object
649    * @param {boolean} isAbort Determines if the transaction was terminated via abort().
650    * @return {void}
651    */
652     handleTransactionResponse:function(o, callback, isAbort)
653     {
654                 var httpStatus, responseObject;
655                 var args = (callback && callback.argument)?callback.argument:null;
656
657                 try
658                 {
659                         if(o.conn.status !== undefined && o.conn.status !== 0){
660                                 httpStatus = o.conn.status;
661                         }
662                         else{
663                                 httpStatus = 13030;
664                         }
665                 }
666                 catch(e){
667
668                          // 13030 is a custom code to indicate the condition -- in Mozilla/FF --
669                          // when the XHR object's status and statusText properties are
670                          // unavailable, and a query attempt throws an exception.
671                         httpStatus = 13030;
672                 }
673
674                 if(httpStatus >= 200 && httpStatus < 300 || httpStatus === 1223){
675                         responseObject = this.createResponseObject(o, args);
676                         if(callback && callback.success){
677                                 if(!callback.scope){
678                                         callback.success(responseObject);
679                                 }
680                                 else{
681                                         // If a scope property is defined, the callback will be fired from
682                                         // the context of the object.
683                                         callback.success.apply(callback.scope, [responseObject]);
684                                 }
685                         }
686
687                         // Fire global custom event -- successEvent
688                         this.successEvent.fire(responseObject);
689
690                         if(o.successEvent){
691                                 // Fire transaction custom event -- successEvent
692                                 o.successEvent.fire(responseObject);
693                         }
694                 }
695                 else{
696                         switch(httpStatus){
697                                 // The following cases are wininet.dll error codes that may be encountered.
698                                 case 12002: // Server timeout
699                                 case 12029: // 12029 to 12031 correspond to dropped connections.
700                                 case 12030:
701                                 case 12031:
702                                 case 12152: // Connection closed by server.
703                                 case 13030: // See above comments for variable status.
704                                         responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false));
705                                         if(callback && callback.failure){
706                                                 if(!callback.scope){
707                                                         callback.failure(responseObject);
708                                                 }
709                                                 else{
710                                                         callback.failure.apply(callback.scope, [responseObject]);
711                                                 }
712                                         }
713
714                                         break;
715                                 default:
716                                         responseObject = this.createResponseObject(o, args);
717                                         if(callback && callback.failure){
718                                                 if(!callback.scope){
719                                                         callback.failure(responseObject);
720                                                 }
721                                                 else{
722                                                         callback.failure.apply(callback.scope, [responseObject]);
723                                                 }
724                                         }
725                         }
726
727                         // Fire global custom event -- failureEvent
728                         this.failureEvent.fire(responseObject);
729
730                         if(o.failureEvent){
731                                 // Fire transaction custom event -- failureEvent
732                                 o.failureEvent.fire(responseObject);
733                         }
734
735                 }
736
737                 this.releaseObject(o);
738                 responseObject = null;
739     },
740
741   /**
742    * @description This method evaluates the server response, creates and returns the results via
743    * its properties.  Success and failure cases will differ in the response
744    * object's property values.
745    * @method createResponseObject
746    * @private
747    * @static
748    * @param {object} o The connection object
749    * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
750    * @return {object}
751    */
752     createResponseObject:function(o, callbackArg)
753     {
754                 var obj = {};
755                 var headerObj = {};
756
757                 try
758                 {
759                         var headerStr = o.conn.getAllResponseHeaders();
760                         var header = headerStr.split('\n');
761                         for(var i=0; i<header.length; i++){
762                                 var delimitPos = header[i].indexOf(':');
763                                 if(delimitPos != -1){
764                                         headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
765                                 }
766                         }
767                 }
768                 catch(e){}
769
770                 obj.tId = o.tId;
771                 // Normalize IE's response to HTTP 204 when Win error 1223.
772                 obj.status = (o.conn.status == 1223)?204:o.conn.status;
773                 // Normalize IE's statusText to "No Content" instead of "Unknown".
774                 obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText;
775                 obj.getResponseHeader = headerObj;
776                 obj.getAllResponseHeaders = headerStr;
777                 obj.responseText = o.conn.responseText;
778                 obj.responseXML = o.conn.responseXML;
779
780                 if(callbackArg){
781                         obj.argument = callbackArg;
782                 }
783
784                 return obj;
785     },
786
787   /**
788    * @description If a transaction cannot be completed due to dropped or closed connections,
789    * there may be not be enough information to build a full response object.
790    * The failure callback will be fired and this specific condition can be identified
791    * by a status property value of 0.
792    *
793    * If an abort was successful, the status property will report a value of -1.
794    *
795    * @method createExceptionObject
796    * @private
797    * @static
798    * @param {int} tId The Transaction Id
799    * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
800    * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
801    * @return {object}
802    */
803     createExceptionObject:function(tId, callbackArg, isAbort)
804     {
805                 var COMM_CODE = 0;
806                 var COMM_ERROR = 'communication failure';
807                 var ABORT_CODE = -1;
808                 var ABORT_ERROR = 'transaction aborted';
809
810                 var obj = {};
811
812                 obj.tId = tId;
813                 if(isAbort){
814                         obj.status = ABORT_CODE;
815                         obj.statusText = ABORT_ERROR;
816                 }
817                 else{
818                         obj.status = COMM_CODE;
819                         obj.statusText = COMM_ERROR;
820                 }
821
822                 if(callbackArg){
823                         obj.argument = callbackArg;
824                 }
825
826                 return obj;
827     },
828
829   /**
830    * @description Method that initializes the custom HTTP headers for the each transaction.
831    * @method initHeader
832    * @public
833    * @static
834    * @param {string} label The HTTP header label
835    * @param {string} value The HTTP header value
836    * @param {string} isDefault Determines if the specific header is a default header
837    * automatically sent with each transaction.
838    * @return {void}
839    */
840         initHeader:function(label, value, isDefault)
841         {
842                 var headerObj = (isDefault)?this._default_headers:this._http_headers;
843                 headerObj[label] = value;
844
845                 if(isDefault){
846                         this._has_default_headers = true;
847                 }
848                 else{
849                         this._has_http_headers = true;
850                 }
851         },
852
853
854   /**
855    * @description Accessor that sets the HTTP headers for each transaction.
856    * @method setHeader
857    * @private
858    * @static
859    * @param {object} o The connection object for the transaction.
860    * @return {void}
861    */
862         setHeader:function(o)
863         {
864                 var prop;
865                 if(this._has_default_headers){
866                         for(prop in this._default_headers){
867                                 if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){
868                                         o.conn.setRequestHeader(prop, this._default_headers[prop]);
869                                 }
870                         }
871                 }
872
873                 if(this._has_http_headers){
874                         for(prop in this._http_headers){
875                                 if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){
876                                         o.conn.setRequestHeader(prop, this._http_headers[prop]);
877                                 }
878                         }
879                         delete this._http_headers;
880
881                         this._http_headers = {};
882                         this._has_http_headers = false;
883                 }
884         },
885
886   /**
887    * @description Resets the default HTTP headers object
888    * @method resetDefaultHeaders
889    * @public
890    * @static
891    * @return {void}
892    */
893         resetDefaultHeaders:function(){
894                 delete this._default_headers;
895                 this._default_headers = {};
896                 this._has_default_headers = false;
897         },
898
899   /**
900    * @description This method assembles the form label and value pairs and
901    * constructs an encoded string.
902    * asyncRequest() will automatically initialize the transaction with a
903    * a HTTP header Content-Type of application/x-www-form-urlencoded.
904    * @method setForm
905    * @public
906    * @static
907    * @param {string || object} form id or name attribute, or form object.
908    * @param {boolean} optional enable file upload.
909    * @param {boolean} optional enable file upload over SSL in IE only.
910    * @return {string} string of the HTML form field name and value pairs..
911    */
912         setForm:function(formId, isUpload, secureUri)
913         {
914         var oForm, oElement, oName, oValue, oDisabled,
915             hasSubmit = false,
916             data = [], item = 0,
917             i,len,j,jlen,opt;
918
919                 this.resetFormState();
920
921                 if(typeof formId == 'string'){
922                         // Determine if the argument is a form id or a form name.
923                         // Note form name usage is deprecated by supported
924                         // here for legacy reasons.
925                         oForm = (document.getElementById(formId) || document.forms[formId]);
926                 }
927                 else if(typeof formId == 'object'){
928                         // Treat argument as an HTML form object.
929                         oForm = formId;
930                 }
931                 else{
932                         return;
933                 }
934
935                 // If the isUpload argument is true, setForm will call createFrame to initialize
936                 // an iframe as the form target.
937                 //
938                 // The argument secureURI is also required by IE in SSL environments
939                 // where the secureURI string is a fully qualified HTTP path, used to set the source
940                 // of the iframe, to a stub resource in the same domain.
941                 if(isUpload){
942
943                         // Create iframe in preparation for file upload.
944                         this.createFrame(secureUri?secureUri:null);
945
946                         // Set form reference and file upload properties to true.
947                         this._isFormSubmit = true;
948                         this._isFileUpload = true;
949                         this._formNode = oForm;
950
951                         return;
952
953                 }
954
955                 // Iterate over the form elements collection to construct the
956                 // label-value pairs.
957                 for (i=0,len=oForm.elements.length; i<len; ++i){
958                         oElement  = oForm.elements[i];
959                         oDisabled = oElement.disabled;
960             oName     = oElement.name;
961
962                         // Do not submit fields that are disabled or
963                         // do not have a name attribute value.
964                         if(!oDisabled && oName)
965                         {
966                 oName  = encodeURIComponent(oName)+'=';
967                 oValue = encodeURIComponent(oElement.value);
968
969                                 switch(oElement.type)
970                                 {
971                     // Safari, Opera, FF all default opt.value from .text if
972                     // value attribute not specified in markup
973                                         case 'select-one':
974                         if (oElement.selectedIndex > -1) {
975                             opt = oElement.options[oElement.selectedIndex];
976                             data[item++] = oName + encodeURIComponent(
977                                 (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
978                         }
979                         break;
980                                         case 'select-multiple':
981                         if (oElement.selectedIndex > -1) {
982                             for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){
983                                 opt = oElement.options[j];
984                                 if (opt.selected) {
985                                     data[item++] = oName + encodeURIComponent(
986                                         (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
987                                 }
988                             }
989                         }
990                                                 break;
991                                         case 'radio':
992                                         case 'checkbox':
993                                                 if(oElement.checked){
994                             data[item++] = oName + oValue;
995                                                 }
996                                                 break;
997                                         case 'file':
998                                                 // stub case as XMLHttpRequest will only send the file path as a string.
999                                         case undefined:
1000                                                 // stub case for fieldset element which returns undefined.
1001                                         case 'reset':
1002                                                 // stub case for input type reset button.
1003                                         case 'button':
1004                                                 // stub case for input type button elements.
1005                                                 break;
1006                                         case 'submit':
1007                                                 if(hasSubmit === false){
1008                                                         if(this._hasSubmitListener && this._submitElementValue){
1009                                 data[item++] = this._submitElementValue;
1010                                                         }
1011                                                         hasSubmit = true;
1012                                                 }
1013                                                 break;
1014                                         default:
1015                         data[item++] = oName + oValue;
1016                                 }
1017                         }
1018                 }
1019
1020                 this._isFormSubmit = true;
1021                 this._sFormData = data.join('&');
1022
1023
1024                 this.initHeader('Content-Type', this._default_form_header);
1025
1026                 return this._sFormData;
1027         },
1028
1029   /**
1030    * @description Resets HTML form properties when an HTML form or HTML form
1031    * with file upload transaction is sent.
1032    * @method resetFormState
1033    * @private
1034    * @static
1035    * @return {void}
1036    */
1037         resetFormState:function(){
1038                 this._isFormSubmit = false;
1039                 this._isFileUpload = false;
1040                 this._formNode = null;
1041                 this._sFormData = "";
1042         },
1043
1044   /**
1045    * @description Creates an iframe to be used for form file uploads.  It is remove from the
1046    * document upon completion of the upload transaction.
1047    * @method createFrame
1048    * @private
1049    * @static
1050    * @param {string} optional qualified path of iframe resource for SSL in IE.
1051    * @return {void}
1052    */
1053         createFrame:function(secureUri){
1054
1055                 // IE does not allow the setting of id and name attributes as object
1056                 // properties via createElement().  A different iframe creation
1057                 // pattern is required for IE.
1058                 var frameId = 'yuiIO' + this._transaction_id;
1059                 var io;
1060                 if(YAHOO.env.ua.ie){
1061                         io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
1062
1063                         // IE will throw a security exception in an SSL environment if the
1064                         // iframe source is undefined.
1065                         if(typeof secureUri == 'boolean'){
1066                                 io.src = 'javascript:false';
1067                         }
1068                 }
1069                 else{
1070                         io = document.createElement('iframe');
1071                         io.id = frameId;
1072                         io.name = frameId;
1073                 }
1074
1075                 io.style.position = 'absolute';
1076                 io.style.top = '-1000px';
1077                 io.style.left = '-1000px';
1078
1079                 document.body.appendChild(io);
1080         },
1081
1082   /**
1083    * @description Parses the POST data and creates hidden form elements
1084    * for each key-value, and appends them to the HTML form object.
1085    * @method appendPostData
1086    * @private
1087    * @static
1088    * @param {string} postData The HTTP POST data
1089    * @return {array} formElements Collection of hidden fields.
1090    */
1091         appendPostData:function(postData)
1092         {
1093                 var formElements = [],
1094                         postMessage = postData.split('&'),
1095                         i, delimitPos;
1096                 for(i=0; i < postMessage.length; i++){
1097                         delimitPos = postMessage[i].indexOf('=');
1098                         if(delimitPos != -1){
1099                                 formElements[i] = document.createElement('input');
1100                                 formElements[i].type = 'hidden';
1101                                 formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos));
1102                                 formElements[i].value = decodeURIComponent(postMessage[i].substring(delimitPos+1));
1103                                 this._formNode.appendChild(formElements[i]);
1104                         }
1105                 }
1106
1107                 return formElements;
1108         },
1109
1110   /**
1111    * @description Uploads HTML form, inclusive of files/attachments, using the
1112    * iframe created in createFrame to facilitate the transaction.
1113    * @method uploadFile
1114    * @private
1115    * @static
1116    * @param {int} id The transaction id.
1117    * @param {object} callback User-defined callback object.
1118    * @param {string} uri Fully qualified path of resource.
1119    * @param {string} postData POST data to be submitted in addition to HTML form.
1120    * @return {void}
1121    */
1122         uploadFile:function(o, callback, uri, postData){
1123
1124                 // Each iframe has an id prefix of "yuiIO" followed
1125                 // by the unique transaction id.
1126                 var frameId = 'yuiIO' + o.tId,
1127                     uploadEncoding = 'multipart/form-data',
1128                     io = document.getElementById(frameId),
1129                     oConn = this,
1130                         args = (callback && callback.argument)?callback.argument:null,
1131             oElements,i,prop,obj;
1132
1133                 // Track original HTML form attribute values.
1134                 var rawFormAttributes =
1135                 {
1136                         action:this._formNode.getAttribute('action'),
1137                         method:this._formNode.getAttribute('method'),
1138                         target:this._formNode.getAttribute('target')
1139                 };
1140
1141                 // Initialize the HTML form properties in case they are
1142                 // not defined in the HTML form.
1143                 this._formNode.setAttribute('action', uri);
1144                 this._formNode.setAttribute('method', 'POST');
1145                 this._formNode.setAttribute('target', frameId);
1146
1147                 if(YAHOO.env.ua.ie){
1148                         // IE does not respect property enctype for HTML forms.
1149                         // Instead it uses the property - "encoding".
1150                         this._formNode.setAttribute('encoding', uploadEncoding);
1151                 }
1152                 else{
1153                         this._formNode.setAttribute('enctype', uploadEncoding);
1154                 }
1155
1156                 if(postData){
1157                         oElements = this.appendPostData(postData);
1158                 }
1159
1160                 // Start file upload.
1161                 this._formNode.submit();
1162
1163                 // Fire global custom event -- startEvent
1164                 this.startEvent.fire(o, args);
1165
1166                 if(o.startEvent){
1167                         // Fire transaction custom event -- startEvent
1168                         o.startEvent.fire(o, args);
1169                 }
1170
1171                 // Start polling if a callback is present and the timeout
1172                 // property has been defined.
1173                 if(callback && callback.timeout){
1174                         this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
1175                 }
1176
1177                 // Remove HTML elements created by appendPostData
1178                 if(oElements && oElements.length > 0){
1179                         for(i=0; i < oElements.length; i++){
1180                                 this._formNode.removeChild(oElements[i]);
1181                         }
1182                 }
1183
1184                 // Restore HTML form attributes to their original
1185                 // values prior to file upload.
1186                 for(prop in rawFormAttributes){
1187                         if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){
1188                                 if(rawFormAttributes[prop]){
1189                                         this._formNode.setAttribute(prop, rawFormAttributes[prop]);
1190                                 }
1191                                 else{
1192                                         this._formNode.removeAttribute(prop);
1193                                 }
1194                         }
1195                 }
1196
1197                 // Reset HTML form state properties.
1198                 this.resetFormState();
1199
1200                 // Create the upload callback handler that fires when the iframe
1201                 // receives the load event.  Subsequently, the event handler is detached
1202                 // and the iframe removed from the document.
1203                 var uploadCallback = function()
1204                 {
1205                         if(callback && callback.timeout){
1206                                 window.clearTimeout(oConn._timeOut[o.tId]);
1207                                 delete oConn._timeOut[o.tId];
1208                         }
1209
1210                         // Fire global custom event -- completeEvent
1211                         oConn.completeEvent.fire(o, args);
1212
1213                         if(o.completeEvent){
1214                                 // Fire transaction custom event -- completeEvent
1215                                 o.completeEvent.fire(o, args);
1216                         }
1217
1218                         obj = {
1219                             tId : o.tId,
1220                             argument : callback.argument
1221             };
1222
1223                         try
1224                         {
1225                                 // responseText and responseXML will be populated with the same data from the iframe.
1226                                 // Since the HTTP headers cannot be read from the iframe
1227                                 obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent;
1228                                 obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
1229                         }
1230                         catch(e){}
1231
1232                         if(callback && callback.upload){
1233                                 if(!callback.scope){
1234                                         callback.upload(obj);
1235                                 }
1236                                 else{
1237                                         callback.upload.apply(callback.scope, [obj]);
1238                                 }
1239                         }
1240
1241                         // Fire global custom event -- uploadEvent
1242                         oConn.uploadEvent.fire(obj);
1243
1244                         if(o.uploadEvent){
1245                                 // Fire transaction custom event -- uploadEvent
1246                                 o.uploadEvent.fire(obj);
1247                         }
1248
1249                         YAHOO.util.Event.removeListener(io, "load", uploadCallback);
1250
1251                         setTimeout(
1252                                 function(){
1253                                         document.body.removeChild(io);
1254                                         oConn.releaseObject(o);
1255                                 }, 100);
1256                 };
1257
1258                 // Bind the onload handler to the iframe to detect the file upload response.
1259                 YAHOO.util.Event.addListener(io, "load", uploadCallback);
1260         },
1261
1262   /**
1263    * @description Method to terminate a transaction, if it has not reached readyState 4.
1264    * @method abort
1265    * @public
1266    * @static
1267    * @param {object} o The connection object returned by asyncRequest.
1268    * @param {object} callback  User-defined callback object.
1269    * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout.
1270    * @return {boolean}
1271    */
1272         abort:function(o, callback, isTimeout)
1273         {
1274                 var abortStatus;
1275                 var args = (callback && callback.argument)?callback.argument:null;
1276
1277
1278                 if(o && o.conn){
1279                         if(this.isCallInProgress(o)){
1280                                 // Issue abort request
1281                                 o.conn.abort();
1282
1283                                 window.clearInterval(this._poll[o.tId]);
1284                                 delete this._poll[o.tId];
1285
1286                                 if(isTimeout){
1287                                         window.clearTimeout(this._timeOut[o.tId]);
1288                                         delete this._timeOut[o.tId];
1289                                 }
1290
1291                                 abortStatus = true;
1292                         }
1293                 }
1294                 else if(o && o.isUpload === true){
1295                         var frameId = 'yuiIO' + o.tId;
1296                         var io = document.getElementById(frameId);
1297
1298                         if(io){
1299                                 // Remove all listeners on the iframe prior to
1300                                 // its destruction.
1301                                 YAHOO.util.Event.removeListener(io, "load");
1302                                 // Destroy the iframe facilitating the transaction.
1303                                 document.body.removeChild(io);
1304
1305                                 if(isTimeout){
1306                                         window.clearTimeout(this._timeOut[o.tId]);
1307                                         delete this._timeOut[o.tId];
1308                                 }
1309
1310                                 abortStatus = true;
1311                         }
1312                 }
1313                 else{
1314                         abortStatus = false;
1315                 }
1316
1317                 if(abortStatus === true){
1318                         // Fire global custom event -- abortEvent
1319                         this.abortEvent.fire(o, args);
1320
1321                         if(o.abortEvent){
1322                                 // Fire transaction custom event -- abortEvent
1323                                 o.abortEvent.fire(o, args);
1324                         }
1325
1326                         this.handleTransactionResponse(o, callback, true);
1327                 }
1328
1329                 return abortStatus;
1330         },
1331
1332   /**
1333    * @description Determines if the transaction is still being processed.
1334    * @method isCallInProgress
1335    * @public
1336    * @static
1337    * @param {object} o The connection object returned by asyncRequest
1338    * @return {boolean}
1339    */
1340         isCallInProgress:function(o)
1341         {
1342                 // if the XHR object assigned to the transaction has not been dereferenced,
1343                 // then check its readyState status.  Otherwise, return false.
1344                 if(o && o.conn){
1345                         return o.conn.readyState !== 4 && o.conn.readyState !== 0;
1346                 }
1347                 else if(o && o.isUpload === true){
1348                         var frameId = 'yuiIO' + o.tId;
1349                         return document.getElementById(frameId)?true:false;
1350                 }
1351                 else{
1352                         return false;
1353                 }
1354         },
1355
1356   /**
1357    * @description Dereference the XHR instance and the connection object after the transaction is completed.
1358    * @method releaseObject
1359    * @private
1360    * @static
1361    * @param {object} o The connection object
1362    * @return {void}
1363    */
1364         releaseObject:function(o)
1365         {
1366                 if(o && o.conn){
1367                         //dereference the XHR instance.
1368                         o.conn = null;
1369
1370
1371                         //dereference the connection object.
1372                         o = null;
1373                 }
1374         }
1375 };
1376 YAHOO.register("connection", YAHOO.util.Connect, {version: "2.7.0", build: "1799"});