| Index: third_party/polymer/components/iron-ajax/iron-request.html
 | 
| diff --git a/third_party/polymer/components/iron-ajax/iron-request.html b/third_party/polymer/components/iron-ajax/iron-request.html
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..128ce951448df15c421e615c545b9b625facd6c6
 | 
| --- /dev/null
 | 
| +++ b/third_party/polymer/components/iron-ajax/iron-request.html
 | 
| @@ -0,0 +1,443 @@
 | 
| +<!--
 | 
| +@license
 | 
| +Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 | 
| +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 | 
| +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 | 
| +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 | 
| +Code distributed by Google as part of the polymer project is also
 | 
| +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 | 
| +-->
 | 
| +
 | 
| +<link rel="import" href="../polymer/polymer.html">
 | 
| +<link rel="import" href="../promise-polyfill/promise-polyfill-lite.html">
 | 
| +
 | 
| +<!--
 | 
| +iron-request can be used to perform XMLHttpRequests.
 | 
| +
 | 
| +    <iron-request id="xhr"></iron-request>
 | 
| +    ...
 | 
| +    this.$.xhr.send({url: url, body: params});
 | 
| +-->
 | 
| +<script>
 | 
| +  'use strict';
 | 
| +
 | 
| +  Polymer({
 | 
| +    is: 'iron-request',
 | 
| +
 | 
| +    hostAttributes: {
 | 
| +      hidden: true
 | 
| +    },
 | 
| +
 | 
| +    properties: {
 | 
| +
 | 
| +      /**
 | 
| +       * A reference to the XMLHttpRequest instance used to generate the
 | 
| +       * network request.
 | 
| +       *
 | 
| +       * @type {XMLHttpRequest}
 | 
| +       */
 | 
| +      xhr: {
 | 
| +        type: Object,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: function() {
 | 
| +          return new XMLHttpRequest();
 | 
| +        }
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * A reference to the parsed response body, if the `xhr` has completely
 | 
| +       * resolved.
 | 
| +       *
 | 
| +       * @type {*}
 | 
| +       * @default null
 | 
| +       */
 | 
| +      response: {
 | 
| +        type: Object,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: function() {
 | 
| +          return null;
 | 
| +        }
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * A reference to the status code, if the `xhr` has completely resolved.
 | 
| +       */
 | 
| +      status: {
 | 
| +        type: Number,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: 0
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * A reference to the status text, if the `xhr` has completely resolved.
 | 
| +       */
 | 
| +      statusText: {
 | 
| +        type: String,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: ''
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * A promise that resolves when the `xhr` response comes back, or rejects
 | 
| +       * if there is an error before the `xhr` completes.
 | 
| +       *
 | 
| +       * @type {Promise}
 | 
| +       */
 | 
| +      completes: {
 | 
| +        type: Object,
 | 
| +        readOnly: true,
 | 
| +        notify: true,
 | 
| +        value: function() {
 | 
| +          return new Promise(function (resolve, reject) {
 | 
| +            this.resolveCompletes = resolve;
 | 
| +            this.rejectCompletes = reject;
 | 
| +          }.bind(this));
 | 
| +        }
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * An object that contains progress information emitted by the XHR if
 | 
| +       * available.
 | 
| +       *
 | 
| +       * @default {}
 | 
| +       */
 | 
| +      progress: {
 | 
| +        type: Object,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: function() {
 | 
| +          return {};
 | 
| +        }
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * Aborted will be true if an abort of the request is attempted.
 | 
| +       */
 | 
| +      aborted: {
 | 
| +        type: Boolean,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: false,
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * Errored will be true if the browser fired an error event from the
 | 
| +       * XHR object (mainly network errors).
 | 
| +       */
 | 
| +      errored: {
 | 
| +        type: Boolean,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: false
 | 
| +      },
 | 
| +
 | 
| +      /**
 | 
| +       * TimedOut will be true if the XHR threw a timeout event.
 | 
| +       */
 | 
| +      timedOut: {
 | 
| +        type: Boolean,
 | 
| +        notify: true,
 | 
| +        readOnly: true,
 | 
| +        value: false
 | 
| +      }
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Succeeded is true if the request succeeded. The request succeeded if it
 | 
| +     * loaded without error, wasn't aborted, and the status code is ≥ 200, and
 | 
| +     * < 300, or if the status code is 0.
 | 
| +     *
 | 
| +     * The status code 0 is accepted as a success because some schemes - e.g.
 | 
| +     * file:// - don't provide status codes.
 | 
| +     *
 | 
| +     * @return {boolean}
 | 
| +     */
 | 
| +    get succeeded() {
 | 
| +      if (this.errored || this.aborted || this.timedOut) {
 | 
| +        return false;
 | 
| +      }
 | 
| +      var status = this.xhr.status || 0;
 | 
| +
 | 
| +      // Note: if we are using the file:// protocol, the status code will be 0
 | 
| +      // for all outcomes (successful or otherwise).
 | 
| +      return status === 0 ||
 | 
| +        (status >= 200 && status < 300);
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Sends an HTTP request to the server and returns the XHR object.
 | 
| +     *
 | 
| +     * The handling of the `body` parameter will vary based on the Content-Type
 | 
| +     * header. See the docs for iron-ajax's `body` param for details.
 | 
| +     *
 | 
| +     * @param {{
 | 
| +     *   url: string,
 | 
| +     *   method: (string|undefined),
 | 
| +     *   async: (boolean|undefined),
 | 
| +     *   body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object),
 | 
| +     *   headers: (Object|undefined),
 | 
| +     *   handleAs: (string|undefined),
 | 
| +     *   jsonPrefix: (string|undefined),
 | 
| +     *   withCredentials: (boolean|undefined)}} options -
 | 
| +     *     url The url to which the request is sent.
 | 
| +     *     method The HTTP method to use, default is GET.
 | 
| +     *     async By default, all requests are sent asynchronously. To send synchronous requests,
 | 
| +     *         set to false.
 | 
| +     *     body The content for the request body for POST method.
 | 
| +     *     headers HTTP request headers.
 | 
| +     *     handleAs The response type. Default is 'text'.
 | 
| +     *     withCredentials Whether or not to send credentials on the request. Default is false.
 | 
| +     *   timeout: (Number|undefined)
 | 
| +     * @return {Promise}
 | 
| +     */
 | 
| +    send: function (options) {
 | 
| +      var xhr = this.xhr;
 | 
| +
 | 
| +      if (xhr.readyState > 0) {
 | 
| +        return null;
 | 
| +      }
 | 
| +
 | 
| +      xhr.addEventListener('progress', function (progress) {
 | 
| +        this._setProgress({
 | 
| +          lengthComputable: progress.lengthComputable,
 | 
| +          loaded: progress.loaded,
 | 
| +          total: progress.total
 | 
| +        });
 | 
| +      }.bind(this))
 | 
| +
 | 
| +      xhr.addEventListener('error', function (error) {
 | 
| +        this._setErrored(true);
 | 
| +        this._updateStatus();
 | 
| +        this.rejectCompletes(error);
 | 
| +      }.bind(this));
 | 
| +
 | 
| +      xhr.addEventListener('timeout', function (error) {
 | 
| +        this._setTimedOut(true);
 | 
| +        this._updateStatus();
 | 
| +        this.rejectCompletes(error);
 | 
| +      }.bind(this));
 | 
| +
 | 
| +      xhr.addEventListener('abort', function () {
 | 
| +        this._updateStatus();
 | 
| +        this.rejectCompletes(new Error('Request aborted.'));
 | 
| +      }.bind(this));
 | 
| +
 | 
| +      // Called after all of the above.
 | 
| +      xhr.addEventListener('loadend', function () {
 | 
| +        this._updateStatus();
 | 
| +        this._setResponse(this.parseResponse());
 | 
| +
 | 
| +        if (!this.succeeded) {
 | 
| +          this.rejectCompletes(new Error('The request failed with status code: ' + this.xhr.status));
 | 
| +          return;
 | 
| +        }
 | 
| +
 | 
| +        this.resolveCompletes(this);
 | 
| +      }.bind(this));
 | 
| +
 | 
| +      this.url = options.url;
 | 
| +      xhr.open(
 | 
| +        options.method || 'GET',
 | 
| +        options.url,
 | 
| +        options.async !== false
 | 
| +      );
 | 
| +
 | 
| +      var acceptType = {
 | 
| +        'json': 'application/json',
 | 
| +        'text': 'text/plain',
 | 
| +        'html': 'text/html',
 | 
| +        'xml': 'application/xml',
 | 
| +        'arraybuffer': 'application/octet-stream'
 | 
| +      }[options.handleAs];
 | 
| +      var headers = options.headers || Object.create(null);
 | 
| +      var newHeaders = Object.create(null);
 | 
| +      for (var key in headers) {
 | 
| +        newHeaders[key.toLowerCase()] = headers[key];
 | 
| +      }
 | 
| +      headers = newHeaders;
 | 
| +
 | 
| +      if (acceptType && !headers['accept']) {
 | 
| +        headers['accept'] = acceptType;
 | 
| +      }
 | 
| +      Object.keys(headers).forEach(function (requestHeader) {
 | 
| +        if (/[A-Z]/.test(requestHeader)) {
 | 
| +          Polymer.Base._error('Headers must be lower case, got', requestHeader);
 | 
| +        }
 | 
| +        xhr.setRequestHeader(
 | 
| +          requestHeader,
 | 
| +          headers[requestHeader]
 | 
| +        );
 | 
| +      }, this);
 | 
| +
 | 
| +      if (options.async !== false) {
 | 
| +        if (options.async) {
 | 
| +          xhr.timeout = options.timeout;
 | 
| +        }
 | 
| +
 | 
| +        var handleAs = options.handleAs;
 | 
| +
 | 
| +        // If a JSON prefix is present, the responseType must be 'text' or the
 | 
| +        // browser won’t be able to parse the response.
 | 
| +        if (!!options.jsonPrefix || !handleAs) {
 | 
| +          handleAs = 'text';
 | 
| +        }
 | 
| +
 | 
| +        // In IE, `xhr.responseType` is an empty string when the response
 | 
| +        // returns. Hence, caching it as `xhr._responseType`.
 | 
| +        xhr.responseType = xhr._responseType = handleAs;
 | 
| +
 | 
| +        // Cache the JSON prefix, if it exists.
 | 
| +        if (!!options.jsonPrefix) {
 | 
| +          xhr._jsonPrefix = options.jsonPrefix;
 | 
| +        }
 | 
| +      }
 | 
| +
 | 
| +      xhr.withCredentials = !!options.withCredentials;
 | 
| +
 | 
| +
 | 
| +      var body = this._encodeBodyObject(options.body, headers['content-type']);
 | 
| +
 | 
| +      xhr.send(
 | 
| +        /** @type {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|
 | 
| +                   null|string|undefined} */
 | 
| +        (body));
 | 
| +
 | 
| +      return this.completes;
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Attempts to parse the response body of the XHR. If parsing succeeds,
 | 
| +     * the value returned will be deserialized based on the `responseType`
 | 
| +     * set on the XHR.
 | 
| +     *
 | 
| +     * @return {*} The parsed response,
 | 
| +     * or undefined if there was an empty response or parsing failed.
 | 
| +     */
 | 
| +    parseResponse: function () {
 | 
| +      var xhr = this.xhr;
 | 
| +      var responseType = xhr.responseType || xhr._responseType;
 | 
| +      var preferResponseText = !this.xhr.responseType;
 | 
| +      var prefixLen = (xhr._jsonPrefix && xhr._jsonPrefix.length) || 0;
 | 
| +
 | 
| +      try {
 | 
| +        switch (responseType) {
 | 
| +          case 'json':
 | 
| +            // If the xhr object doesn't have a natural `xhr.responseType`,
 | 
| +            // we can assume that the browser hasn't parsed the response for us,
 | 
| +            // and so parsing is our responsibility. Likewise if response is
 | 
| +            // undefined, as there's no way to encode undefined in JSON.
 | 
| +            if (preferResponseText || xhr.response === undefined) {
 | 
| +              // Try to emulate the JSON section of the response body section of
 | 
| +              // the spec: https://xhr.spec.whatwg.org/#response-body
 | 
| +              // That is to say, we try to parse as JSON, but if anything goes
 | 
| +              // wrong return null.
 | 
| +              try {
 | 
| +                return JSON.parse(xhr.responseText);
 | 
| +              } catch (_) {
 | 
| +                return null;
 | 
| +              }
 | 
| +            }
 | 
| +
 | 
| +            return xhr.response;
 | 
| +          case 'xml':
 | 
| +            return xhr.responseXML;
 | 
| +          case 'blob':
 | 
| +          case 'document':
 | 
| +          case 'arraybuffer':
 | 
| +            return xhr.response;
 | 
| +          case 'text':
 | 
| +          default: {
 | 
| +            // If `prefixLen` is set, it implies the response should be parsed
 | 
| +            // as JSON once the prefix of length `prefixLen` is stripped from
 | 
| +            // it. Emulate the behavior above where null is returned on failure
 | 
| +            // to parse.
 | 
| +            if (prefixLen) {
 | 
| +              try {
 | 
| +                return JSON.parse(xhr.responseText.substring(prefixLen));
 | 
| +              } catch (_) {
 | 
| +                return null;
 | 
| +              }
 | 
| +            }
 | 
| +            return xhr.responseText;
 | 
| +          }
 | 
| +        }
 | 
| +      } catch (e) {
 | 
| +        this.rejectCompletes(new Error('Could not parse response. ' + e.message));
 | 
| +      }
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Aborts the request.
 | 
| +     */
 | 
| +    abort: function () {
 | 
| +      this._setAborted(true);
 | 
| +      this.xhr.abort();
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * @param {*} body The given body of the request to try and encode.
 | 
| +     * @param {?string} contentType The given content type, to infer an encoding
 | 
| +     *     from.
 | 
| +     * @return {*} Either the encoded body as a string, if successful,
 | 
| +     *     or the unaltered body object if no encoding could be inferred.
 | 
| +     */
 | 
| +    _encodeBodyObject: function(body, contentType) {
 | 
| +      if (typeof body == 'string') {
 | 
| +        return body;  // Already encoded.
 | 
| +      }
 | 
| +      var bodyObj = /** @type {Object} */ (body);
 | 
| +      switch(contentType) {
 | 
| +        case('application/json'):
 | 
| +          return JSON.stringify(bodyObj);
 | 
| +        case('application/x-www-form-urlencoded'):
 | 
| +          return this._wwwFormUrlEncode(bodyObj);
 | 
| +      }
 | 
| +      return body;
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * @param {Object} object The object to encode as x-www-form-urlencoded.
 | 
| +     * @return {string} .
 | 
| +     */
 | 
| +    _wwwFormUrlEncode: function(object) {
 | 
| +      if (!object) {
 | 
| +        return '';
 | 
| +      }
 | 
| +      var pieces = [];
 | 
| +      Object.keys(object).forEach(function(key) {
 | 
| +        // TODO(rictic): handle array values here, in a consistent way with
 | 
| +        //   iron-ajax params.
 | 
| +        pieces.push(
 | 
| +            this._wwwFormUrlEncodePiece(key) + '=' +
 | 
| +            this._wwwFormUrlEncodePiece(object[key]));
 | 
| +      }, this);
 | 
| +      return pieces.join('&');
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * @param {*} str A key or value to encode as x-www-form-urlencoded.
 | 
| +     * @return {string} .
 | 
| +     */
 | 
| +    _wwwFormUrlEncodePiece: function(str) {
 | 
| +      // Spec says to normalize newlines to \r\n and replace %20 spaces with +.
 | 
| +      // jQuery does this as well, so this is likely to be widely compatible.
 | 
| +      if (str === null) {
 | 
| +        return '';
 | 
| +      }
 | 
| +      return encodeURIComponent(str.toString().replace(/\r?\n/g, '\r\n'))
 | 
| +          .replace(/%20/g, '+');
 | 
| +    },
 | 
| +
 | 
| +    /**
 | 
| +     * Updates the status code and status text.
 | 
| +     */
 | 
| +    _updateStatus: function() {
 | 
| +      this._setStatus(this.xhr.status);
 | 
| +      this._setStatusText((this.xhr.statusText === undefined) ? '' : this.xhr.statusText);
 | 
| +    }
 | 
| +  });
 | 
| +</script>
 | 
| 
 |