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