×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: Javascript
Posted by: Isaac Dettman
Added: Nov 4, 2016 9:50 PM
Views: 7
Fetch Polyfill
  1. (function(self) {
  2.   'use strict';
  3.  
  4.   if (self.fetch) {
  5.     return
  6.   }
  7.  
  8.   var support = {
  9.     searchParams: 'URLSearchParams' in self,
  10.     iterable: 'Symbol' in self && 'iterator' in Symbol,
  11.     blob: 'FileReader' in self && 'Blob' in self && (function() {
  12.       try {
  13.         new Blob()
  14.         return true
  15.       } catch(e) {
  16.         return false
  17.       }
  18.     })(),
  19.     formData: 'FormData' in self,
  20.     arrayBuffer: 'ArrayBuffer' in self
  21.   }
  22.  
  23.   function normalizeName(name) {
  24.     if (typeof name !== 'string') {
  25.       name = String(name)
  26.     }
  27.     if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
  28.       throw new TypeError('Invalid character in header field name')
  29.     }
  30.     return name.toLowerCase()
  31.   }
  32.  
  33.   function normalizeValue(value) {
  34.     if (typeof value !== 'string') {
  35.       value = String(value)
  36.     }
  37.     return value
  38.   }
  39.  
  40.   // Build a destructive iterator for the value list
  41.   function iteratorFor(items) {
  42.     var iterator = {
  43.       next: function() {
  44.         var value = items.shift()
  45.         return {done: value === undefined, value: value}
  46.       }
  47.     }
  48.  
  49.     if (support.iterable) {
  50.       iterator[Symbol.iterator] = function() {
  51.         return iterator
  52.       }
  53.     }
  54.  
  55.     return iterator
  56.   }
  57.  
  58.   function Headers(headers) {
  59.     this.map = {}
  60.  
  61.     if (headers instanceof Headers) {
  62.       headers.forEach(function(value, name) {
  63.         this.append(name, value)
  64.       }, this)
  65.  
  66.     } else if (headers) {
  67.       Object.getOwnPropertyNames(headers).forEach(function(name) {
  68.         this.append(name, headers[name])
  69.       }, this)
  70.     }
  71.   }
  72.  
  73.   Headers.prototype.append = function(name, value) {
  74.     name = normalizeName(name)
  75.     value = normalizeValue(value)
  76.     var list = this.map[name]
  77.     if (!list) {
  78.       list = []
  79.       this.map[name] = list
  80.     }
  81.     list.push(value)
  82.   }
  83.  
  84.   Headers.prototype['delete'] = function(name) {
  85.     delete this.map[normalizeName(name)]
  86.   }
  87.  
  88.   Headers.prototype.get = function(name) {
  89.     var values = this.map[normalizeName(name)]
  90.     return values ? values[0] : null
  91.   }
  92.  
  93.   Headers.prototype.getAll = function(name) {
  94.     return this.map[normalizeName(name)] || []
  95.   }
  96.  
  97.   Headers.prototype.has = function(name) {
  98.     return this.map.hasOwnProperty(normalizeName(name))
  99.   }
  100.  
  101.   Headers.prototype.set = function(name, value) {
  102.     this.map[normalizeName(name)] = [normalizeValue(value)]
  103.   }
  104.  
  105.   Headers.prototype.forEach = function(callback, thisArg) {
  106.     Object.getOwnPropertyNames(this.map).forEach(function(name) {
  107.       this.map[name].forEach(function(value) {
  108.         callback.call(thisArg, value, name, this)
  109.       }, this)
  110.     }, this)
  111.   }
  112.  
  113.   Headers.prototype.keys = function() {
  114.     var items = []
  115.     this.forEach(function(value, name) { items.push(name) })
  116.     return iteratorFor(items)
  117.   }
  118.  
  119.   Headers.prototype.values = function() {
  120.     var items = []
  121.     this.forEach(function(value) { items.push(value) })
  122.     return iteratorFor(items)
  123.   }
  124.  
  125.   Headers.prototype.entries = function() {
  126.     var items = []
  127.     this.forEach(function(value, name) { items.push([name, value]) })
  128.     return iteratorFor(items)
  129.   }
  130.  
  131.   if (support.iterable) {
  132.     Headers.prototype[Symbol.iterator] = Headers.prototype.entries
  133.   }
  134.  
  135.   function consumed(body) {
  136.     if (body.bodyUsed) {
  137.       return Promise.reject(new TypeError('Already read'))
  138.     }
  139.     body.bodyUsed = true
  140.   }
  141.  
  142.   function fileReaderReady(reader) {
  143.     return new Promise(function(resolve, reject) {
  144.       reader.onload = function() {
  145.         resolve(reader.result)
  146.       }
  147.       reader.onerror = function() {
  148.         reject(reader.error)
  149.       }
  150.     })
  151.   }
  152.  
  153.   function readBlobAsArrayBuffer(blob) {
  154.     var reader = new FileReader()
  155.     reader.readAsArrayBuffer(blob)
  156.     return fileReaderReady(reader)
  157.   }
  158.  
  159.   function readBlobAsText(blob) {
  160.     var reader = new FileReader()
  161.     reader.readAsText(blob)
  162.     return fileReaderReady(reader)
  163.   }
  164.  
  165.   function Body() {
  166.     this.bodyUsed = false
  167.  
  168.     this._initBody = function(body) {
  169.       this._bodyInit = body
  170.       if (typeof body === 'string') {
  171.         this._bodyText = body
  172.       } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
  173.         this._bodyBlob = body
  174.       } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
  175.         this._bodyFormData = body
  176.       } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
  177.         this._bodyText = body.toString()
  178.       } else if (!body) {
  179.         this._bodyText = ''
  180.       } else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) {
  181.         // Only support ArrayBuffers for POST method.
  182.         // Receiving ArrayBuffers happens via Blobs, instead.
  183.       } else {
  184.         throw new Error('unsupported BodyInit type')
  185.       }
  186.  
  187.       if (!this.headers.get('content-type')) {
  188.         if (typeof body === 'string') {
  189.           this.headers.set('content-type', 'text/plain;charset=UTF-8')
  190.         } else if (this._bodyBlob && this._bodyBlob.type) {
  191.           this.headers.set('content-type', this._bodyBlob.type)
  192.         } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
  193.           this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
  194.         }
  195.       }
  196.     }
  197.  
  198.     if (support.blob) {
  199.       this.blob = function() {
  200.         var rejected = consumed(this)
  201.         if (rejected) {
  202.           return rejected
  203.         }
  204.  
  205.         if (this._bodyBlob) {
  206.           return Promise.resolve(this._bodyBlob)
  207.         } else if (this._bodyFormData) {
  208.           throw new Error('could not read FormData body as blob')
  209.         } else {
  210.           return Promise.resolve(new Blob([this._bodyText]))
  211.         }
  212.       }
  213.  
  214.       this.arrayBuffer = function() {
  215.         return this.blob().then(readBlobAsArrayBuffer)
  216.       }
  217.  
  218.       this.text = function() {
  219.         var rejected = consumed(this)
  220.         if (rejected) {
  221.           return rejected
  222.         }
  223.  
  224.         if (this._bodyBlob) {
  225.           return readBlobAsText(this._bodyBlob)
  226.         } else if (this._bodyFormData) {
  227.           throw new Error('could not read FormData body as text')
  228.         } else {
  229.           return Promise.resolve(this._bodyText)
  230.         }
  231.       }
  232.     } else {
  233.       this.text = function() {
  234.         var rejected = consumed(this)
  235.         return rejected ? rejected : Promise.resolve(this._bodyText)
  236.       }
  237.     }
  238.  
  239.     if (support.formData) {
  240.       this.formData = function() {
  241.         return this.text().then(decode)
  242.       }
  243.     }
  244.  
  245.     this.json = function() {
  246.       return this.text().then(JSON.parse)
  247.     }
  248.  
  249.     return this
  250.   }
  251.  
  252.   // HTTP methods whose capitalization should be normalized
  253.   var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
  254.  
  255.   function normalizeMethod(method) {
  256.     var upcased = method.toUpperCase()
  257.     return (methods.indexOf(upcased) > -1) ? upcased : method
  258.   }
  259.  
  260.   function Request(input, options) {
  261.     options = options || {}
  262.     var body = options.body
  263.     if (Request.prototype.isPrototypeOf(input)) {
  264.       if (input.bodyUsed) {
  265.         throw new TypeError('Already read')
  266.       }
  267.       this.url = input.url
  268.       this.credentials = input.credentials
  269.       if (!options.headers) {
  270.         this.headers = new Headers(input.headers)
  271.       }
  272.       this.method = input.method
  273.       this.mode = input.mode
  274.       if (!body) {
  275.         body = input._bodyInit
  276.         input.bodyUsed = true
  277.       }
  278.     } else {
  279.       this.url = input
  280.     }
  281.  
  282.     this.credentials = options.credentials || this.credentials || 'omit'
  283.     if (options.headers || !this.headers) {
  284.       this.headers = new Headers(options.headers)
  285.     }
  286.     this.method = normalizeMethod(options.method || this.method || 'GET')
  287.     this.mode = options.mode || this.mode || null
  288.     this.referrer = null
  289.  
  290.     if ((this.method === 'GET' || this.method === 'HEAD') && body) {
  291.       throw new TypeError('Body not allowed for GET or HEAD requests')
  292.     }
  293.     this._initBody(body)
  294.   }
  295.  
  296.   Request.prototype.clone = function() {
  297.     return new Request(this)
  298.   }
  299.  
  300.   function decode(body) {
  301.     var form = new FormData()
  302.     body.trim().split('&').forEach(function(bytes) {
  303.       if (bytes) {
  304.         var split = bytes.split('=')
  305.         var name = split.shift().replace(/\+/g, ' ')
  306.         var value = split.join('=').replace(/\+/g, ' ')
  307.         form.append(decodeURIComponent(name), decodeURIComponent(value))
  308.       }
  309.     })
  310.     return form
  311.   }
  312.  
  313.   function headers(xhr) {
  314.     var head = new Headers()
  315.     var pairs = (xhr.getAllResponseHeaders() || '').trim().split('\n')
  316.     pairs.forEach(function(header) {
  317.       var split = header.trim().split(':')
  318.       var key = split.shift().trim()
  319.       var value = split.join(':').trim()
  320.       head.append(key, value)
  321.     })
  322.     return head
  323.   }
  324.  
  325.   Body.call(Request.prototype)
  326.  
  327.   function Response(bodyInit, options) {
  328.     if (!options) {
  329.       options = {}
  330.     }
  331.  
  332.     this.type = 'default'
  333.     this.status = options.status
  334.     this.ok = this.status >= 200 && this.status < 300
  335.     this.statusText = options.statusText
  336.     this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
  337.     this.url = options.url || ''
  338.     this._initBody(bodyInit)
  339.   }
  340.  
  341.   Body.call(Response.prototype)
  342.  
  343.   Response.prototype.clone = function() {
  344.     return new Response(this._bodyInit, {
  345.       status: this.status,
  346.       statusText: this.statusText,
  347.       headers: new Headers(this.headers),
  348.       url: this.url
  349.     })
  350.   }
  351.  
  352.   Response.error = function() {
  353.     var response = new Response(null, {status: 0, statusText: ''})
  354.     response.type = 'error'
  355.     return response
  356.   }
  357.  
  358.   var redirectStatuses = [301, 302, 303, 307, 308]
  359.  
  360.   Response.redirect = function(url, status) {
  361.     if (redirectStatuses.indexOf(status) === -1) {
  362.       throw new RangeError('Invalid status code')
  363.     }
  364.  
  365.     return new Response(null, {status: status, headers: {location: url}})
  366.   }
  367.  
  368.   self.Headers = Headers
  369.   self.Request = Request
  370.   self.Response = Response
  371.  
  372.   self.fetch = function(input, init) {
  373.     return new Promise(function(resolve, reject) {
  374.       var request
  375.       if (Request.prototype.isPrototypeOf(input) && !init) {
  376.         request = input
  377.       } else {
  378.         request = new Request(input, init)
  379.       }
  380.  
  381.       var xhr = new XMLHttpRequest()
  382.  
  383.       function responseURL() {
  384.         if ('responseURL' in xhr) {
  385.           return xhr.responseURL
  386.         }
  387.  
  388.         // Avoid security warnings on getResponseHeader when not allowed by CORS
  389.         if (/^X-Request-URL:/mi.test(xhr.getAllResponseHeaders())) {
  390.           return xhr.getResponseHeader('X-Request-URL')
  391.         }
  392.  
  393.         return
  394.       }
  395.  
  396.       xhr.onload = function() {
  397.         var options = {
  398.           status: xhr.status,
  399.           statusText: xhr.statusText,
  400.           headers: headers(xhr),
  401.           url: responseURL()
  402.         }
  403.         var body = 'response' in xhr ? xhr.response : xhr.responseText
  404.         resolve(new Response(body, options))
  405.       }
  406.  
  407.       xhr.onerror = function() {
  408.         reject(new TypeError('Network request failed'))
  409.       }
  410.  
  411.       xhr.ontimeout = function() {
  412.         reject(new TypeError('Network request failed'))
  413.       }
  414.  
  415.       xhr.open(request.method, request.url, true)
  416.  
  417.       if (request.credentials === 'include') {
  418.         xhr.withCredentials = true
  419.       }
  420.  
  421.       if ('responseType' in xhr && support.blob) {
  422.         xhr.responseType = 'blob'
  423.       }
  424.  
  425.       request.headers.forEach(function(value, name) {
  426.         xhr.setRequestHeader(name, value)
  427.       })
  428.  
  429.       xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
  430.     })
  431.   }
  432.   self.fetch.polyfill = true
  433. })(typeof self !== 'undefined' ? self : this);