[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/io-base/ -> io-base.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1