src/cm/media/js/lib/yui/yui3-3.15.0/build/io-base/io-base.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('io-base', function (Y, NAME) {
       
     2 
       
     3 /**
       
     4 Base IO functionality. Provides basic XHR transport support.
       
     5 
       
     6 @module io
       
     7 @submodule io-base
       
     8 @for IO
       
     9 **/
       
    10 
       
    11 var // List of events that comprise the IO event lifecycle.
       
    12     EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'],
       
    13 
       
    14     // Whitelist of used XHR response object properties.
       
    15     XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'],
       
    16 
       
    17     win = Y.config.win,
       
    18     uid = 0;
       
    19 
       
    20 /**
       
    21 The IO class is a utility that brokers HTTP requests through a simplified
       
    22 interface.  Specifically, it allows JavaScript to make HTTP requests to
       
    23 a resource without a page reload.  The underlying transport for making
       
    24 same-domain requests is the XMLHttpRequest object.  IO can also use
       
    25 Flash, if specified as a transport, for cross-domain requests.
       
    26 
       
    27 @class IO
       
    28 @constructor
       
    29 @param {Object} config Object of EventTarget's publish method configurations
       
    30                     used to configure IO's events.
       
    31 **/
       
    32 function IO (config) {
       
    33     var io = this;
       
    34 
       
    35     io._uid = 'io:' + uid++;
       
    36     io._init(config);
       
    37     Y.io._map[io._uid] = io;
       
    38 }
       
    39 
       
    40 IO.prototype = {
       
    41     //--------------------------------------
       
    42     //  Properties
       
    43     //--------------------------------------
       
    44 
       
    45    /**
       
    46     * A counter that increments for each transaction.
       
    47     *
       
    48     * @property _id
       
    49     * @private
       
    50     * @type {Number}
       
    51     */
       
    52     _id: 0,
       
    53 
       
    54    /**
       
    55     * Object of IO HTTP headers sent with each transaction.
       
    56     *
       
    57     * @property _headers
       
    58     * @private
       
    59     * @type {Object}
       
    60     */
       
    61     _headers: {
       
    62         'X-Requested-With' : 'XMLHttpRequest'
       
    63     },
       
    64 
       
    65    /**
       
    66     * Object that stores timeout values for any transaction with a defined
       
    67     * "timeout" configuration property.
       
    68     *
       
    69     * @property _timeout
       
    70     * @private
       
    71     * @type {Object}
       
    72     */
       
    73     _timeout: {},
       
    74 
       
    75     //--------------------------------------
       
    76     //  Methods
       
    77     //--------------------------------------
       
    78 
       
    79     _init: function(config) {
       
    80         var io = this, i, len;
       
    81 
       
    82         io.cfg = config || {};
       
    83 
       
    84         Y.augment(io, Y.EventTarget);
       
    85         for (i = 0, len = EVENTS.length; i < len; ++i) {
       
    86             // Publish IO global events with configurations, if any.
       
    87             // IO global events are set to broadcast by default.
       
    88             // These events use the "io:" namespace.
       
    89             io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config));
       
    90             // Publish IO transaction events with configurations, if
       
    91             // any.  These events use the "io-trn:" namespace.
       
    92             io.publish('io-trn:' + EVENTS[i], config);
       
    93         }
       
    94     },
       
    95 
       
    96    /**
       
    97     * Method that creates a unique transaction object for each request.
       
    98     *
       
    99     * @method _create
       
   100     * @private
       
   101     * @param {Object} cfg Configuration object subset to determine if
       
   102     *                 the transaction is an XDR or file upload,
       
   103     *                 requiring an alternate transport.
       
   104     * @param {Number} id Transaction id
       
   105     * @return {Object} The transaction object
       
   106     */
       
   107     _create: function(config, id) {
       
   108         var io = this,
       
   109             transaction = {
       
   110                 id : Y.Lang.isNumber(id) ? id : io._id++,
       
   111                 uid: io._uid
       
   112             },
       
   113             alt = config.xdr ? config.xdr.use : null,
       
   114             form = config.form && config.form.upload ? 'iframe' : null,
       
   115             use;
       
   116 
       
   117         if (alt === 'native') {
       
   118             // Non-IE and IE >= 10  can use XHR level 2 and not rely on an
       
   119             // external transport.
       
   120             alt = Y.UA.ie && !SUPPORTS_CORS ? 'xdr' : null;
       
   121 
       
   122             // Prevent "pre-flight" OPTIONS request by removing the
       
   123             // `X-Requested-With` HTTP header from CORS requests. This header
       
   124             // can be added back on a per-request basis, if desired.
       
   125             io.setHeader('X-Requested-With');
       
   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 win.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     *       <dt>credentials</dt>
       
   560     *         <dd>Set the value to 'true' to set XHR.withCredentials property to true.</dd>
       
   561     *     </dl></dd>
       
   562     *
       
   563     *   <dt>form</dt>
       
   564     *     <dd>Form serialization configuration object.  Its properties are:
       
   565     *     <dl>
       
   566     *       <dt>id</dt>
       
   567     *         <dd>Node object or id of HTML form</dd>
       
   568     *       <dt>useDisabled</dt>
       
   569     *         <dd>`true` to also serialize disabled form field values
       
   570     *         (defaults to `false`)</dd>
       
   571     *     </dl></dd>
       
   572     *
       
   573     *   <dt>on</dt>
       
   574     *     <dd>Assigns transaction event subscriptions. Available events are:
       
   575     *     <dl>
       
   576     *       <dt>start</dt>
       
   577     *         <dd>Fires when a request is sent to a resource.</dd>
       
   578     *       <dt>complete</dt>
       
   579     *         <dd>Fires when the transaction is complete.</dd>
       
   580     *       <dt>success</dt>
       
   581     *         <dd>Fires when the HTTP response status is within the 2xx
       
   582     *         range.</dd>
       
   583     *       <dt>failure</dt>
       
   584     *         <dd>Fires when the HTTP response status is outside the 2xx
       
   585     *         range, if an exception occurs, if the transation is aborted,
       
   586     *         or if the transaction exceeds a configured `timeout`.</dd>
       
   587     *       <dt>end</dt>
       
   588     *         <dd>Fires at the conclusion of the transaction
       
   589     *            lifecycle, after `success` or `failure`.</dd>
       
   590     *     </dl>
       
   591     *
       
   592     *     <p>Callback functions for `start` and `end` receive the id of the
       
   593     *     transaction as a first argument. For `complete`, `success`, and
       
   594     *     `failure`, callbacks receive the id and the response object
       
   595     *     (usually the XMLHttpRequest instance).  If the `arguments`
       
   596     *     property was included in the configuration object passed to
       
   597     *     `Y.io()`, the configured data will be passed to all callbacks as
       
   598     *     the last argument.</p>
       
   599     *     </dd>
       
   600     *
       
   601     *   <dt>sync</dt>
       
   602     *     <dd>Pass `true` to make a same-domain transaction synchronous.
       
   603     *     <strong>CAVEAT</strong>: This will negatively impact the user
       
   604     *     experience. Have a <em>very</em> good reason if you intend to use
       
   605     *     this.</dd>
       
   606     *
       
   607     *   <dt>context</dt>
       
   608     *     <dd>The "`this'" object for all configured event handlers. If a
       
   609     *     specific context is needed for individual callbacks, bind the
       
   610     *     callback to a context using `Y.bind()`.</dd>
       
   611     *
       
   612     *   <dt>headers</dt>
       
   613     *     <dd>Object map of transaction headers to send to the server. The
       
   614     *     object keys are the header names and the values are the header
       
   615     *     values.</dd>
       
   616     *
       
   617     *   <dt>timeout</dt>
       
   618     *     <dd>Millisecond threshold for the transaction before being
       
   619     *     automatically aborted.</dd>
       
   620     *
       
   621     *   <dt>arguments</dt>
       
   622     *     <dd>User-defined data passed to all registered event handlers.
       
   623     *     This value is available as the second argument in the "start" and
       
   624     *     "end" event handlers. It is the third argument in the "complete",
       
   625     *     "success", and "failure" event handlers. <strong>Be sure to quote
       
   626     *     this property name in the transaction configuration as
       
   627     *     "arguments" is a reserved word in JavaScript</strong> (e.g.
       
   628     *     `Y.io({ ..., "arguments": stuff })`).</dd>
       
   629     * </dl>
       
   630     *
       
   631     * @method send
       
   632     * @public
       
   633     * @param {String} uri Qualified path to transaction resource.
       
   634     * @param {Object} config Configuration object for the transaction.
       
   635     * @param {Number} id Transaction id, if already set.
       
   636     * @return {Object}
       
   637     */
       
   638     send: function(uri, config, id) {
       
   639         var transaction, method, i, len, sync, data,
       
   640             io = this,
       
   641             u = uri,
       
   642             response = {};
       
   643 
       
   644         config = config ? Y.Object(config) : {};
       
   645         transaction = io._create(config, id);
       
   646         method = config.method ? config.method.toUpperCase() : 'GET';
       
   647         sync = config.sync;
       
   648         data = config.data;
       
   649 
       
   650         // Serialize a map object into a key-value string using
       
   651         // querystring-stringify-simple.
       
   652         if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) {
       
   653             if (Y.QueryString && Y.QueryString.stringify) {
       
   654                 config.data = data = Y.QueryString.stringify(data);
       
   655             } else {
       
   656             }
       
   657         }
       
   658 
       
   659         if (config.form) {
       
   660             if (config.form.upload) {
       
   661                 // This is a file upload transaction, calling
       
   662                 // upload() in io-upload-iframe.
       
   663                 return io.upload(transaction, uri, config);
       
   664             } else {
       
   665                 // Serialize HTML form data into a key-value string.
       
   666                 data = io._serialize(config.form, data);
       
   667             }
       
   668         }
       
   669 
       
   670         // Convert falsy values to an empty string. This way IE can't be
       
   671         // rediculous and translate `undefined` to "undefined".
       
   672         data || (data = '');
       
   673 
       
   674         if (data) {
       
   675             switch (method) {
       
   676                 case 'GET':
       
   677                 case 'HEAD':
       
   678                 case 'DELETE':
       
   679                     u = io._concat(u, data);
       
   680                     data = '';
       
   681                     break;
       
   682                 case 'POST':
       
   683                 case 'PUT':
       
   684                     // If Content-Type is defined in the configuration object, or
       
   685                     // or as a default header, it will be used instead of
       
   686                     // 'application/x-www-form-urlencoded; charset=UTF-8'
       
   687                     config.headers = Y.merge({
       
   688                         'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
       
   689                     }, config.headers);
       
   690                     break;
       
   691             }
       
   692         }
       
   693 
       
   694         if (transaction.xdr) {
       
   695             // Route data to io-xdr module for flash and XDomainRequest.
       
   696             return io.xdr(u, transaction, config);
       
   697         }
       
   698         else if (transaction.notify) {
       
   699             // Route data to custom transport
       
   700             return transaction.c.send(transaction, uri, config);
       
   701         }
       
   702 
       
   703         if (!sync && !transaction.upload) {
       
   704             transaction.c.onreadystatechange = function() {
       
   705                 io._rS(transaction, config);
       
   706             };
       
   707         }
       
   708 
       
   709         try {
       
   710             // Determine if request is to be set as
       
   711             // synchronous or asynchronous.
       
   712             transaction.c.open(method, u, !sync, config.username || null, config.password || null);
       
   713             io._setHeaders(transaction.c, config.headers || {});
       
   714             io.start(transaction, config);
       
   715 
       
   716             // Will work only in browsers that implement the
       
   717             // Cross-Origin Resource Sharing draft.
       
   718             if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) {
       
   719                 transaction.c.withCredentials = true;
       
   720             }
       
   721 
       
   722             // Using "null" with HTTP POST will result in a request
       
   723             // with no Content-Length header defined.
       
   724             transaction.c.send(data);
       
   725 
       
   726             if (sync) {
       
   727                 // Create a response object for synchronous transactions,
       
   728                 // mixing id and arguments properties with the xhr
       
   729                 // properties whitelist.
       
   730                 for (i = 0, len = XHR_PROPS.length; i < len; ++i) {
       
   731                     response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]];
       
   732                 }
       
   733 
       
   734                 response.getAllResponseHeaders = function() {
       
   735                     return transaction.c.getAllResponseHeaders();
       
   736                 };
       
   737 
       
   738                 response.getResponseHeader = function(name) {
       
   739                     return transaction.c.getResponseHeader(name);
       
   740                 };
       
   741 
       
   742                 io.complete(transaction, config);
       
   743                 io._result(transaction, config);
       
   744 
       
   745                 return response;
       
   746             }
       
   747         } catch(e) {
       
   748             if (transaction.xdr) {
       
   749                 // This exception is usually thrown by browsers
       
   750                 // that do not support XMLHttpRequest Level 2.
       
   751                 // Retry the request with the XDR transport set
       
   752                 // to 'flash'.  If the Flash transport is not
       
   753                 // initialized or available, the transaction
       
   754                 // will resolve to a transport error.
       
   755                 return io._retry(transaction, uri, config);
       
   756             } else {
       
   757                 io.complete(transaction, config);
       
   758                 io._result(transaction, config);
       
   759             }
       
   760         }
       
   761 
       
   762         // If config.timeout is defined, and the request is standard XHR,
       
   763         // initialize timeout polling.
       
   764         if (config.timeout) {
       
   765             io._startTimeout(transaction, config.timeout);
       
   766         }
       
   767 
       
   768         return {
       
   769             id: transaction.id,
       
   770             abort: function() {
       
   771                 return transaction.c ? io._abort(transaction, 'abort') : false;
       
   772             },
       
   773             isInProgress: function() {
       
   774                 return transaction.c ? (transaction.c.readyState % 4) : false;
       
   775             },
       
   776             io: io
       
   777         };
       
   778     }
       
   779 };
       
   780 
       
   781 /**
       
   782 Method for initiating an ajax call.  The first argument is the url end
       
   783 point for the call.  The second argument is an object to configure the
       
   784 transaction and attach event subscriptions.  The configuration object
       
   785 supports the following properties:
       
   786 
       
   787 <dl>
       
   788   <dt>method</dt>
       
   789     <dd>HTTP method verb (e.g., GET or POST). If this property is not
       
   790         not defined, the default value will be GET.</dd>
       
   791 
       
   792   <dt>data</dt>
       
   793     <dd>This is the name-value string that will be sent as the
       
   794     transaction data. If the request is HTTP GET, the data become
       
   795     part of querystring. If HTTP POST, the data are sent in the
       
   796     message body.</dd>
       
   797 
       
   798   <dt>xdr</dt>
       
   799     <dd>Defines the transport to be used for cross-domain requests.
       
   800     By setting this property, the transaction will use the specified
       
   801     transport instead of XMLHttpRequest. The properties of the
       
   802     transport object are:
       
   803     <dl>
       
   804       <dt>use</dt>
       
   805         <dd>The transport to be used: 'flash' or 'native'</dd>
       
   806       <dt>dataType</dt>
       
   807         <dd>Set the value to 'XML' if that is the expected response
       
   808         content type.</dd>
       
   809     </dl></dd>
       
   810 
       
   811   <dt>form</dt>
       
   812     <dd>Form serialization configuration object.  Its properties are:
       
   813     <dl>
       
   814       <dt>id</dt>
       
   815         <dd>Node object or id of HTML form</dd>
       
   816       <dt>useDisabled</dt>
       
   817         <dd>`true` to also serialize disabled form field values
       
   818         (defaults to `false`)</dd>
       
   819     </dl></dd>
       
   820 
       
   821   <dt>on</dt>
       
   822     <dd>Assigns transaction event subscriptions. Available events are:
       
   823     <dl>
       
   824       <dt>start</dt>
       
   825         <dd>Fires when a request is sent to a resource.</dd>
       
   826       <dt>complete</dt>
       
   827         <dd>Fires when the transaction is complete.</dd>
       
   828       <dt>success</dt>
       
   829         <dd>Fires when the HTTP response status is within the 2xx
       
   830         range.</dd>
       
   831       <dt>failure</dt>
       
   832         <dd>Fires when the HTTP response status is outside the 2xx
       
   833         range, if an exception occurs, if the transation is aborted,
       
   834         or if the transaction exceeds a configured `timeout`.</dd>
       
   835       <dt>end</dt>
       
   836         <dd>Fires at the conclusion of the transaction
       
   837            lifecycle, after `success` or `failure`.</dd>
       
   838     </dl>
       
   839 
       
   840     <p>Callback functions for `start` and `end` receive the id of the
       
   841     transaction as a first argument. For `complete`, `success`, and
       
   842     `failure`, callbacks receive the id and the response object
       
   843     (usually the XMLHttpRequest instance).  If the `arguments`
       
   844     property was included in the configuration object passed to
       
   845     `Y.io()`, the configured data will be passed to all callbacks as
       
   846     the last argument.</p>
       
   847     </dd>
       
   848 
       
   849   <dt>sync</dt>
       
   850     <dd>Pass `true` to make a same-domain transaction synchronous.
       
   851     <strong>CAVEAT</strong>: This will negatively impact the user
       
   852     experience. Have a <em>very</em> good reason if you intend to use
       
   853     this.</dd>
       
   854 
       
   855   <dt>context</dt>
       
   856     <dd>The "`this'" object for all configured event handlers. If a
       
   857     specific context is needed for individual callbacks, bind the
       
   858     callback to a context using `Y.bind()`.</dd>
       
   859 
       
   860   <dt>headers</dt>
       
   861     <dd>Object map of transaction headers to send to the server. The
       
   862     object keys are the header names and the values are the header
       
   863     values.</dd>
       
   864 
       
   865   <dt>timeout</dt>
       
   866     <dd>Millisecond threshold for the transaction before being
       
   867     automatically aborted.</dd>
       
   868 
       
   869   <dt>arguments</dt>
       
   870     <dd>User-defined data passed to all registered event handlers.
       
   871     This value is available as the second argument in the "start" and
       
   872     "end" event handlers. It is the third argument in the "complete",
       
   873     "success", and "failure" event handlers. <strong>Be sure to quote
       
   874     this property name in the transaction configuration as
       
   875     "arguments" is a reserved word in JavaScript</strong> (e.g.
       
   876     `Y.io({ ..., "arguments": stuff })`).</dd>
       
   877 </dl>
       
   878 
       
   879 @method io
       
   880 @static
       
   881 @param {String} url qualified path to transaction resource.
       
   882 @param {Object} config configuration object for the transaction.
       
   883 @return {Object}
       
   884 @for YUI
       
   885 **/
       
   886 Y.io = function(url, config) {
       
   887     // Calling IO through the static interface will use and reuse
       
   888     // an instance of IO.
       
   889     var transaction = Y.io._map['io:0'] || new IO();
       
   890     return transaction.send.apply(transaction, [url, config]);
       
   891 };
       
   892 
       
   893 /**
       
   894 Method for setting and deleting IO HTTP headers to be sent with every
       
   895 request.
       
   896 
       
   897 Hosted as a property on the `io` function (e.g. `Y.io.header`).
       
   898 
       
   899 @method header
       
   900 @param {String} name HTTP header
       
   901 @param {String} value HTTP header value
       
   902 @static
       
   903 **/
       
   904 Y.io.header = function(name, value) {
       
   905     // Calling IO through the static interface will use and reuse
       
   906     // an instance of IO.
       
   907     var transaction = Y.io._map['io:0'] || new IO();
       
   908     transaction.setHeader(name, value);
       
   909 };
       
   910 
       
   911 Y.IO = IO;
       
   912 // Map of all IO instances created.
       
   913 Y.io._map = {};
       
   914 var XHR = win && win.XMLHttpRequest,
       
   915     XDR = win && win.XDomainRequest,
       
   916     AX = win && win.ActiveXObject,
       
   917 
       
   918     // Checks for the presence of the `withCredentials` in an XHR instance
       
   919     // object, which will be present if the environment supports CORS.
       
   920     SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest());
       
   921 
       
   922 
       
   923 Y.mix(Y.IO, {
       
   924     /**
       
   925     * The ID of the default IO transport, defaults to `xhr`
       
   926     * @property _default
       
   927     * @type {String}
       
   928     * @static
       
   929     */
       
   930     _default: 'xhr',
       
   931     /**
       
   932     *
       
   933     * @method defaultTransport
       
   934     * @static
       
   935     * @param {String} [id] The transport to set as the default, if empty a new transport is created.
       
   936     * @return {Object} The transport object with a `send` method
       
   937     */
       
   938     defaultTransport: function(id) {
       
   939         if (id) {
       
   940             Y.IO._default = id;
       
   941         } else {
       
   942             var o = {
       
   943                 c: Y.IO.transports[Y.IO._default](),
       
   944                 notify: Y.IO._default === 'xhr' ? false : true
       
   945             };
       
   946             return o;
       
   947         }
       
   948     },
       
   949     /**
       
   950     * An object hash of custom transports available to IO
       
   951     * @property transports
       
   952     * @type {Object}
       
   953     * @static
       
   954     */
       
   955     transports: {
       
   956         xhr: function () {
       
   957             return XHR ? new XMLHttpRequest() :
       
   958                 AX ? new ActiveXObject('Microsoft.XMLHTTP') : null;
       
   959         },
       
   960         xdr: function () {
       
   961             return XDR ? new XDomainRequest() : null;
       
   962         },
       
   963         iframe: function () { return {}; },
       
   964         flash: null,
       
   965         nodejs: null
       
   966     },
       
   967     /**
       
   968     * Create a custom transport of type and return it's object
       
   969     * @method customTransport
       
   970     * @param {String} id The id of the transport to create.
       
   971     * @static
       
   972     */
       
   973     customTransport: function(id) {
       
   974         var o = { c: Y.IO.transports[id]() };
       
   975 
       
   976         o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true;
       
   977         return o;
       
   978     }
       
   979 });
       
   980 
       
   981 Y.mix(Y.IO.prototype, {
       
   982     /**
       
   983     * Fired from the notify method of the transport which in turn fires
       
   984     * the event on the IO object.
       
   985     * @method notify
       
   986     * @param {String} event The name of the event
       
   987     * @param {Object} transaction The transaction object
       
   988     * @param {Object} config The configuration object for this transaction
       
   989     */
       
   990     notify: function(event, transaction, config) {
       
   991         var io = this;
       
   992 
       
   993         switch (event) {
       
   994             case 'timeout':
       
   995             case 'abort':
       
   996             case 'transport error':
       
   997                 transaction.c = { status: 0, statusText: event };
       
   998                 event = 'failure';
       
   999             default:
       
  1000                 io[event].apply(io, [transaction, config]);
       
  1001         }
       
  1002     }
       
  1003 });
       
  1004 
       
  1005 
       
  1006 
       
  1007 
       
  1008 }, '@VERSION@', {"requires": ["event-custom-base", "querystring-stringify-simple"]});