~bac/juju-gui/trunkcopy

« back to all changes in this revision

Viewing changes to lib/yui/build/io-base/io-base.js

  • Committer: kapil.foss at gmail
  • Date: 2012-07-13 18:45:59 UTC
  • Revision ID: kapil.foss@gmail.com-20120713184559-2xl7be17egsrz0c9
reshape

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
YUI 3.5.1 (build 22)
3
 
Copyright 2012 Yahoo! Inc. All rights reserved.
4
 
Licensed under the BSD License.
5
 
http://yuilibrary.com/license/
6
 
*/
7
 
YUI.add('io-base', function(Y) {
8
 
 
9
 
/**
10
 
Base IO functionality. Provides basic XHR transport support.
11
 
@module io-base
12
 
@main io-base
13
 
@for IO
14
 
**/
15
 
 
16
 
var // List of events that comprise the IO event lifecycle.
17
 
    EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'],
18
 
 
19
 
    // Whitelist of used XHR response object properties.
20
 
    XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'],
21
 
 
22
 
    win = Y.config.win,
23
 
    uid = 0;
24
 
 
25
 
/**
26
 
The IO class is a utility that brokers HTTP requests through a simplified
27
 
interface.  Specifically, it allows JavaScript to make HTTP requests to
28
 
a resource without a page reload.  The underlying transport for making
29
 
same-domain requests is the XMLHttpRequest object.  IO can also use
30
 
Flash, if specified as a transport, for cross-domain requests.
31
 
 
32
 
@class IO
33
 
@constructor
34
 
@param {Object} config Object of EventTarget's publish method configurations
35
 
                    used to configure IO's events.
36
 
**/
37
 
function IO (config) {
38
 
    var io = this;
39
 
 
40
 
    io._uid = 'io:' + uid++;
41
 
    io._init(config);
42
 
    Y.io._map[io._uid] = io;
43
 
}
44
 
 
45
 
IO.prototype = {
46
 
    //--------------------------------------
47
 
    //  Properties
48
 
    //--------------------------------------
49
 
 
50
 
   /**
51
 
    * A counter that increments for each transaction.
52
 
    *
53
 
    * @property _id
54
 
    * @private
55
 
    * @type {Number}
56
 
    */
57
 
    _id: 0,
58
 
 
59
 
   /**
60
 
    * Object of IO HTTP headers sent with each transaction.
61
 
    *
62
 
    * @property _headers
63
 
    * @private
64
 
    * @type {Object}
65
 
    */
66
 
    _headers: {
67
 
        'X-Requested-With' : 'XMLHttpRequest'
68
 
    },
69
 
 
70
 
   /**
71
 
    * Object that stores timeout values for any transaction with a defined
72
 
    * "timeout" configuration property.
73
 
    *
74
 
    * @property _timeout
75
 
    * @private
76
 
    * @type {Object}
77
 
    */
78
 
    _timeout: {},
79
 
 
80
 
    //--------------------------------------
81
 
    //  Methods
82
 
    //--------------------------------------
83
 
 
84
 
    _init: function(config) {
85
 
        var io = this, i, len;
86
 
 
87
 
        io.cfg = config || {};
88
 
 
89
 
        Y.augment(io, Y.EventTarget);
90
 
        for (i = 0, len = EVENTS.length; i < len; ++i) {
91
 
            // Publish IO global events with configurations, if any.
92
 
            // IO global events are set to broadcast by default.
93
 
            // These events use the "io:" namespace.
94
 
            io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config));
95
 
            // Publish IO transaction events with configurations, if
96
 
            // any.  These events use the "io-trn:" namespace.
97
 
            io.publish('io-trn:' + EVENTS[i], config);
98
 
        }
99
 
    },
100
 
 
101
 
   /**
102
 
    * Method that creates a unique transaction object for each request.
103
 
    *
104
 
    * @method _create
105
 
    * @private
106
 
    * @param {Object} cfg Configuration object subset to determine if
107
 
    *                 the transaction is an XDR or file upload,
108
 
    *                 requiring an alternate transport.
109
 
    * @param {Number} id Transaction id
110
 
    * @return {Object} The transaction object
111
 
    */
112
 
    _create: function(config, id) {
113
 
        var io = this,
114
 
            transaction = {
115
 
                id : Y.Lang.isNumber(id) ? id : io._id++,
116
 
                uid: io._uid
117
 
            },
118
 
            alt = config.xdr ? config.xdr.use : null,
119
 
            form = config.form && config.form.upload ? 'iframe' : null,
120
 
            use;
121
 
 
122
 
        if (alt === 'native') {
123
 
            // Non-IE  can use XHR level 2 and not rely on an
124
 
            // external transport.
125
 
            alt = Y.UA.ie ? 'xdr' : null;
126
 
        }
127
 
 
128
 
        use = alt || form;
129
 
        transaction = use ? Y.merge(Y.IO.customTransport(use), transaction) :
130
 
                            Y.merge(Y.IO.defaultTransport(), transaction);
131
 
 
132
 
        if (transaction.notify) {
133
 
            config.notify = function (e, t, c) { io.notify(e, t, c); };
134
 
        }
135
 
 
136
 
        if (!use) {
137
 
            if (win && win.FormData && config.data instanceof FormData) {
138
 
                transaction.c.upload.onprogress = function (e) {
139
 
                    io.progress(transaction, e, config);
140
 
                };
141
 
                transaction.c.onload = function (e) {
142
 
                    io.load(transaction, e, config);
143
 
                };
144
 
                transaction.c.onerror = function (e) {
145
 
                    io.error(transaction, e, config);
146
 
                };
147
 
                transaction.upload = true;
148
 
            }
149
 
        }
150
 
 
151
 
        return transaction;
152
 
    },
153
 
 
154
 
    _destroy: function(transaction) {
155
 
        if (win && !transaction.notify && !transaction.xdr) {
156
 
            if (XHR && !transaction.upload) {
157
 
                transaction.c.onreadystatechange = null;
158
 
            } else if (transaction.upload) {
159
 
                transaction.c.upload.onprogress = null;
160
 
                transaction.c.onload = null;
161
 
                transaction.c.onerror = null;
162
 
            } else if (Y.UA.ie && !transaction.e) {
163
 
                // IE, when using XMLHttpRequest as an ActiveX Object, will throw
164
 
                // a "Type Mismatch" error if the event handler is set to "null".
165
 
                transaction.c.abort();
166
 
            }
167
 
        }
168
 
 
169
 
        transaction = transaction.c = null;
170
 
    },
171
 
 
172
 
   /**
173
 
    * Method for creating and firing events.
174
 
    *
175
 
    * @method _evt
176
 
    * @private
177
 
    * @param {String} eventName Event to be published.
178
 
    * @param {Object} transaction Transaction object.
179
 
    * @param {Object} config Configuration data subset for event subscription.
180
 
    */
181
 
    _evt: function(eventName, transaction, config) {
182
 
        var io          = this, params,
183
 
            args        = config['arguments'],
184
 
            emitFacade  = io.cfg.emitFacade,
185
 
            globalEvent = "io:" + eventName,
186
 
            trnEvent    = "io-trn:" + eventName;
187
 
 
188
 
        // Workaround for #2532107
189
 
        this.detach(trnEvent);
190
 
 
191
 
        if (transaction.e) {
192
 
            transaction.c = { status: 0, statusText: transaction.e };
193
 
        }
194
 
 
195
 
        // Fire event with parameters or an Event Facade.
196
 
        params = [ emitFacade ?
197
 
            {
198
 
                id: transaction.id,
199
 
                data: transaction.c,
200
 
                cfg: config,
201
 
                'arguments': args
202
 
            } :
203
 
            transaction.id
204
 
        ];
205
 
 
206
 
        if (!emitFacade) {
207
 
            if (eventName === EVENTS[0] || eventName === EVENTS[2]) {
208
 
                if (args) {
209
 
                    params.push(args);
210
 
                }
211
 
            } else {
212
 
                if (transaction.evt) {
213
 
                    params.push(transaction.evt);
214
 
                } else {
215
 
                    params.push(transaction.c);
216
 
                }
217
 
                if (args) {
218
 
                    params.push(args);
219
 
                }
220
 
            }
221
 
        }
222
 
 
223
 
        params.unshift(globalEvent);
224
 
        // Fire global events.
225
 
        io.fire.apply(io, params);
226
 
        // Fire transaction events, if receivers are defined.
227
 
        if (config.on) {
228
 
            params[0] = trnEvent;
229
 
            io.once(trnEvent, config.on[eventName], config.context || Y);
230
 
            io.fire.apply(io, params);
231
 
        }
232
 
    },
233
 
 
234
 
   /**
235
 
    * Fires event "io:start" and creates, fires a transaction-specific
236
 
    * start event, if `config.on.start` is defined.
237
 
    *
238
 
    * @method start
239
 
    * @param {Object} transaction Transaction object.
240
 
    * @param {Object} config Configuration object for the transaction.
241
 
    */
242
 
    start: function(transaction, config) {
243
 
       /**
244
 
        * Signals the start of an IO request.
245
 
        * @event io:start
246
 
        */
247
 
        this._evt(EVENTS[0], transaction, config);
248
 
    },
249
 
 
250
 
   /**
251
 
    * Fires event "io:complete" and creates, fires a
252
 
    * transaction-specific "complete" event, if config.on.complete is
253
 
    * defined.
254
 
    *
255
 
    * @method complete
256
 
    * @param {Object} transaction Transaction object.
257
 
    * @param {Object} config Configuration object for the transaction.
258
 
    */
259
 
    complete: function(transaction, config) {
260
 
       /**
261
 
        * Signals the completion of the request-response phase of a
262
 
        * transaction. Response status and data are accessible, if
263
 
        * available, in this event.
264
 
        * @event io:complete
265
 
        */
266
 
        this._evt(EVENTS[1], transaction, config);
267
 
    },
268
 
 
269
 
   /**
270
 
    * Fires event "io:end" and creates, fires a transaction-specific "end"
271
 
    * event, if config.on.end is defined.
272
 
    *
273
 
    * @method end
274
 
    * @param {Object} transaction Transaction object.
275
 
    * @param {Object} config Configuration object for the transaction.
276
 
    */
277
 
    end: function(transaction, config) {
278
 
       /**
279
 
        * Signals the end of the transaction lifecycle.
280
 
        * @event io:end
281
 
        */
282
 
        this._evt(EVENTS[2], transaction, config);
283
 
        this._destroy(transaction);
284
 
    },
285
 
 
286
 
   /**
287
 
    * Fires event "io:success" and creates, fires a transaction-specific
288
 
    * "success" event, if config.on.success is defined.
289
 
    *
290
 
    * @method success
291
 
    * @param {Object} transaction Transaction object.
292
 
    * @param {Object} config Configuration object for the transaction.
293
 
    */
294
 
    success: function(transaction, config) {
295
 
       /**
296
 
        * Signals an HTTP response with status in the 2xx range.
297
 
        * Fires after io:complete.
298
 
        * @event io:success
299
 
        */
300
 
        this._evt(EVENTS[3], transaction, config);
301
 
        this.end(transaction, config);
302
 
    },
303
 
 
304
 
   /**
305
 
    * Fires event "io:failure" and creates, fires a transaction-specific
306
 
    * "failure" event, if config.on.failure is defined.
307
 
    *
308
 
    * @method failure
309
 
    * @param {Object} transaction Transaction object.
310
 
    * @param {Object} config Configuration object for the transaction.
311
 
    */
312
 
    failure: function(transaction, config) {
313
 
       /**
314
 
        * Signals an HTTP response with status outside of the 2xx range.
315
 
        * Fires after io:complete.
316
 
        * @event io:failure
317
 
        */
318
 
        this._evt(EVENTS[4], transaction, config);
319
 
        this.end(transaction, config);
320
 
    },
321
 
 
322
 
   /**
323
 
    * Fires event "io:progress" and creates, fires a transaction-specific
324
 
    * "progress" event -- for XMLHttpRequest file upload -- if
325
 
    * config.on.progress is defined.
326
 
    *
327
 
    * @method progress
328
 
    * @param {Object} transaction Transaction object.
329
 
    * @param {Object} progress event.
330
 
    * @param {Object} config Configuration object for the transaction.
331
 
    */
332
 
    progress: function(transaction, e, config) {
333
 
       /**
334
 
        * Signals the interactive state during a file upload transaction.
335
 
        * This event fires after io:start and before io:complete.
336
 
        * @event io:progress
337
 
        */
338
 
        transaction.evt = e;
339
 
        this._evt(EVENTS[5], transaction, config);
340
 
    },
341
 
 
342
 
   /**
343
 
    * Fires event "io:complete" and creates, fires a transaction-specific
344
 
    * "complete" event -- for XMLHttpRequest file upload -- if
345
 
    * config.on.complete is defined.
346
 
    *
347
 
    * @method load
348
 
    * @param {Object} transaction Transaction object.
349
 
    * @param {Object} load event.
350
 
    * @param {Object} config Configuration object for the transaction.
351
 
    */
352
 
    load: function (transaction, e, config) {
353
 
        transaction.evt = e.target;
354
 
        this._evt(EVENTS[1], transaction, config);
355
 
    },
356
 
 
357
 
   /**
358
 
    * Fires event "io:failure" and creates, fires a transaction-specific
359
 
    * "failure" event -- for XMLHttpRequest file upload -- if
360
 
    * config.on.failure is defined.
361
 
    *
362
 
    * @method error
363
 
    * @param {Object} transaction Transaction object.
364
 
    * @param {Object} error event.
365
 
    * @param {Object} config Configuration object for the transaction.
366
 
    */
367
 
    error: function (transaction, e, config) {
368
 
        transaction.evt = e;
369
 
        this._evt(EVENTS[4], transaction, config);
370
 
    },
371
 
 
372
 
   /**
373
 
    * Retry an XDR transaction, using the Flash tranport, if the native
374
 
    * transport fails.
375
 
    *
376
 
    * @method _retry
377
 
    * @private
378
 
    * @param {Object} transaction Transaction object.
379
 
    * @param {String} uri Qualified path to transaction resource.
380
 
    * @param {Object} config Configuration object for the transaction.
381
 
    */
382
 
    _retry: function(transaction, uri, config) {
383
 
        this._destroy(transaction);
384
 
        config.xdr.use = 'flash';
385
 
        return this.send(uri, config, transaction.id);
386
 
    },
387
 
 
388
 
   /**
389
 
    * Method that concatenates string data for HTTP GET transactions.
390
 
    *
391
 
    * @method _concat
392
 
    * @private
393
 
    * @param {String} uri URI or root data.
394
 
    * @param {String} data Data to be concatenated onto URI.
395
 
    * @return {String}
396
 
    */
397
 
    _concat: function(uri, data) {
398
 
        uri += (uri.indexOf('?') === -1 ? '?' : '&') + data;
399
 
        return uri;
400
 
    },
401
 
 
402
 
   /**
403
 
    * Stores default client headers for all transactions. If a label is
404
 
    * passed with no value argument, the header will be deleted.
405
 
    *
406
 
    * @method setHeader
407
 
    * @param {String} name HTTP header
408
 
    * @param {String} value HTTP header value
409
 
    */
410
 
    setHeader: function(name, value) {
411
 
        if (value) {
412
 
            this._headers[name] = value;
413
 
        } else {
414
 
            delete this._headers[name];
415
 
        }
416
 
    },
417
 
 
418
 
   /**
419
 
    * Method that sets all HTTP headers to be sent in a transaction.
420
 
    *
421
 
    * @method _setHeaders
422
 
    * @private
423
 
    * @param {Object} transaction - XHR instance for the specific transaction.
424
 
    * @param {Object} headers - HTTP headers for the specific transaction, as
425
 
    *                    defined in the configuration object passed to YUI.io().
426
 
    */
427
 
    _setHeaders: function(transaction, headers) {
428
 
        headers = Y.merge(this._headers, headers);
429
 
        Y.Object.each(headers, function(value, name) {
430
 
            if (value !== 'disable') {
431
 
                transaction.setRequestHeader(name, headers[name]);
432
 
            }
433
 
        });
434
 
    },
435
 
 
436
 
   /**
437
 
    * Starts timeout count if the configuration object has a defined
438
 
    * timeout property.
439
 
    *
440
 
    * @method _startTimeout
441
 
    * @private
442
 
    * @param {Object} transaction Transaction object generated by _create().
443
 
    * @param {Object} timeout Timeout in milliseconds.
444
 
    */
445
 
    _startTimeout: function(transaction, timeout) {
446
 
        var io = this;
447
 
 
448
 
        io._timeout[transaction.id] = setTimeout(function() {
449
 
            io._abort(transaction, 'timeout');
450
 
        }, timeout);
451
 
    },
452
 
 
453
 
   /**
454
 
    * Clears the timeout interval started by _startTimeout().
455
 
    *
456
 
    * @method _clearTimeout
457
 
    * @private
458
 
    * @param {Number} id - Transaction id.
459
 
    */
460
 
    _clearTimeout: function(id) {
461
 
        clearTimeout(this._timeout[id]);
462
 
        delete this._timeout[id];
463
 
    },
464
 
 
465
 
   /**
466
 
    * Method that determines if a transaction response qualifies as success
467
 
    * or failure, based on the response HTTP status code, and fires the
468
 
    * appropriate success or failure events.
469
 
    *
470
 
    * @method _result
471
 
    * @private
472
 
    * @static
473
 
    * @param {Object} transaction Transaction object generated by _create().
474
 
    * @param {Object} config Configuration object passed to io().
475
 
    */
476
 
    _result: function(transaction, config) {
477
 
        var status;
478
 
        // Firefox will throw an exception if attempting to access
479
 
        // an XHR object's status property, after a request is aborted.
480
 
        try {
481
 
            status = transaction.c.status;
482
 
        } catch(e) {
483
 
            status = 0;
484
 
        }
485
 
 
486
 
        // IE reports HTTP 204 as HTTP 1223.
487
 
        if (status >= 200 && status < 300 || status === 304 || status === 1223) {
488
 
            this.success(transaction, config);
489
 
        } else {
490
 
            this.failure(transaction, config);
491
 
        }
492
 
    },
493
 
 
494
 
   /**
495
 
    * Event handler bound to onreadystatechange.
496
 
    *
497
 
    * @method _rS
498
 
    * @private
499
 
    * @param {Object} transaction Transaction object generated by _create().
500
 
    * @param {Object} config Configuration object passed to YUI.io().
501
 
    */
502
 
    _rS: function(transaction, config) {
503
 
        var io = this;
504
 
 
505
 
        if (transaction.c.readyState === 4) {
506
 
            if (config.timeout) {
507
 
                io._clearTimeout(transaction.id);
508
 
            }
509
 
 
510
 
            // Yield in the event of request timeout or abort.
511
 
            setTimeout(function() {
512
 
                io.complete(transaction, config);
513
 
                io._result(transaction, config);
514
 
            }, 0);
515
 
        }
516
 
    },
517
 
 
518
 
   /**
519
 
    * Terminates a transaction due to an explicit abort or timeout.
520
 
    *
521
 
    * @method _abort
522
 
    * @private
523
 
    * @param {Object} transaction Transaction object generated by _create().
524
 
    * @param {String} type Identifies timed out or aborted transaction.
525
 
    */
526
 
    _abort: function(transaction, type) {
527
 
        if (transaction && transaction.c) {
528
 
            transaction.e = type;
529
 
            transaction.c.abort();
530
 
        }
531
 
    },
532
 
 
533
 
   /**
534
 
    * Requests a transaction. `send()` is implemented as `Y.io()`.  Each
535
 
    * transaction may include a configuration object.  Its properties are:
536
 
    *
537
 
    * <dl>
538
 
    *   <dt>method</dt>
539
 
    *     <dd>HTTP method verb (e.g., GET or POST). If this property is not
540
 
    *         not defined, the default value will be GET.</dd>
541
 
    *
542
 
    *   <dt>data</dt>
543
 
    *     <dd>This is the name-value string that will be sent as the
544
 
    *     transaction data. If the request is HTTP GET, the data become
545
 
    *     part of querystring. If HTTP POST, the data are sent in the
546
 
    *     message body.</dd>
547
 
    *
548
 
    *   <dt>xdr</dt>
549
 
    *     <dd>Defines the transport to be used for cross-domain requests.
550
 
    *     By setting this property, the transaction will use the specified
551
 
    *     transport instead of XMLHttpRequest. The properties of the
552
 
    *     transport object are:
553
 
    *     <dl>
554
 
    *       <dt>use</dt>
555
 
    *         <dd>The transport to be used: 'flash' or 'native'</dd>
556
 
    *       <dt>dataType</dt>
557
 
    *         <dd>Set the value to 'XML' if that is the expected response
558
 
    *         content type.</dd>
559
 
    *     </dl></dd>
560
 
    *
561
 
    *   <dt>form</dt>
562
 
    *     <dd>Form serialization configuration object.  Its properties are:
563
 
    *     <dl>
564
 
    *       <dt>id</dt>
565
 
    *         <dd>Node object or id of HTML form</dd>
566
 
    *       <dt>useDisabled</dt>
567
 
    *         <dd>`true` to also serialize disabled form field values
568
 
    *         (defaults to `false`)</dd>
569
 
    *     </dl></dd>
570
 
    *
571
 
    *   <dt>on</dt>
572
 
    *     <dd>Assigns transaction event subscriptions. Available events are:
573
 
    *     <dl>
574
 
    *       <dt>start</dt>
575
 
    *         <dd>Fires when a request is sent to a resource.</dd>
576
 
    *       <dt>complete</dt>
577
 
    *         <dd>Fires when the transaction is complete.</dd>
578
 
    *       <dt>success</dt>
579
 
    *         <dd>Fires when the HTTP response status is within the 2xx
580
 
    *         range.</dd>
581
 
    *       <dt>failure</dt>
582
 
    *         <dd>Fires when the HTTP response status is outside the 2xx
583
 
    *         range, if an exception occurs, if the transation is aborted,
584
 
    *         or if the transaction exceeds a configured `timeout`.</dd>
585
 
    *       <dt>end</dt>
586
 
    *         <dd>Fires at the conclusion of the transaction
587
 
    *            lifecycle, after `success` or `failure`.</dd>
588
 
    *     </dl>
589
 
    *
590
 
    *     <p>Callback functions for `start` and `end` receive the id of the
591
 
    *     transaction as a first argument. For `complete`, `success`, and
592
 
    *     `failure`, callbacks receive the id and the response object
593
 
    *     (usually the XMLHttpRequest instance).  If the `arguments`
594
 
    *     property was included in the configuration object passed to
595
 
    *     `Y.io()`, the configured data will be passed to all callbacks as
596
 
    *     the last argument.</p>
597
 
    *     </dd>
598
 
    *
599
 
    *   <dt>sync</dt>
600
 
    *     <dd>Pass `true` to make a same-domain transaction synchronous.
601
 
    *     <strong>CAVEAT</strong>: This will negatively impact the user
602
 
    *     experience. Have a <em>very</em> good reason if you intend to use
603
 
    *     this.</dd>
604
 
    *
605
 
    *   <dt>context</dt>
606
 
    *     <dd>The "`this'" object for all configured event handlers. If a
607
 
    *     specific context is needed for individual callbacks, bind the
608
 
    *     callback to a context using `Y.bind()`.</dd>
609
 
    *
610
 
    *   <dt>headers</dt>
611
 
    *     <dd>Object map of transaction headers to send to the server. The
612
 
    *     object keys are the header names and the values are the header
613
 
    *     values.</dd>
614
 
    *
615
 
    *   <dt>timeout</dt>
616
 
    *     <dd>Millisecond threshold for the transaction before being
617
 
    *     automatically aborted.</dd>
618
 
    *
619
 
    *   <dt>arguments</dt>
620
 
    *     <dd>User-defined data passed to all registered event handlers.
621
 
    *     This value is available as the second argument in the "start" and
622
 
    *     "end" event handlers. It is the third argument in the "complete",
623
 
    *     "success", and "failure" event handlers. <strong>Be sure to quote
624
 
    *     this property name in the transaction configuration as
625
 
    *     "arguments" is a reserved word in JavaScript</strong> (e.g.
626
 
    *     `Y.io({ ..., "arguments": stuff })`).</dd>
627
 
    * </dl>
628
 
    *
629
 
    * @method send
630
 
    * @public
631
 
    * @param {String} uri Qualified path to transaction resource.
632
 
    * @param {Object} config Configuration object for the transaction.
633
 
    * @param {Number} id Transaction id, if already set.
634
 
    * @return {Object}
635
 
    */
636
 
    send: function(uri, config, id) {
637
 
        var transaction, method, i, len, sync, data,
638
 
            io = this,
639
 
            u = uri,
640
 
            response = {};
641
 
 
642
 
        config = config ? Y.Object(config) : {};
643
 
        transaction = io._create(config, id);
644
 
        method = config.method ? config.method.toUpperCase() : 'GET';
645
 
        sync = config.sync;
646
 
        data = config.data;
647
 
 
648
 
        // Serialize an map object into a key-value string using
649
 
        // querystring-stringify-simple.
650
 
        if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) {
651
 
            data = Y.QueryString.stringify(data);
652
 
        }
653
 
 
654
 
        if (config.form) {
655
 
            if (config.form.upload) {
656
 
                // This is a file upload transaction, calling
657
 
                // upload() in io-upload-iframe.
658
 
                return io.upload(transaction, uri, config);
659
 
            } else {
660
 
                // Serialize HTML form data into a key-value string.
661
 
                data = io._serialize(config.form, data);
662
 
            }
663
 
        }
664
 
 
665
 
        if (data) {
666
 
            switch (method) {
667
 
                case 'GET':
668
 
                case 'HEAD':
669
 
                case 'DELETE':
670
 
                    u = io._concat(u, data);
671
 
                    data = '';
672
 
                    break;
673
 
                case 'POST':
674
 
                case 'PUT':
675
 
                    // If Content-Type is defined in the configuration object, or
676
 
                    // or as a default header, it will be used instead of
677
 
                    // 'application/x-www-form-urlencoded; charset=UTF-8'
678
 
                    config.headers = Y.merge({
679
 
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
680
 
                    }, config.headers);
681
 
                    break;
682
 
            }
683
 
        }
684
 
 
685
 
        if (transaction.xdr) {
686
 
            // Route data to io-xdr module for flash and XDomainRequest.
687
 
            return io.xdr(u, transaction, config);
688
 
        }
689
 
        else if (transaction.notify) {
690
 
            // Route data to custom transport
691
 
            return transaction.c.send(transaction, uri, config);
692
 
        }
693
 
 
694
 
        if (!sync && !transaction.upload) {
695
 
            transaction.c.onreadystatechange = function() {
696
 
                io._rS(transaction, config);
697
 
            };
698
 
        }
699
 
 
700
 
        try {
701
 
            // Determine if request is to be set as
702
 
            // synchronous or asynchronous.
703
 
            transaction.c.open(method, u, !sync, config.username || null, config.password || null);
704
 
            io._setHeaders(transaction.c, config.headers || {});
705
 
            io.start(transaction, config);
706
 
 
707
 
            // Will work only in browsers that implement the
708
 
            // Cross-Origin Resource Sharing draft.
709
 
            if (config.xdr && config.xdr.credentials) {
710
 
                if (!Y.UA.ie) {
711
 
                    transaction.c.withCredentials = true;
712
 
                }
713
 
            }
714
 
 
715
 
            // Using "null" with HTTP POST will result in a request
716
 
            // with no Content-Length header defined.
717
 
            transaction.c.send(data);
718
 
 
719
 
            if (sync) {
720
 
                // Create a response object for synchronous transactions,
721
 
                // mixing id and arguments properties with the xhr
722
 
                // properties whitelist.
723
 
                for (i = 0, len = XHR_PROPS.length; i < len; ++i) {
724
 
                    response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]];
725
 
                }
726
 
 
727
 
                response.getAllResponseHeaders = function() {
728
 
                    return transaction.c.getAllResponseHeaders();
729
 
                };
730
 
 
731
 
                response.getResponseHeader = function(name) {
732
 
                    return transaction.c.getResponseHeader(name);
733
 
                };
734
 
 
735
 
                io.complete(transaction, config);
736
 
                io._result(transaction, config);
737
 
 
738
 
                return response;
739
 
            }
740
 
        } catch(e) {
741
 
            if (transaction.xdr) {
742
 
                // This exception is usually thrown by browsers
743
 
                // that do not support XMLHttpRequest Level 2.
744
 
                // Retry the request with the XDR transport set
745
 
                // to 'flash'.  If the Flash transport is not
746
 
                // initialized or available, the transaction
747
 
                // will resolve to a transport error.
748
 
                return io._retry(transaction, uri, config);
749
 
            } else {
750
 
                io.complete(transaction, config);
751
 
                io._result(transaction, config);
752
 
            }
753
 
        }
754
 
 
755
 
        // If config.timeout is defined, and the request is standard XHR,
756
 
        // initialize timeout polling.
757
 
        if (config.timeout) {
758
 
            io._startTimeout(transaction, config.timeout);
759
 
        }
760
 
 
761
 
        return {
762
 
            id: transaction.id,
763
 
            abort: function() {
764
 
                return transaction.c ? io._abort(transaction, 'abort') : false;
765
 
            },
766
 
            isInProgress: function() {
767
 
                return transaction.c ? (transaction.c.readyState % 4) : false;
768
 
            },
769
 
            io: io
770
 
        };
771
 
    }
772
 
};
773
 
 
774
 
/**
775
 
Method for initiating an ajax call.  The first argument is the url end
776
 
point for the call.  The second argument is an object to configure the
777
 
transaction and attach event subscriptions.  The configuration object
778
 
supports the following properties:
779
 
 
780
 
<dl>
781
 
  <dt>method</dt>
782
 
    <dd>HTTP method verb (e.g., GET or POST). If this property is not
783
 
        not defined, the default value will be GET.</dd>
784
 
 
785
 
  <dt>data</dt>
786
 
    <dd>This is the name-value string that will be sent as the
787
 
    transaction data. If the request is HTTP GET, the data become
788
 
    part of querystring. If HTTP POST, the data are sent in the
789
 
    message body.</dd>
790
 
 
791
 
  <dt>xdr</dt>
792
 
    <dd>Defines the transport to be used for cross-domain requests.
793
 
    By setting this property, the transaction will use the specified
794
 
    transport instead of XMLHttpRequest. The properties of the
795
 
    transport object are:
796
 
    <dl>
797
 
      <dt>use</dt>
798
 
        <dd>The transport to be used: 'flash' or 'native'</dd>
799
 
      <dt>dataType</dt>
800
 
        <dd>Set the value to 'XML' if that is the expected response
801
 
        content type.</dd>
802
 
    </dl></dd>
803
 
 
804
 
  <dt>form</dt>
805
 
    <dd>Form serialization configuration object.  Its properties are:
806
 
    <dl>
807
 
      <dt>id</dt>
808
 
        <dd>Node object or id of HTML form</dd>
809
 
      <dt>useDisabled</dt>
810
 
        <dd>`true` to also serialize disabled form field values
811
 
        (defaults to `false`)</dd>
812
 
    </dl></dd>
813
 
 
814
 
  <dt>on</dt>
815
 
    <dd>Assigns transaction event subscriptions. Available events are:
816
 
    <dl>
817
 
      <dt>start</dt>
818
 
        <dd>Fires when a request is sent to a resource.</dd>
819
 
      <dt>complete</dt>
820
 
        <dd>Fires when the transaction is complete.</dd>
821
 
      <dt>success</dt>
822
 
        <dd>Fires when the HTTP response status is within the 2xx
823
 
        range.</dd>
824
 
      <dt>failure</dt>
825
 
        <dd>Fires when the HTTP response status is outside the 2xx
826
 
        range, if an exception occurs, if the transation is aborted,
827
 
        or if the transaction exceeds a configured `timeout`.</dd>
828
 
      <dt>end</dt>
829
 
        <dd>Fires at the conclusion of the transaction
830
 
           lifecycle, after `success` or `failure`.</dd>
831
 
    </dl>
832
 
 
833
 
    <p>Callback functions for `start` and `end` receive the id of the
834
 
    transaction as a first argument. For `complete`, `success`, and
835
 
    `failure`, callbacks receive the id and the response object
836
 
    (usually the XMLHttpRequest instance).  If the `arguments`
837
 
    property was included in the configuration object passed to
838
 
    `Y.io()`, the configured data will be passed to all callbacks as
839
 
    the last argument.</p>
840
 
    </dd>
841
 
 
842
 
  <dt>sync</dt>
843
 
    <dd>Pass `true` to make a same-domain transaction synchronous.
844
 
    <strong>CAVEAT</strong>: This will negatively impact the user
845
 
    experience. Have a <em>very</em> good reason if you intend to use
846
 
    this.</dd>
847
 
 
848
 
  <dt>context</dt>
849
 
    <dd>The "`this'" object for all configured event handlers. If a
850
 
    specific context is needed for individual callbacks, bind the
851
 
    callback to a context using `Y.bind()`.</dd>
852
 
 
853
 
  <dt>headers</dt>
854
 
    <dd>Object map of transaction headers to send to the server. The
855
 
    object keys are the header names and the values are the header
856
 
    values.</dd>
857
 
 
858
 
  <dt>timeout</dt>
859
 
    <dd>Millisecond threshold for the transaction before being
860
 
    automatically aborted.</dd>
861
 
 
862
 
  <dt>arguments</dt>
863
 
    <dd>User-defined data passed to all registered event handlers.
864
 
    This value is available as the second argument in the "start" and
865
 
    "end" event handlers. It is the third argument in the "complete",
866
 
    "success", and "failure" event handlers. <strong>Be sure to quote
867
 
    this property name in the transaction configuration as
868
 
    "arguments" is a reserved word in JavaScript</strong> (e.g.
869
 
    `Y.io({ ..., "arguments": stuff })`).</dd>
870
 
</dl>
871
 
 
872
 
@method io
873
 
@static
874
 
@param {String} url qualified path to transaction resource.
875
 
@param {Object} config configuration object for the transaction.
876
 
@return {Object}
877
 
@for YUI
878
 
**/
879
 
Y.io = function(url, config) {
880
 
    // Calling IO through the static interface will use and reuse
881
 
    // an instance of IO.
882
 
    var transaction = Y.io._map['io:0'] || new IO();
883
 
    return transaction.send.apply(transaction, [url, config]);
884
 
};
885
 
 
886
 
/**
887
 
Method for setting and deleting IO HTTP headers to be sent with every
888
 
request.
889
 
 
890
 
Hosted as a property on the `io` function (e.g. `Y.io.header`).
891
 
 
892
 
@method header
893
 
@param {String} name HTTP header
894
 
@param {String} value HTTP header value
895
 
@static
896
 
**/
897
 
Y.io.header = function(name, value) {
898
 
    // Calling IO through the static interface will use and reuse
899
 
    // an instance of IO.
900
 
    var transaction = Y.io._map['io:0'] || new IO();
901
 
    transaction.setHeader(name, value);
902
 
};
903
 
 
904
 
Y.IO = IO;
905
 
// Map of all IO instances created.
906
 
Y.io._map = {};
907
 
var XHR = win && win.XMLHttpRequest,
908
 
    XDR = win && win.XDomainRequest,
909
 
    AX = win && win.ActiveXObject;
910
 
 
911
 
 
912
 
Y.mix(Y.IO, {
913
 
    /**
914
 
    * The ID of the default IO transport, defaults to `xhr`
915
 
    * @property _default
916
 
    * @type {String}
917
 
    * @static
918
 
    */
919
 
    _default: 'xhr',
920
 
    /**
921
 
    *
922
 
    * @method defaultTransport
923
 
    * @static
924
 
    * @param {String} [id] The transport to set as the default, if empty a new transport is created.
925
 
    * @return {Object} The transport object with a `send` method
926
 
    */
927
 
    defaultTransport: function(id) {
928
 
        if (id) {
929
 
            Y.IO._default = id;
930
 
        } else {
931
 
            var o = {
932
 
                c: Y.IO.transports[Y.IO._default](),
933
 
                notify: Y.IO._default === 'xhr' ? false : true
934
 
            };
935
 
            return o;
936
 
        }
937
 
    },
938
 
    /**
939
 
    * An object hash of custom transports available to IO
940
 
    * @property transports
941
 
    * @type {Object}
942
 
    * @static
943
 
    */
944
 
    transports: {
945
 
        xhr: function () {
946
 
            return XHR ? new XMLHttpRequest() :
947
 
                AX ? new ActiveXObject('Microsoft.XMLHTTP') : null;
948
 
        },
949
 
        xdr: function () {
950
 
            return XDR ? new XDomainRequest() : null;
951
 
        },
952
 
        iframe: function () { return {}; },
953
 
        flash: null,
954
 
        nodejs: null
955
 
    },
956
 
    /**
957
 
    * Create a custom transport of type and return it's object
958
 
    * @method customTransport
959
 
    * @param {String} id The id of the transport to create.
960
 
    * @static
961
 
    */
962
 
    customTransport: function(id) {
963
 
        var o = { c: Y.IO.transports[id]() };
964
 
 
965
 
        o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true;
966
 
        return o;
967
 
    }
968
 
});
969
 
 
970
 
Y.mix(Y.IO.prototype, {
971
 
    /**
972
 
    * Fired from the notify method of the transport which in turn fires
973
 
    * the event on the IO object.
974
 
    * @method notify
975
 
    * @param {String} event The name of the event
976
 
    * @param {Object} transaction The transaction object
977
 
    * @param {Object} config The configuration object for this transaction
978
 
    */
979
 
    notify: function(event, transaction, config) {
980
 
        var io = this;
981
 
 
982
 
        switch (event) {
983
 
            case 'timeout':
984
 
            case 'abort':
985
 
            case 'transport error':
986
 
                transaction.c = { status: 0, statusText: event };
987
 
                event = 'failure';
988
 
            default:
989
 
                io[event].apply(io, [transaction, config]);
990
 
        }
991
 
    }
992
 
});
993
 
 
994
 
 
995
 
 
996
 
 
997
 
}, '3.5.1' ,{requires:['event-custom-base', 'querystring-stringify-simple']});