| /* global fetch */ |
| /* global Headers */ |
| import {blob as createBlob, readAsArrayBuffer } from 'pouchdb-binary-utils'; |
| |
| function wrappedFetch() { |
| var wrappedPromise = {}; |
| |
| var promise = new Promise(function (resolve, reject) { |
| wrappedPromise.resolve = resolve; |
| wrappedPromise.reject = reject; |
| }); |
| |
| var args = new Array(arguments.length); |
| |
| for (var i = 0; i < args.length; i++) { |
| args[i] = arguments[i]; |
| } |
| |
| wrappedPromise.promise = promise; |
| |
| Promise.resolve().then(function () { |
| return fetch.apply(null, args); |
| }).then(function (response) { |
| wrappedPromise.resolve(response); |
| }).catch(function (error) { |
| wrappedPromise.reject(error); |
| }); |
| |
| return wrappedPromise; |
| } |
| |
| function fetchRequest(options, callback) { |
| var wrappedPromise, timer, response; |
| |
| var headers = new Headers(); |
| |
| var fetchOptions = { |
| method: options.method, |
| credentials: 'include', |
| headers: headers |
| }; |
| |
| if (options.json) { |
| headers.set('Accept', 'application/json'); |
| headers.set('Content-Type', options.headers['Content-Type'] || |
| 'application/json'); |
| } |
| |
| if (options.body && |
| options.processData && |
| typeof options.body !== 'string') { |
| fetchOptions.body = JSON.stringify(options.body); |
| } else if ('body' in options) { |
| fetchOptions.body = options.body; |
| } else { |
| fetchOptions.body = null; |
| } |
| |
| Object.keys(options.headers).forEach(function (key) { |
| if (options.headers.hasOwnProperty(key)) { |
| headers.set(key, options.headers[key]); |
| } |
| }); |
| |
| wrappedPromise = wrappedFetch(options.url, fetchOptions); |
| |
| if (options.timeout > 0) { |
| timer = setTimeout(function () { |
| wrappedPromise.reject(new Error('Load timeout for resource: ' + |
| options.url)); |
| }, options.timeout); |
| } |
| |
| wrappedPromise.promise.then(function (fetchResponse) { |
| response = { |
| statusCode: fetchResponse.status |
| }; |
| |
| if (options.timeout > 0) { |
| clearTimeout(timer); |
| } |
| |
| if (response.statusCode >= 200 && response.statusCode < 300) { |
| return options.binary ? fetchResponse.blob() : fetchResponse.text(); |
| } |
| |
| return fetchResponse.json(); |
| }).then(function (result) { |
| if (response.statusCode >= 200 && response.statusCode < 300) { |
| callback(null, response, result); |
| } else { |
| result.status = response.statusCode; |
| callback(result); |
| } |
| }).catch(function (error) { |
| if (!error) { |
| // this happens when the listener is canceled |
| error = new Error('canceled'); |
| } |
| callback(error); |
| }); |
| |
| return {abort: wrappedPromise.reject}; |
| } |
| |
| function xhRequest(options, callback) { |
| |
| var xhr, timer; |
| var timedout = false; |
| |
| var abortReq = function () { |
| xhr.abort(); |
| cleanUp(); |
| }; |
| |
| var timeoutReq = function () { |
| timedout = true; |
| xhr.abort(); |
| cleanUp(); |
| }; |
| |
| var ret = {abort: abortReq}; |
| |
| var cleanUp = function () { |
| clearTimeout(timer); |
| ret.abort = function () {}; |
| if (xhr) { |
| xhr.onprogress = undefined; |
| if (xhr.upload) { |
| xhr.upload.onprogress = undefined; |
| } |
| xhr.onreadystatechange = undefined; |
| xhr = undefined; |
| } |
| }; |
| |
| if (options.xhr) { |
| xhr = new options.xhr(); |
| } else { |
| xhr = new XMLHttpRequest(); |
| } |
| |
| try { |
| xhr.open(options.method, options.url); |
| } catch (exception) { |
| return callback(new Error(exception.name || 'Url is invalid')); |
| } |
| |
| xhr.withCredentials = ('withCredentials' in options) ? |
| options.withCredentials : true; |
| |
| if (options.method === 'GET') { |
| delete options.headers['Content-Type']; |
| } else if (options.json) { |
| options.headers.Accept = 'application/json'; |
| options.headers['Content-Type'] = options.headers['Content-Type'] || |
| 'application/json'; |
| if (options.body && |
| options.processData && |
| typeof options.body !== "string") { |
| options.body = JSON.stringify(options.body); |
| } |
| } |
| |
| if (options.binary) { |
| xhr.responseType = 'arraybuffer'; |
| } |
| |
| if (!('body' in options)) { |
| options.body = null; |
| } |
| |
| for (var key in options.headers) { |
| if (options.headers.hasOwnProperty(key)) { |
| xhr.setRequestHeader(key, options.headers[key]); |
| } |
| } |
| |
| if (options.timeout > 0) { |
| timer = setTimeout(timeoutReq, options.timeout); |
| xhr.onprogress = function () { |
| clearTimeout(timer); |
| if (xhr.readyState !== 4) { |
| timer = setTimeout(timeoutReq, options.timeout); |
| } |
| }; |
| if (typeof xhr.upload !== 'undefined') { // does not exist in ie9 |
| xhr.upload.onprogress = xhr.onprogress; |
| } |
| } |
| |
| xhr.onreadystatechange = function () { |
| if (xhr.readyState !== 4) { |
| return; |
| } |
| |
| var response = { |
| statusCode: xhr.status |
| }; |
| |
| if (xhr.status >= 200 && xhr.status < 300) { |
| var data; |
| if (options.binary) { |
| data = createBlob([xhr.response || ''], { |
| type: xhr.getResponseHeader('Content-Type') |
| }); |
| } else { |
| data = xhr.responseText; |
| } |
| callback(null, response, data); |
| } else { |
| var err = {}; |
| if (timedout) { |
| err = new Error('ETIMEDOUT'); |
| err.code = 'ETIMEDOUT'; |
| } else if (typeof xhr.response === 'string' && xhr.response !== '') { |
| try { |
| err = JSON.parse(xhr.response); |
| } catch (e) {} |
| } |
| |
| err.status = xhr.status; |
| |
| callback(err); |
| } |
| cleanUp(); |
| }; |
| |
| if (options.body && (options.body instanceof Blob)) { |
| readAsArrayBuffer(options.body, function (arrayBuffer) { |
| xhr.send(arrayBuffer); |
| }); |
| } else { |
| xhr.send(options.body); |
| } |
| |
| return ret; |
| } |
| |
| function testXhr() { |
| try { |
| new XMLHttpRequest(); |
| return true; |
| } catch (err) { |
| return false; |
| } |
| } |
| |
| var hasXhr = testXhr(); |
| |
| function ajax(options, callback) { |
| if (!process.env.FETCH && (hasXhr || options.xhr)) { |
| return xhRequest(options, callback); |
| } else { |
| return fetchRequest(options, callback); |
| } |
| } |
| |
| export default ajax; |