Project

General

Profile

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.8.0r4
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 Collection of polling references to the polling mechanism in handleReadyState.
135
 * @property _poll
136
 * @private
137
 * @static
138
 * @type object
139
  */
140
    _poll:{},
141

    
142
 /**
143
 * @description Queue of timeout values for each transaction callback with a defined timeout value.
144
 * @property _timeOut
145
 * @private
146
 * @static
147
 * @type object
148
  */
149
    _timeOut:{},
150

    
151
  /**
152
  * @description The polling frequency, in milliseconds, for HandleReadyState.
153
   * when attempting to determine a transaction's XHR readyState.
154
   * The default is 50 milliseconds.
155
  * @property _polling_interval
156
  * @private
157
  * @static
158
  * @type int
159
   */
160
     _polling_interval:50,
161

    
162
  /**
163
  * @description A transaction counter that increments the transaction id for each transaction.
164
  * @property _transaction_id
165
  * @private
166
  * @static
167
  * @type int
168
   */
169
     _transaction_id:0,
170

    
171
  /**
172
  * @description Custom event that fires at the start of a transaction
173
  * @property startEvent
174
  * @private
175
  * @static
176
  * @type CustomEvent
177
   */
178
    startEvent: new YAHOO.util.CustomEvent('start'),
179

    
180
  /**
181
  * @description Custom event that fires when a transaction response has completed.
182
  * @property completeEvent
183
  * @private
184
  * @static
185
  * @type CustomEvent
186
   */
187
    completeEvent: new YAHOO.util.CustomEvent('complete'),
188

    
189
  /**
190
  * @description Custom event that fires when handleTransactionResponse() determines a
191
   * response in the HTTP 2xx range.
192
  * @property successEvent
193
  * @private
194
  * @static
195
  * @type CustomEvent
196
   */
197
    successEvent: new YAHOO.util.CustomEvent('success'),
198

    
199
  /**
200
  * @description Custom event that fires when handleTransactionResponse() determines a
201
   * response in the HTTP 4xx/5xx range.
202
  * @property failureEvent
203
  * @private
204
  * @static
205
  * @type CustomEvent
206
   */
207
    failureEvent: new YAHOO.util.CustomEvent('failure'),
208

    
209
  /**
210
  * @description Custom event that fires when a transaction is successfully aborted.
211
  * @property abortEvent
212
  * @private
213
  * @static
214
  * @type CustomEvent
215
   */
216
    abortEvent: new YAHOO.util.CustomEvent('abort'),
217

    
218
  /**
219
  * @description A reference table that maps callback custom events members to its specific
220
   * event name.
221
  * @property _customEvents
222
  * @private
223
  * @static
224
  * @type object
225
   */
226
    _customEvents:
227
    {
228
        onStart:['startEvent', 'start'],
229
        onComplete:['completeEvent', 'complete'],
230
        onSuccess:['successEvent', 'success'],
231
        onFailure:['failureEvent', 'failure'],
232
        onUpload:['uploadEvent', 'upload'],
233
        onAbort:['abortEvent', 'abort']
234
    },
235

    
236
  /**
237
  * @description Member to add an ActiveX id to the existing xml_progid array.
238
   * In the event(unlikely) a new ActiveX id is introduced, it can be added
239
   * without internal code modifications.
240
  * @method setProgId
241
  * @public
242
  * @static
243
  * @param {string} id The ActiveX id to be added to initialize the XHR object.
244
  * @return void
245
   */
246
    setProgId:function(id)
247
    {
248
        this._msxml_progid.unshift(id);
249
    },
250

    
251
  /**
252
  * @description Member to override the default POST header.
253
  * @method setDefaultPostHeader
254
  * @public
255
  * @static
256
  * @param {boolean} b Set and use default header - true or false .
257
  * @return void
258
   */
259
    setDefaultPostHeader:function(b)
260
    {
261
        if(typeof b == 'string'){
262
            this._default_post_header = b;
263
        }
264
        else if(typeof b == 'boolean'){
265
            this._use_default_post_header = b;
266
        }
267
    },
268

    
269
  /**
270
  * @description Member to override the default transaction header..
271
  * @method setDefaultXhrHeader
272
  * @public
273
  * @static
274
  * @param {boolean} b Set and use default header - true or false .
275
  * @return void
276
   */
277
    setDefaultXhrHeader:function(b)
278
    {
279
        if(typeof b == 'string'){
280
            this._default_xhr_header = b;
281
        }
282
        else{
283
            this._use_default_xhr_header = b;
284
        }
285
    },
286

    
287
  /**
288
  * @description Member to modify the default polling interval.
289
  * @method setPollingInterval
290
  * @public
291
  * @static
292
  * @param {int} i The polling interval in milliseconds.
293
  * @return void
294
   */
295
    setPollingInterval:function(i)
296
    {
297
        if(typeof i == 'number' && isFinite(i)){
298
            this._polling_interval = i;
299
        }
300
    },
301

    
302
  /**
303
  * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
304
   * the XMLHttpRequest instance and the transaction id.
305
  * @method createXhrObject
306
  * @private
307
  * @static
308
  * @param {int} transactionId Property containing the transaction id for this transaction.
309
  * @return object
310
   */
311
    createXhrObject:function(transactionId)
312
    {
313
        var obj,http,i;
314
        try
315
        {
316
            // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
317
            http = new XMLHttpRequest();
318
            //  Object literal with http and tId properties
319
            obj = { conn:http, tId:transactionId, xhr: true };
320
        }
321
        catch(e)
322
        {
323
            for(i=0; i<this._msxml_progid.length; ++i){
324
                try
325
                {
326
                    // Instantiates XMLHttpRequest for IE and assign to http
327
                    http = new ActiveXObject(this._msxml_progid[i]);
328
                    //  Object literal with conn and tId properties
329
                    obj = { conn:http, tId:transactionId, xhr: true };
330
                    break;
331
                }
332
                catch(e1){}
333
            }
334
        }
335
        finally
336
        {
337
            return obj;
338
        }
339
    },
340

    
341
  /**
342
  * @description This method is called by asyncRequest to create a
343
   * valid connection object for the transaction.  It also passes a
344
   * transaction id and increments the transaction id counter.
345
  * @method getConnectionObject
346
  * @private
347
  * @static
348
  * @return {object}
349
   */
350
    getConnectionObject:function(t)
351
    {
352
        var o, tId = this._transaction_id;
353

    
354
        try
355
        {
356
            if(!t){
357
                o = this.createXhrObject(tId);
358
            }
359
            else{
360
                o = {tId:tId};
361
                if(t==='xdr'){
362
                    o.conn = this._transport;
363
                    o.xdr = true;
364
                }
365
                else if(t==='upload'){
366
                    o.upload = true;
367
                }
368
            }
369

    
370
            if(o){
371
                this._transaction_id++;
372
            }
373
        }
374
        catch(e){}
375
        return o;
376
    },
377

    
378
  /**
379
  * @description Method for initiating an asynchronous request via the XHR object.
380
  * @method asyncRequest
381
  * @public
382
  * @static
383
  * @param {string} method HTTP transaction method
384
  * @param {string} uri Fully qualified path of resource
385
  * @param {callback} callback User-defined callback function or object
386
  * @param {string} postData POST body
387
  * @return {object} Returns the connection object
388
   */
389
    asyncRequest:function(method, uri, callback, postData)
390
    {
391
        var o,t,args = (callback && callback.argument)?callback.argument:null;
392

    
393
        if(this._isFileUpload){
394
            t = 'upload';
395
        }
396
        else if(callback.xdr){
397
            t = 'xdr';
398
        }
399

    
400
        o = this.getConnectionObject(t);
401
        if(!o){
402
            return null;
403
        }
404
        else{
405

    
406
            // Intialize any transaction-specific custom events, if provided.
407
            if(callback && callback.customevents){
408
                this.initCustomEvents(o, callback);
409
            }
410

    
411
            if(this._isFormSubmit){
412
                if(this._isFileUpload){
413
                    this.uploadFile(o, callback, uri, postData);
414
                    return o;
415
                }
416

    
417
                // If the specified HTTP method is GET, setForm() will return an
418
                // encoded string that is concatenated to the uri to
419
                // create a querystring.
420
                if(method.toUpperCase() == 'GET'){
421
                    if(this._sFormData.length !== 0){
422
                        // If the URI already contains a querystring, append an ampersand
423
                        // and then concatenate _sFormData to the URI.
424
                        uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
425
                    }
426
                }
427
                else if(method.toUpperCase() == 'POST'){
428
                    // If POST data exist in addition to the HTML form data,
429
                    // it will be concatenated to the form data.
430
                    postData = postData?this._sFormData + "&" + postData:this._sFormData;
431
                }
432
            }
433

    
434
            if(method.toUpperCase() == 'GET' && (callback && callback.cache === false)){
435
                // If callback.cache is defined and set to false, a
436
                // timestamp value will be added to the querystring.
437
                uri += ((uri.indexOf('?') == -1)?'?':'&') + "rnd=" + new Date().valueOf().toString();
438
            }
439

    
440
            // Each transaction will automatically include a custom header of
441
            // "X-Requested-With: XMLHttpRequest" to identify the request as
442
            // having originated from Connection Manager.
443
            if(this._use_default_xhr_header){
444
                if(!this._default_headers['X-Requested-With']){
445
                    this.initHeader('X-Requested-With', this._default_xhr_header, true);
446
                }
447
            }
448

    
449
            //If the transaction method is POST and the POST header value is set to true
450
            //or a custom value, initalize the Content-Type header to this value.
451
            if((method.toUpperCase() === 'POST' && this._use_default_post_header) && this._isFormSubmit === false){
452
                this.initHeader('Content-Type', this._default_post_header);
453
            }
454

    
455
            if(o.xdr){
456
                this.xdr(o, method, uri, callback, postData);
457
                return o;
458
            }
459

    
460
            o.conn.open(method, uri, true);
461
            //Initialize all default and custom HTTP headers,
462
            if(this._has_default_headers || this._has_http_headers){
463
                this.setHeader(o);
464
            }
465

    
466
            this.handleReadyState(o, callback);
467
            o.conn.send(postData || '');
468

    
469
            // Reset the HTML form data and state properties as
470
            // soon as the data are submitted.
471
            if(this._isFormSubmit === true){
472
                this.resetFormState();
473
            }
474

    
475
            // Fire global custom event -- startEvent
476
            this.startEvent.fire(o, args);
477

    
478
            if(o.startEvent){
479
                // Fire transaction custom event -- startEvent
480
                o.startEvent.fire(o, args);
481
            }
482

    
483
            return o;
484
        }
485
    },
486

    
487
  /**
488
  * @description This method creates and subscribes custom events,
489
   * specific to each transaction
490
  * @method initCustomEvents
491
  * @private
492
  * @static
493
  * @param {object} o The connection object
494
  * @param {callback} callback The user-defined callback object
495
  * @return {void}
496
   */
497
    initCustomEvents:function(o, callback)
498
    {
499
        var prop;
500
        // Enumerate through callback.customevents members and bind/subscribe
501
        // events that match in the _customEvents table.
502
        for(prop in callback.customevents){
503
            if(this._customEvents[prop][0]){
504
                // Create the custom event
505
                o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null);
506

    
507
                // Subscribe the custom event
508
                o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]);
509
            }
510
        }
511
    },
512

    
513
  /**
514
  * @description This method serves as a timer that polls the XHR object's readyState
515
   * property during a transaction, instead of binding a callback to the
516
   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
517
   * will process the response, and the timer will be cleared.
518
  * @method handleReadyState
519
  * @private
520
  * @static
521
  * @param {object} o The connection object
522
  * @param {callback} callback The user-defined callback object
523
  * @return {void}
524
   */
525

    
526
    handleReadyState:function(o, callback)
527

    
528
    {
529
        var oConn = this,
530
            args = (callback && callback.argument)?callback.argument:null;
531

    
532
        if(callback && callback.timeout){
533
            this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
534
        }
535

    
536
        this._poll[o.tId] = window.setInterval(
537
            function(){
538
                if(o.conn && o.conn.readyState === 4){
539

    
540
                    // Clear the polling interval for the transaction
541
                    // and remove the reference from _poll.
542
                    window.clearInterval(oConn._poll[o.tId]);
543
                    delete oConn._poll[o.tId];
544

    
545
                    if(callback && callback.timeout){
546
                        window.clearTimeout(oConn._timeOut[o.tId]);
547
                        delete oConn._timeOut[o.tId];
548
                    }
549

    
550
                    // Fire global custom event -- completeEvent
551
                    oConn.completeEvent.fire(o, args);
552

    
553
                    if(o.completeEvent){
554
                        // Fire transaction custom event -- completeEvent
555
                        o.completeEvent.fire(o, args);
556
                    }
557

    
558
                    oConn.handleTransactionResponse(o, callback);
559
                }
560
            }
561
        ,this._polling_interval);
562
    },
563

    
564
  /**
565
  * @description This method attempts to interpret the server response and
566
   * determine whether the transaction was successful, or if an error or
567
   * exception was encountered.
568
  * @method handleTransactionResponse
569
  * @private
570
  * @static
571
  * @param {object} o The connection object
572
  * @param {object} callback The user-defined callback object
573
  * @param {boolean} isAbort Determines if the transaction was terminated via abort().
574
  * @return {void}
575
   */
576
    handleTransactionResponse:function(o, callback, isAbort)
577
    {
578
        var httpStatus, responseObject,
579
            args = (callback && callback.argument)?callback.argument:null,
580
            xdrS = (o.r && o.r.statusText === 'xdr:success')?true:false,
581
            xdrF = (o.r && o.r.statusText === 'xdr:failure')?true:false,
582
            xdrA = isAbort;
583

    
584
        try
585
        {
586
            if((o.conn.status !== undefined && o.conn.status !== 0) || xdrS){
587
                // XDR requests will not have HTTP status defined. The
588
                // statusText property will define the response status
589
                // set by the Flash transport.
590
                httpStatus = o.conn.status;
591
            }
592
            else if(xdrF && !xdrA){
593
                // Set XDR transaction failure to a status of 0, which
594
                // resolves as an HTTP failure, instead of an exception.
595
                httpStatus = 0;
596
            }
597
            else{
598
                httpStatus = 13030;
599
            }
600
        }
601
        catch(e){
602

    
603
             // 13030 is a custom code to indicate the condition -- in Mozilla/FF --
604
             // when the XHR object's status and statusText properties are
605
             // unavailable, and a query attempt throws an exception.
606
            httpStatus = 13030;
607
        }
608

    
609
        if((httpStatus >= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){
610
            responseObject = o.xdr ? o.r : this.createResponseObject(o, args);
611
            if(callback && callback.success){
612
                if(!callback.scope){
613
                    callback.success(responseObject);
614
                }
615
                else{
616
                    // If a scope property is defined, the callback will be fired from
617
                    // the context of the object.
618
                    callback.success.apply(callback.scope, [responseObject]);
619
                }
620
            }
621

    
622
            // Fire global custom event -- successEvent
623
            this.successEvent.fire(responseObject);
624

    
625
            if(o.successEvent){
626
                // Fire transaction custom event -- successEvent
627
                o.successEvent.fire(responseObject);
628
            }
629
        }
630
        else{
631
            switch(httpStatus){
632
                // The following cases are wininet.dll error codes that may be encountered.
633
                case 12002: // Server timeout
634
                case 12029: // 12029 to 12031 correspond to dropped connections.
635
                case 12030:
636
                case 12031:
637
                case 12152: // Connection closed by server.
638
                case 13030: // See above comments for variable status.
639
                    // XDR transactions will not resolve to this case, since the
640
                    // response object is already built in the xdr response.
641
                    responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false));
642
                    if(callback && callback.failure){
643
                        if(!callback.scope){
644
                            callback.failure(responseObject);
645
                        }
646
                        else{
647
                            callback.failure.apply(callback.scope, [responseObject]);
648
                        }
649
                    }
650

    
651
                    break;
652
                default:
653
                    responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args);
654
                    if(callback && callback.failure){
655
                        if(!callback.scope){
656
                            callback.failure(responseObject);
657
                        }
658
                        else{
659
                            callback.failure.apply(callback.scope, [responseObject]);
660
                        }
661
                    }
662
            }
663

    
664
            // Fire global custom event -- failureEvent
665
            this.failureEvent.fire(responseObject);
666

    
667
            if(o.failureEvent){
668
                // Fire transaction custom event -- failureEvent
669
                o.failureEvent.fire(responseObject);
670
            }
671

    
672
        }
673

    
674
        this.releaseObject(o);
675
        responseObject = null;
676
    },
677

    
678
  /**
679
  * @description This method evaluates the server response, creates and returns the results via
680
   * its properties.  Success and failure cases will differ in the response
681
   * object's property values.
682
  * @method createResponseObject
683
  * @private
684
  * @static
685
  * @param {object} o The connection object
686
  * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
687
  * @return {object}
688
   */
689
    createResponseObject:function(o, callbackArg)
690
    {
691
        var obj = {}, headerObj = {},
692
            i, headerStr, header, delimitPos;
693

    
694
        try
695
        {
696
            headerStr = o.conn.getAllResponseHeaders();
697
            header = headerStr.split('\n');
698
            for(i=0; i<header.length; i++){
699
                delimitPos = header[i].indexOf(':');
700
                if(delimitPos != -1){
701
                    headerObj[header[i].substring(0,delimitPos)] = YAHOO.lang.trim(header[i].substring(delimitPos+2));
702
                }
703
            }
704
        }
705
        catch(e){}
706

    
707
        obj.tId = o.tId;
708
        // Normalize IE's response to HTTP 204 when Win error 1223.
709
        obj.status = (o.conn.status == 1223)?204:o.conn.status;
710
        // Normalize IE's statusText to "No Content" instead of "Unknown".
711
        obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText;
712
        obj.getResponseHeader = headerObj;
713
        obj.getAllResponseHeaders = headerStr;
714
        obj.responseText = o.conn.responseText;
715
        obj.responseXML = o.conn.responseXML;
716

    
717
        if(callbackArg){
718
            obj.argument = callbackArg;
719
        }
720

    
721
        return obj;
722
    },
723

    
724
  /**
725
  * @description If a transaction cannot be completed due to dropped or closed connections,
726
   * there may be not be enough information to build a full response object.
727
   * The failure callback will be fired and this specific condition can be identified
728
   * by a status property value of 0.
729
   *
730
   * If an abort was successful, the status property will report a value of -1.
731
   *
732
  * @method createExceptionObject
733
  * @private
734
  * @static
735
  * @param {int} tId The Transaction Id
736
  * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
737
  * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
738
  * @return {object}
739
   */
740
    createExceptionObject:function(tId, callbackArg, isAbort)
741
    {
742
        var COMM_CODE = 0,
743
            COMM_ERROR = 'communication failure',
744
            ABORT_CODE = -1,
745
            ABORT_ERROR = 'transaction aborted',
746
            obj = {};
747

    
748
        obj.tId = tId;
749
        if(isAbort){
750
            obj.status = ABORT_CODE;
751
            obj.statusText = ABORT_ERROR;
752
        }
753
        else{
754
            obj.status = COMM_CODE;
755
            obj.statusText = COMM_ERROR;
756
        }
757

    
758
        if(callbackArg){
759
            obj.argument = callbackArg;
760
        }
761

    
762
        return obj;
763
    },
764

    
765
  /**
766
  * @description Method that initializes the custom HTTP headers for the each transaction.
767
  * @method initHeader
768
  * @public
769
  * @static
770
  * @param {string} label The HTTP header label
771
  * @param {string} value The HTTP header value
772
  * @param {string} isDefault Determines if the specific header is a default header
773
   * automatically sent with each transaction.
774
  * @return {void}
775
   */
776
    initHeader:function(label, value, isDefault)
777
    {
778
        var headerObj = (isDefault)?this._default_headers:this._http_headers;
779

    
780
        headerObj[label] = value;
781
        if(isDefault){
782
            this._has_default_headers = true;
783
        }
784
        else{
785
            this._has_http_headers = true;
786
        }
787
    },
788

    
789

    
790
  /**
791
  * @description Accessor that sets the HTTP headers for each transaction.
792
  * @method setHeader
793
  * @private
794
  * @static
795
  * @param {object} o The connection object for the transaction.
796
  * @return {void}
797
   */
798
    setHeader:function(o)
799
    {
800
        var prop;
801
        if(this._has_default_headers){
802
            for(prop in this._default_headers){
803
                if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){
804
                    o.conn.setRequestHeader(prop, this._default_headers[prop]);
805
                }
806
            }
807
        }
808

    
809
        if(this._has_http_headers){
810
            for(prop in this._http_headers){
811
                if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){
812
                    o.conn.setRequestHeader(prop, this._http_headers[prop]);
813
                }
814
            }
815

    
816
            this._http_headers = {};
817
            this._has_http_headers = false;
818
        }
819
    },
820

    
821
  /**
822
  * @description Resets the default HTTP headers object
823
  * @method resetDefaultHeaders
824
  * @public
825
  * @static
826
  * @return {void}
827
   */
828
    resetDefaultHeaders:function(){
829
        this._default_headers = {};
830
        this._has_default_headers = false;
831
    },
832

    
833
  /**
834
  * @description Method to terminate a transaction, if it has not reached readyState 4.
835
  * @method abort
836
  * @public
837
  * @static
838
  * @param {object} o The connection object returned by asyncRequest.
839
  * @param {object} callback  User-defined callback object.
840
  * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout.
841
  * @return {boolean}
842
   */
843
    abort:function(o, callback, isTimeout)
844
    {
845
        var abortStatus,
846
            args = (callback && callback.argument)?callback.argument:null;
847
            o = o || {};
848

    
849
        if(o.conn){
850
            if(o.xhr){
851
                if(this.isCallInProgress(o)){
852
                    // Issue abort request
853
                    o.conn.abort();
854

    
855
                    window.clearInterval(this._poll[o.tId]);
856
                    delete this._poll[o.tId];
857

    
858
                    if(isTimeout){
859
                        window.clearTimeout(this._timeOut[o.tId]);
860
                        delete this._timeOut[o.tId];
861
                    }
862

    
863
                    abortStatus = true;
864
                }
865
            }
866
            else if(o.xdr){
867
                o.conn.abort(o.tId);
868
                abortStatus = true;
869
            }
870
        }
871
        else if(o.upload){
872
            var frameId = 'yuiIO' + o.tId;
873
            var io = document.getElementById(frameId);
874

    
875
            if(io){
876
                // Remove all listeners on the iframe prior to
877
                // its destruction.
878
                YAHOO.util.Event.removeListener(io, "load");
879
                // Destroy the iframe facilitating the transaction.
880
                document.body.removeChild(io);
881

    
882
                if(isTimeout){
883
                    window.clearTimeout(this._timeOut[o.tId]);
884
                    delete this._timeOut[o.tId];
885
                }
886

    
887
                abortStatus = true;
888
            }
889
        }
890
        else{
891
            abortStatus = false;
892
        }
893

    
894
        if(abortStatus === true){
895
            // Fire global custom event -- abortEvent
896
            this.abortEvent.fire(o, args);
897

    
898
            if(o.abortEvent){
899
                // Fire transaction custom event -- abortEvent
900
                o.abortEvent.fire(o, args);
901
            }
902

    
903
            this.handleTransactionResponse(o, callback, true);
904
        }
905

    
906
        return abortStatus;
907
    },
908

    
909
  /**
910
  * @description Determines if the transaction is still being processed.
911
  * @method isCallInProgress
912
  * @public
913
  * @static
914
  * @param {object} o The connection object returned by asyncRequest
915
  * @return {boolean}
916
   */
917
    isCallInProgress:function(o)
918
    {
919
        o = o || {};
920
        // if the XHR object assigned to the transaction has not been dereferenced,
921
        // then check its readyState status.  Otherwise, return false.
922
        if(o.xhr && o.conn){
923
            return o.conn.readyState !== 4 && o.conn.readyState !== 0;
924
        }
925
        else if(o.xdr && o.conn){
926
            return o.conn.isCallInProgress(o.tId);
927
        }
928
        else if(o.upload === true){
929
            return document.getElementById('yuiIO' + o.tId)?true:false;
930
        }
931
        else{
932
            return false;
933
        }
934
    },
935

    
936
  /**
937
  * @description Dereference the XHR instance and the connection object after the transaction is completed.
938
  * @method releaseObject
939
  * @private
940
  * @static
941
  * @param {object} o The connection object
942
  * @return {void}
943
   */
944
    releaseObject:function(o)
945
    {
946
        if(o && o.conn){
947
            //dereference the XHR instance.
948
            o.conn = null;
949

    
950

    
951
            //dereference the connection object.
952
            o = null;
953
        }
954
    }
955
};
956

    
957
/**
958
 * @for Connect
959
  */
960
(function() {
961
    var YCM = YAHOO.util.Connect, _fn = {};
962

    
963
   /**
964
   * @description This method creates and instantiates the Flash transport.
965
   * @method _swf
966
   * @private
967
   * @static
968
   * @param {string} URI to connection.swf.
969
   * @return {void}
970
    */
971
    function _swf(uri) {
972
        var o = '<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="' +
973
                uri + '" width="0" height="0">' +
974
                 '<param name="movie" value="' + uri + '">' +
975
                '<param name="allowScriptAccess" value="always">' +
976
                '</object>',
977
            c = document.createElement('div');
978

    
979
        document.body.appendChild(c);
980
        c.innerHTML = o;
981
    }
982

    
983
   /**
984
   * @description This method calls the public method on the
985
    * Flash transport to start the XDR transaction.  It is analogous
986
    * to Connection Manager's asyncRequest method.
987
   * @method xdr
988
   * @private
989
   * @static
990
   * @param {object} The transaction object.
991
   * @param {string} HTTP request method.
992
   * @param {string} URI for the transaction.
993
   * @param {object} The transaction's callback object.
994
   * @param {object} The JSON object used as HTTP POST data.
995
   * @return {void}
996
    */
997
    function _xdr(o, m, u, c, d) {
998
        _fn[parseInt(o.tId)] = { 'o':o, 'c':c };
999
        if (d) {
1000
            c.method = m;
1001
            c.data = d;
1002
        }
1003

    
1004
        o.conn.send(u, c, o.tId);
1005
    }
1006

    
1007
   /**
1008
   * @description This method instantiates the Flash transport and
1009
    * establishes a static reference to it, used for all XDR requests.
1010
   * @method transport
1011
   * @public
1012
   * @static
1013
   * @param {string} URI to connection.swf.
1014
   * @return {void}
1015
    */
1016
    function _init(uri) {
1017
        _swf(uri);
1018
        YCM._transport = document.getElementById('YUIConnectionSwf');
1019
    }
1020

    
1021
    function _xdrReady() {
1022
        YCM.xdrReadyEvent.fire();
1023
    }
1024

    
1025
   /**
1026
   * @description This method fires the global and transaction start
1027
    * events.
1028
   * @method _xdrStart
1029
   * @private
1030
   * @static
1031
   * @param {object} The transaction object.
1032
   * @param {string} The transaction's callback object.
1033
   * @return {void}
1034
    */
1035
    function _xdrStart(o, cb) {
1036
        if (o) {
1037
            // Fire global custom event -- startEvent
1038
            YCM.startEvent.fire(o, cb.argument);
1039

    
1040
            if(o.startEvent){
1041
                // Fire transaction custom event -- startEvent
1042
                o.startEvent.fire(o, cb.argument);
1043
            }
1044
        }
1045
    }
1046

    
1047
   /**
1048
   * @description This method is the initial response handler
1049
    * for XDR transactions.  The Flash transport calls this
1050
    * function and sends the response payload.
1051
   * @method handleXdrResponse
1052
   * @private
1053
   * @static
1054
   * @param {object} The response object sent from the Flash transport.
1055
   * @return {void}
1056
    */
1057
    function _handleXdrResponse(r) {
1058
        var o = _fn[r.tId].o,
1059
            cb = _fn[r.tId].c;
1060

    
1061
        if (r.statusText === 'xdr:start') {
1062
            _xdrStart(o, cb);
1063
            return;
1064
        }
1065

    
1066
        r.responseText = decodeURI(r.responseText);
1067
        o.r = r;
1068
        if (cb.argument) {
1069
            o.r.argument = cb.argument;
1070
        }
1071

    
1072
        this.handleTransactionResponse(o, cb, r.statusText === 'xdr:abort' ? true : false);
1073
        delete _fn[r.tId];
1074
    }
1075

    
1076
    // Bind the functions to Connection Manager as static fields.
1077
    YCM.xdr = _xdr;
1078
    YCM.swf = _swf;
1079
    YCM.transport = _init;
1080
    YCM.xdrReadyEvent = new YAHOO.util.CustomEvent('xdrReady');
1081
    YCM.xdrReady = _xdrReady;
1082
    YCM.handleXdrResponse = _handleXdrResponse;
1083
})();
1084

    
1085
/**
1086
 * @for Connect
1087
  */
1088
(function(){
1089
    var YCM = YAHOO.util.Connect,
1090
        YE = YAHOO.util.Event;
1091
   /**
1092
    * @description Property modified by setForm() to determine if the data
1093
    * should be submitted as an HTML form.
1094
    * @property _isFormSubmit
1095
    * @private
1096
    * @static
1097
    * @type boolean
1098
    */
1099
    YCM._isFormSubmit = false;
1100

    
1101
   /**
1102
    * @description Property modified by setForm() to determine if a file(s)
1103
    * upload is expected.
1104
    * @property _isFileUpload
1105
    * @private
1106
    * @static
1107
    * @type boolean
1108
    */
1109
    YCM._isFileUpload = false;
1110

    
1111
   /**
1112
    * @description Property modified by setForm() to set a reference to the HTML
1113
    * form node if the desired action is file upload.
1114
    * @property _formNode
1115
    * @private
1116
    * @static
1117
    * @type object
1118
    */
1119
    YCM._formNode = null;
1120

    
1121
   /**
1122
    * @description Property modified by setForm() to set the HTML form data
1123
    * for each transaction.
1124
    * @property _sFormData
1125
    * @private
1126
    * @static
1127
    * @type string
1128
    */
1129
    YCM._sFormData = null;
1130

    
1131
   /**
1132
    * @description Tracks the name-value pair of the "clicked" submit button if multiple submit
1133
    * buttons are present in an HTML form; and, if YAHOO.util.Event is available.
1134
    * @property _submitElementValue
1135
    * @private
1136
    * @static
1137
    * @type string
1138
    */
1139
    YCM._submitElementValue = null;
1140

    
1141
   /**
1142
   * @description Custom event that fires when handleTransactionResponse() determines a
1143
    * response in the HTTP 4xx/5xx range.
1144
   * @property failureEvent
1145
   * @private
1146
   * @static
1147
   * @type CustomEvent
1148
    */
1149
    YCM.uploadEvent = new YAHOO.util.CustomEvent('upload'),
1150

    
1151
   /**
1152
    * @description Determines whether YAHOO.util.Event is available and returns true or false.
1153
    * If true, an event listener is bound at the document level to trap click events that
1154
    * resolve to a target type of "Submit".  This listener will enable setForm() to determine
1155
    * the clicked "Submit" value in a multi-Submit button, HTML form.
1156
    * @property _hasSubmitListener
1157
    * @private
1158
    * @static
1159
    */
1160
    YCM._hasSubmitListener = function() {
1161
        if(YE){
1162
            YE.addListener(
1163
                document,
1164
                'click',
1165
                function(e){
1166
                    var obj = YE.getTarget(e),
1167
                        name = obj.nodeName.toLowerCase();
1168

    
1169
                    if((name === 'input' || name === 'button') && (obj.type && obj.type.toLowerCase() == 'submit')){
1170
                        YCM._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
1171
                    }
1172
                });
1173
            return true;
1174
        }
1175
        return false;
1176
    }();
1177

    
1178
  /**
1179
  * @description This method assembles the form label and value pairs and
1180
   * constructs an encoded string.
1181
   * asyncRequest() will automatically initialize the transaction with a
1182
   * a HTTP header Content-Type of application/x-www-form-urlencoded.
1183
  * @method setForm
1184
  * @public
1185
  * @static
1186
  * @param {string || object} form id or name attribute, or form object.
1187
  * @param {boolean} optional enable file upload.
1188
  * @param {boolean} optional enable file upload over SSL in IE only.
1189
  * @return {string} string of the HTML form field name and value pairs..
1190
   */
1191
    function _setForm(formId, isUpload, secureUri)
1192
    {
1193
        var oForm, oElement, oName, oValue, oDisabled,
1194
            hasSubmit = false,
1195
            data = [], item = 0,
1196
            i,len,j,jlen,opt;
1197

    
1198
        this.resetFormState();
1199

    
1200
        if(typeof formId == 'string'){
1201
            // Determine if the argument is a form id or a form name.
1202
            // Note form name usage is deprecated by supported
1203
            // here for legacy reasons.
1204
            oForm = (document.getElementById(formId) || document.forms[formId]);
1205
        }
1206
        else if(typeof formId == 'object'){
1207
            // Treat argument as an HTML form object.
1208
            oForm = formId;
1209
        }
1210
        else{
1211
            return;
1212
        }
1213

    
1214
        // If the isUpload argument is true, setForm will call createFrame to initialize
1215
        // an iframe as the form target.
1216
        //
1217
        // The argument secureURI is also required by IE in SSL environments
1218
        // where the secureURI string is a fully qualified HTTP path, used to set the source
1219
        // of the iframe, to a stub resource in the same domain.
1220
        if(isUpload){
1221

    
1222
            // Create iframe in preparation for file upload.
1223
            this.createFrame(secureUri?secureUri:null);
1224

    
1225
            // Set form reference and file upload properties to true.
1226
            this._isFormSubmit = true;
1227
            this._isFileUpload = true;
1228
            this._formNode = oForm;
1229

    
1230
            return;
1231
        }
1232

    
1233
        // Iterate over the form elements collection to construct the
1234
        // label-value pairs.
1235
        for (i=0,len=oForm.elements.length; i<len; ++i){
1236
            oElement  = oForm.elements[i];
1237
            oDisabled = oElement.disabled;
1238
            oName     = oElement.name;
1239

    
1240
            // Do not submit fields that are disabled or
1241
            // do not have a name attribute value.
1242
            if(!oDisabled && oName)
1243
            {
1244
                oName  = encodeURIComponent(oName)+'=';
1245
                oValue = encodeURIComponent(oElement.value);
1246

    
1247
                switch(oElement.type)
1248
                {
1249
                    // Safari, Opera, FF all default opt.value from .text if
1250
                    // value attribute not specified in markup
1251
                    case 'select-one':
1252
                        if (oElement.selectedIndex > -1) {
1253
                            opt = oElement.options[oElement.selectedIndex];
1254
                            data[item++] = oName + encodeURIComponent(
1255
                                (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
1256
                        }
1257
                        break;
1258
                    case 'select-multiple':
1259
                        if (oElement.selectedIndex > -1) {
1260
                            for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){
1261
                                opt = oElement.options[j];
1262
                                if (opt.selected) {
1263
                                    data[item++] = oName + encodeURIComponent(
1264
                                        (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
1265
                                }
1266
                            }
1267
                        }
1268
                        break;
1269
                    case 'radio':
1270
                    case 'checkbox':
1271
                        if(oElement.checked){
1272
                            data[item++] = oName + oValue;
1273
                        }
1274
                        break;
1275
                    case 'file':
1276
                        // stub case as XMLHttpRequest will only send the file path as a string.
1277
                    case undefined:
1278
                        // stub case for fieldset element which returns undefined.
1279
                    case 'reset':
1280
                        // stub case for input type reset button.
1281
                    case 'button':
1282
                        // stub case for input type button elements.
1283
                        break;
1284
                    case 'submit':
1285
                        if(hasSubmit === false){
1286
                            if(this._hasSubmitListener && this._submitElementValue){
1287
                                data[item++] = this._submitElementValue;
1288
                            }
1289
                            hasSubmit = true;
1290
                        }
1291
                        break;
1292
                    default:
1293
                        data[item++] = oName + oValue;
1294
                }
1295
            }
1296
        }
1297

    
1298
        this._isFormSubmit = true;
1299
        this._sFormData = data.join('&');
1300

    
1301

    
1302
        this.initHeader('Content-Type', this._default_form_header);
1303

    
1304
        return this._sFormData;
1305
    }
1306

    
1307
   /**
1308
   * @description Resets HTML form properties when an HTML form or HTML form
1309
    * with file upload transaction is sent.
1310
   * @method resetFormState
1311
   * @private
1312
   * @static
1313
   * @return {void}
1314
    */
1315
    function _resetFormState(){
1316
        this._isFormSubmit = false;
1317
        this._isFileUpload = false;
1318
        this._formNode = null;
1319
        this._sFormData = "";
1320
    }
1321

    
1322

    
1323
   /**
1324
   * @description Creates an iframe to be used for form file uploads.  It is remove from the
1325
    * document upon completion of the upload transaction.
1326
   * @method createFrame
1327
   * @private
1328
   * @static
1329
   * @param {string} optional qualified path of iframe resource for SSL in IE.
1330
   * @return {void}
1331
    */
1332
    function _createFrame(secureUri){
1333

    
1334
        // IE does not allow the setting of id and name attributes as object
1335
        // properties via createElement().  A different iframe creation
1336
        // pattern is required for IE.
1337
        var frameId = 'yuiIO' + this._transaction_id,
1338
            io;
1339
        if(YAHOO.env.ua.ie){
1340
            io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
1341

    
1342
            // IE will throw a security exception in an SSL environment if the
1343
            // iframe source is undefined.
1344
            if(typeof secureUri == 'boolean'){
1345
                io.src = 'javascript:false';
1346
            }
1347
        }
1348
        else{
1349
            io = document.createElement('iframe');
1350
            io.id = frameId;
1351
            io.name = frameId;
1352
        }
1353

    
1354
        io.style.position = 'absolute';
1355
        io.style.top = '-1000px';
1356
        io.style.left = '-1000px';
1357

    
1358
        document.body.appendChild(io);
1359
    }
1360

    
1361
   /**
1362
   * @description Parses the POST data and creates hidden form elements
1363
    * for each key-value, and appends them to the HTML form object.
1364
   * @method appendPostData
1365
   * @private
1366
   * @static
1367
   * @param {string} postData The HTTP POST data
1368
   * @return {array} formElements Collection of hidden fields.
1369
    */
1370
    function _appendPostData(postData){
1371
        var formElements = [],
1372
            postMessage = postData.split('&'),
1373
            i, delimitPos;
1374

    
1375
        for(i=0; i < postMessage.length; i++){
1376
            delimitPos = postMessage[i].indexOf('=');
1377
            if(delimitPos != -1){
1378
                formElements[i] = document.createElement('input');
1379
                formElements[i].type = 'hidden';
1380
                formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos));
1381
                formElements[i].value = decodeURIComponent(postMessage[i].substring(delimitPos+1));
1382
                this._formNode.appendChild(formElements[i]);
1383
            }
1384
        }
1385

    
1386
        return formElements;
1387
    }
1388

    
1389
   /**
1390
   * @description Uploads HTML form, inclusive of files/attachments, using the
1391
    * iframe created in createFrame to facilitate the transaction.
1392
   * @method uploadFile
1393
   * @private
1394
   * @static
1395
   * @param {int} id The transaction id.
1396
   * @param {object} callback User-defined callback object.
1397
   * @param {string} uri Fully qualified path of resource.
1398
   * @param {string} postData POST data to be submitted in addition to HTML form.
1399
   * @return {void}
1400
    */
1401
    function _uploadFile(o, callback, uri, postData){
1402
        // Each iframe has an id prefix of "yuiIO" followed
1403
        // by the unique transaction id.
1404
        var frameId = 'yuiIO' + o.tId,
1405
            uploadEncoding = 'multipart/form-data',
1406
            io = document.getElementById(frameId),
1407
            ie8 = (document.documentMode && document.documentMode === 8) ? true : false,
1408
            oConn = this,
1409
            args = (callback && callback.argument)?callback.argument:null,
1410
            oElements,i,prop,obj, rawFormAttributes, uploadCallback;
1411

    
1412
        // Track original HTML form attribute values.
1413
        rawFormAttributes = {
1414
            action:this._formNode.getAttribute('action'),
1415
            method:this._formNode.getAttribute('method'),
1416
            target:this._formNode.getAttribute('target')
1417
        };
1418

    
1419
        // Initialize the HTML form properties in case they are
1420
        // not defined in the HTML form.
1421
        this._formNode.setAttribute('action', uri);
1422
        this._formNode.setAttribute('method', 'POST');
1423
        this._formNode.setAttribute('target', frameId);
1424

    
1425
        if(YAHOO.env.ua.ie && !ie8){
1426
            // IE does not respect property enctype for HTML forms.
1427
            // Instead it uses the property - "encoding".
1428
            this._formNode.setAttribute('encoding', uploadEncoding);
1429
        }
1430
        else{
1431
            this._formNode.setAttribute('enctype', uploadEncoding);
1432
        }
1433

    
1434
        if(postData){
1435
            oElements = this.appendPostData(postData);
1436
        }
1437

    
1438
        // Start file upload.
1439
        this._formNode.submit();
1440

    
1441
        // Fire global custom event -- startEvent
1442
        this.startEvent.fire(o, args);
1443

    
1444
        if(o.startEvent){
1445
            // Fire transaction custom event -- startEvent
1446
            o.startEvent.fire(o, args);
1447
        }
1448

    
1449
        // Start polling if a callback is present and the timeout
1450
        // property has been defined.
1451
        if(callback && callback.timeout){
1452
            this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
1453
        }
1454

    
1455
        // Remove HTML elements created by appendPostData
1456
        if(oElements && oElements.length > 0){
1457
            for(i=0; i < oElements.length; i++){
1458
                this._formNode.removeChild(oElements[i]);
1459
            }
1460
        }
1461

    
1462
        // Restore HTML form attributes to their original
1463
        // values prior to file upload.
1464
        for(prop in rawFormAttributes){
1465
            if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){
1466
                if(rawFormAttributes[prop]){
1467
                    this._formNode.setAttribute(prop, rawFormAttributes[prop]);
1468
                }
1469
                else{
1470
                    this._formNode.removeAttribute(prop);
1471
                }
1472
            }
1473
        }
1474

    
1475
        // Reset HTML form state properties.
1476
        this.resetFormState();
1477

    
1478
        // Create the upload callback handler that fires when the iframe
1479
        // receives the load event.  Subsequently, the event handler is detached
1480
        // and the iframe removed from the document.
1481
        uploadCallback = function() {
1482
            if(callback && callback.timeout){
1483
                window.clearTimeout(oConn._timeOut[o.tId]);
1484
                delete oConn._timeOut[o.tId];
1485
            }
1486

    
1487
            // Fire global custom event -- completeEvent
1488
            oConn.completeEvent.fire(o, args);
1489

    
1490
            if(o.completeEvent){
1491
                // Fire transaction custom event -- completeEvent
1492
                o.completeEvent.fire(o, args);
1493
            }
1494

    
1495
            obj = {
1496
                tId : o.tId,
1497
                argument : callback.argument
1498
            };
1499

    
1500
            try
1501
            {
1502
                // responseText and responseXML will be populated with the same data from the iframe.
1503
                // Since the HTTP headers cannot be read from the iframe
1504
                obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent;
1505
                obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
1506
            }
1507
            catch(e){}
1508

    
1509
            if(callback && callback.upload){
1510
                if(!callback.scope){
1511
                    callback.upload(obj);
1512
                }
1513
                else{
1514
                    callback.upload.apply(callback.scope, [obj]);
1515
                }
1516
            }
1517

    
1518
            // Fire global custom event -- uploadEvent
1519
            oConn.uploadEvent.fire(obj);
1520

    
1521
            if(o.uploadEvent){
1522
                // Fire transaction custom event -- uploadEvent
1523
                o.uploadEvent.fire(obj);
1524
            }
1525

    
1526
            YE.removeListener(io, "load", uploadCallback);
1527

    
1528
            setTimeout(
1529
                function(){
1530
                    document.body.removeChild(io);
1531
                    oConn.releaseObject(o);
1532
                }, 100);
1533
        };
1534

    
1535
        // Bind the onload handler to the iframe to detect the file upload response.
1536
        YE.addListener(io, "load", uploadCallback);
1537
    }
1538

    
1539
    YCM.setForm = _setForm;
1540
    YCM.resetFormState = _resetFormState;
1541
    YCM.createFrame = _createFrame;
1542
    YCM.appendPostData = _appendPostData;
1543
    YCM.uploadFile = _uploadFile;
1544
})();
1545

    
1546
YAHOO.register("connection", YAHOO.util.Connect, {version: "2.8.0r4", build: "2449"});
(4-4/9)