src/cm/media/js/lib/yui/yui3-3.15.0/build/io-base/io-base-debug.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                 Y.log('Stringifying config.data for request', 'info', 'io');
       
   655                 config.data = data = Y.QueryString.stringify(data);
       
   656             } else {
       
   657                 Y.log('Failed to stringify config.data object, likely because `querystring-stringify-simple` is missing.', 'warn', 'io');
       
   658             }
       
   659         }
       
   660 
       
   661         if (config.form) {
       
   662             if (config.form.upload) {
       
   663                 // This is a file upload transaction, calling
       
   664                 // upload() in io-upload-iframe.
       
   665                 return io.upload(transaction, uri, config);
       
   666             } else {
       
   667                 // Serialize HTML form data into a key-value string.
       
   668                 data = io._serialize(config.form, data);
       
   669             }
       
   670         }
       
   671 
       
   672         // Convert falsy values to an empty string. This way IE can't be
       
   673         // rediculous and translate `undefined` to "undefined".
       
   674         data || (data = '');
       
   675 
       
   676         if (data) {
       
   677             switch (method) {
       
   678                 case 'GET':
       
   679                 case 'HEAD':
       
   680                 case 'DELETE':
       
   681                     u = io._concat(u, data);
       
   682                     data = '';
       
   683                     Y.log('HTTP' + method + ' with data.  The querystring is: ' + u, 'info', 'io');
       
   684                     break;
       
   685                 case 'POST':
       
   686                 case 'PUT':
       
   687                     // If Content-Type is defined in the configuration object, or
       
   688                     // or as a default header, it will be used instead of
       
   689                     // 'application/x-www-form-urlencoded; charset=UTF-8'
       
   690                     config.headers = Y.merge({
       
   691                         'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
       
   692                     }, config.headers);
       
   693                     break;
       
   694             }
       
   695         }
       
   696 
       
   697         if (transaction.xdr) {
       
   698             // Route data to io-xdr module for flash and XDomainRequest.
       
   699             return io.xdr(u, transaction, config);
       
   700         }
       
   701         else if (transaction.notify) {
       
   702             // Route data to custom transport
       
   703             return transaction.c.send(transaction, uri, config);
       
   704         }
       
   705 
       
   706         if (!sync && !transaction.upload) {
       
   707             transaction.c.onreadystatechange = function() {
       
   708                 io._rS(transaction, config);
       
   709             };
       
   710         }
       
   711 
       
   712         try {
       
   713             // Determine if request is to be set as
       
   714             // synchronous or asynchronous.
       
   715             transaction.c.open(method, u, !sync, config.username || null, config.password || null);
       
   716             io._setHeaders(transaction.c, config.headers || {});
       
   717             io.start(transaction, config);
       
   718 
       
   719             // Will work only in browsers that implement the
       
   720             // Cross-Origin Resource Sharing draft.
       
   721             if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) {
       
   722                 transaction.c.withCredentials = true;
       
   723             }
       
   724 
       
   725             // Using "null" with HTTP POST will result in a request
       
   726             // with no Content-Length header defined.
       
   727             transaction.c.send(data);
       
   728 
       
   729             if (sync) {
       
   730                 // Create a response object for synchronous transactions,
       
   731                 // mixing id and arguments properties with the xhr
       
   732                 // properties whitelist.
       
   733                 for (i = 0, len = XHR_PROPS.length; i < len; ++i) {
       
   734                     response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]];
       
   735                 }
       
   736 
       
   737                 response.getAllResponseHeaders = function() {
       
   738                     return transaction.c.getAllResponseHeaders();
       
   739                 };
       
   740 
       
   741                 response.getResponseHeader = function(name) {
       
   742                     return transaction.c.getResponseHeader(name);
       
   743                 };
       
   744 
       
   745                 io.complete(transaction, config);
       
   746                 io._result(transaction, config);
       
   747 
       
   748                 return response;
       
   749             }
       
   750         } catch(e) {
       
   751             if (transaction.xdr) {
       
   752                 // This exception is usually thrown by browsers
       
   753                 // that do not support XMLHttpRequest Level 2.
       
   754                 // Retry the request with the XDR transport set
       
   755                 // to 'flash'.  If the Flash transport is not
       
   756                 // initialized or available, the transaction
       
   757                 // will resolve to a transport error.
       
   758                 return io._retry(transaction, uri, config);
       
   759             } else {
       
   760                 io.complete(transaction, config);
       
   761                 io._result(transaction, config);
       
   762             }
       
   763         }
       
   764 
       
   765         // If config.timeout is defined, and the request is standard XHR,
       
   766         // initialize timeout polling.
       
   767         if (config.timeout) {
       
   768             io._startTimeout(transaction, config.timeout);
       
   769             Y.log('Configuration timeout set to: ' + config.timeout, 'info', 'io');
       
   770         }
       
   771 
       
   772         return {
       
   773             id: transaction.id,
       
   774             abort: function() {
       
   775                 return transaction.c ? io._abort(transaction, 'abort') : false;
       
   776             },
       
   777             isInProgress: function() {
       
   778                 return transaction.c ? (transaction.c.readyState % 4) : false;
       
   779             },
       
   780             io: io
       
   781         };
       
   782     }
       
   783 };
       
   784 
       
   785 /**
       
   786 Method for initiating an ajax call.  The first argument is the url end
       
   787 point for the call.  The second argument is an object to configure the
       
   788 transaction and attach event subscriptions.  The configuration object
       
   789 supports the following properties:
       
   790 
       
   791 <dl>
       
   792   <dt>method</dt>
       
   793     <dd>HTTP method verb (e.g., GET or POST). If this property is not
       
   794         not defined, the default value will be GET.</dd>
       
   795 
       
   796   <dt>data</dt>
       
   797     <dd>This is the name-value string that will be sent as the
       
   798     transaction data. If the request is HTTP GET, the data become
       
   799     part of querystring. If HTTP POST, the data are sent in the
       
   800     message body.</dd>
       
   801 
       
   802   <dt>xdr</dt>
       
   803     <dd>Defines the transport to be used for cross-domain requests.
       
   804     By setting this property, the transaction will use the specified
       
   805     transport instead of XMLHttpRequest. The properties of the
       
   806     transport object are:
       
   807     <dl>
       
   808       <dt>use</dt>
       
   809         <dd>The transport to be used: 'flash' or 'native'</dd>
       
   810       <dt>dataType</dt>
       
   811         <dd>Set the value to 'XML' if that is the expected response
       
   812         content type.</dd>
       
   813     </dl></dd>
       
   814 
       
   815   <dt>form</dt>
       
   816     <dd>Form serialization configuration object.  Its properties are:
       
   817     <dl>
       
   818       <dt>id</dt>
       
   819         <dd>Node object or id of HTML form</dd>
       
   820       <dt>useDisabled</dt>
       
   821         <dd>`true` to also serialize disabled form field values
       
   822         (defaults to `false`)</dd>
       
   823     </dl></dd>
       
   824 
       
   825   <dt>on</dt>
       
   826     <dd>Assigns transaction event subscriptions. Available events are:
       
   827     <dl>
       
   828       <dt>start</dt>
       
   829         <dd>Fires when a request is sent to a resource.</dd>
       
   830       <dt>complete</dt>
       
   831         <dd>Fires when the transaction is complete.</dd>
       
   832       <dt>success</dt>
       
   833         <dd>Fires when the HTTP response status is within the 2xx
       
   834         range.</dd>
       
   835       <dt>failure</dt>
       
   836         <dd>Fires when the HTTP response status is outside the 2xx
       
   837         range, if an exception occurs, if the transation is aborted,
       
   838         or if the transaction exceeds a configured `timeout`.</dd>
       
   839       <dt>end</dt>
       
   840         <dd>Fires at the conclusion of the transaction
       
   841            lifecycle, after `success` or `failure`.</dd>
       
   842     </dl>
       
   843 
       
   844     <p>Callback functions for `start` and `end` receive the id of the
       
   845     transaction as a first argument. For `complete`, `success`, and
       
   846     `failure`, callbacks receive the id and the response object
       
   847     (usually the XMLHttpRequest instance).  If the `arguments`
       
   848     property was included in the configuration object passed to
       
   849     `Y.io()`, the configured data will be passed to all callbacks as
       
   850     the last argument.</p>
       
   851     </dd>
       
   852 
       
   853   <dt>sync</dt>
       
   854     <dd>Pass `true` to make a same-domain transaction synchronous.
       
   855     <strong>CAVEAT</strong>: This will negatively impact the user
       
   856     experience. Have a <em>very</em> good reason if you intend to use
       
   857     this.</dd>
       
   858 
       
   859   <dt>context</dt>
       
   860     <dd>The "`this'" object for all configured event handlers. If a
       
   861     specific context is needed for individual callbacks, bind the
       
   862     callback to a context using `Y.bind()`.</dd>
       
   863 
       
   864   <dt>headers</dt>
       
   865     <dd>Object map of transaction headers to send to the server. The
       
   866     object keys are the header names and the values are the header
       
   867     values.</dd>
       
   868 
       
   869   <dt>timeout</dt>
       
   870     <dd>Millisecond threshold for the transaction before being
       
   871     automatically aborted.</dd>
       
   872 
       
   873   <dt>arguments</dt>
       
   874     <dd>User-defined data passed to all registered event handlers.
       
   875     This value is available as the second argument in the "start" and
       
   876     "end" event handlers. It is the third argument in the "complete",
       
   877     "success", and "failure" event handlers. <strong>Be sure to quote
       
   878     this property name in the transaction configuration as
       
   879     "arguments" is a reserved word in JavaScript</strong> (e.g.
       
   880     `Y.io({ ..., "arguments": stuff })`).</dd>
       
   881 </dl>
       
   882 
       
   883 @method io
       
   884 @static
       
   885 @param {String} url qualified path to transaction resource.
       
   886 @param {Object} config configuration object for the transaction.
       
   887 @return {Object}
       
   888 @for YUI
       
   889 **/
       
   890 Y.io = function(url, config) {
       
   891     // Calling IO through the static interface will use and reuse
       
   892     // an instance of IO.
       
   893     var transaction = Y.io._map['io:0'] || new IO();
       
   894     return transaction.send.apply(transaction, [url, config]);
       
   895 };
       
   896 
       
   897 /**
       
   898 Method for setting and deleting IO HTTP headers to be sent with every
       
   899 request.
       
   900 
       
   901 Hosted as a property on the `io` function (e.g. `Y.io.header`).
       
   902 
       
   903 @method header
       
   904 @param {String} name HTTP header
       
   905 @param {String} value HTTP header value
       
   906 @static
       
   907 **/
       
   908 Y.io.header = function(name, value) {
       
   909     // Calling IO through the static interface will use and reuse
       
   910     // an instance of IO.
       
   911     var transaction = Y.io._map['io:0'] || new IO();
       
   912     transaction.setHeader(name, value);
       
   913 };
       
   914 
       
   915 Y.IO = IO;
       
   916 // Map of all IO instances created.
       
   917 Y.io._map = {};
       
   918 var XHR = win && win.XMLHttpRequest,
       
   919     XDR = win && win.XDomainRequest,
       
   920     AX = win && win.ActiveXObject,
       
   921 
       
   922     // Checks for the presence of the `withCredentials` in an XHR instance
       
   923     // object, which will be present if the environment supports CORS.
       
   924     SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest());
       
   925 
       
   926 
       
   927 Y.mix(Y.IO, {
       
   928     /**
       
   929     * The ID of the default IO transport, defaults to `xhr`
       
   930     * @property _default
       
   931     * @type {String}
       
   932     * @static
       
   933     */
       
   934     _default: 'xhr',
       
   935     /**
       
   936     *
       
   937     * @method defaultTransport
       
   938     * @static
       
   939     * @param {String} [id] The transport to set as the default, if empty a new transport is created.
       
   940     * @return {Object} The transport object with a `send` method
       
   941     */
       
   942     defaultTransport: function(id) {
       
   943         if (id) {
       
   944             Y.log('Setting default IO to: ' + id, 'info', 'io');
       
   945             Y.IO._default = id;
       
   946         } else {
       
   947             var o = {
       
   948                 c: Y.IO.transports[Y.IO._default](),
       
   949                 notify: Y.IO._default === 'xhr' ? false : true
       
   950             };
       
   951             Y.log('Creating default transport: ' + Y.IO._default, 'info', 'io');
       
   952             return o;
       
   953         }
       
   954     },
       
   955     /**
       
   956     * An object hash of custom transports available to IO
       
   957     * @property transports
       
   958     * @type {Object}
       
   959     * @static
       
   960     */
       
   961     transports: {
       
   962         xhr: function () {
       
   963             return XHR ? new XMLHttpRequest() :
       
   964                 AX ? new ActiveXObject('Microsoft.XMLHTTP') : null;
       
   965         },
       
   966         xdr: function () {
       
   967             return XDR ? new XDomainRequest() : null;
       
   968         },
       
   969         iframe: function () { return {}; },
       
   970         flash: null,
       
   971         nodejs: null
       
   972     },
       
   973     /**
       
   974     * Create a custom transport of type and return it's object
       
   975     * @method customTransport
       
   976     * @param {String} id The id of the transport to create.
       
   977     * @static
       
   978     */
       
   979     customTransport: function(id) {
       
   980         var o = { c: Y.IO.transports[id]() };
       
   981 
       
   982         o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true;
       
   983         return o;
       
   984     }
       
   985 });
       
   986 
       
   987 Y.mix(Y.IO.prototype, {
       
   988     /**
       
   989     * Fired from the notify method of the transport which in turn fires
       
   990     * the event on the IO object.
       
   991     * @method notify
       
   992     * @param {String} event The name of the event
       
   993     * @param {Object} transaction The transaction object
       
   994     * @param {Object} config The configuration object for this transaction
       
   995     */
       
   996     notify: function(event, transaction, config) {
       
   997         var io = this;
       
   998 
       
   999         switch (event) {
       
  1000             case 'timeout':
       
  1001             case 'abort':
       
  1002             case 'transport error':
       
  1003                 transaction.c = { status: 0, statusText: event };
       
  1004                 event = 'failure';
       
  1005             default:
       
  1006                 io[event].apply(io, [transaction, config]);
       
  1007         }
       
  1008     }
       
  1009 });
       
  1010 
       
  1011 
       
  1012 
       
  1013 
       
  1014 }, '@VERSION@', {"requires": ["event-custom-base", "querystring-stringify-simple"]});