diff --git a/bower.json b/bower.json index 9fb16079..2697ea18 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "vue-resource", "main": "dist/vue-resource.js", "description": "A web request service for Vue.js", - "version": "0.7.4", + "version": "0.8.0", "homepage": "https://github.com/vuejs/vue-resource", "license": "MIT", "ignore": [ diff --git a/build/build.js b/build/build.js index 4d63191f..938764d7 100644 --- a/build/build.js +++ b/build/build.js @@ -11,7 +11,6 @@ var banner = " * Released under the MIT License.\n" + " */\n"; -// Standalone rollup.rollup({ entry: 'src/index.js', plugins: [ @@ -25,50 +24,45 @@ rollup.rollup({ format: 'umd', banner: banner, moduleName: 'VueResource' - }).code); + }).code, bundle); }) -.then(function () { - return write( - 'dist/vue-resource.min.js', - banner + '\n' + uglify.minify('dist/vue-resource.js').code - ); +.then(function (bundle) { + return write('dist/vue-resource.min.js', + banner + '\n' + uglify.minify('dist/vue-resource.js').code, + bundle); }) -.catch(logError); - -// CommonJS -rollup.rollup({ - entry: 'src/index.js', - plugins: [ - babel({ - presets: ['es2015-rollup'] - }) - ] +.then(function (bundle) { + return write('dist/vue-resource.es2015.js', bundle.generate({ + banner: banner, + footer: 'export { Url, Http, Resource };' + }).code, bundle); }) .then(function (bundle) { return write('dist/vue-resource.common.js', bundle.generate({ format: 'cjs', banner: banner - }).code); -}); + }).code, bundle); +}) +.catch(logError); -function write (dest, code) { +function write(dest, code, bundle) { return new Promise(function (resolve, reject) { fs.writeFile(dest, code, function (err) { if (err) return reject(err); console.log(blue(dest) + ' ' + getSize(code)); - resolve(); + resolve(bundle); }); }); } -function getSize (code) { +function getSize(code) { return (code.length / 1024).toFixed(2) + 'kb'; } -function logError (e) { +function logError(e) { console.log(e); } -function blue (str) { +function blue(str) { return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'; } diff --git a/dist/vue-resource.common.js b/dist/vue-resource.common.js index bf8c6785..2e1844bf 100644 --- a/dist/vue-resource.common.js +++ b/dist/vue-resource.common.js @@ -1,5 +1,5 @@ /*! - * vue-resource v0.7.4 + * vue-resource v0.8.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ @@ -13,154 +13,438 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol }; /** - * Utility functions. + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) */ -var util = {}; -var config = {}; -var array = []; -var console = window.console; -function Util (Vue) { - util = Vue.util; - config = Vue.config; -} +var RESOLVED = 0; +var REJECTED = 1; +var PENDING = 2; -var isArray = Array.isArray; +function Promise$2(executor) { -function warn(msg) { - if (console && util.warn && (!config.silent || config.debug)) { - console.warn('[VueResource warn]: ' + msg); - } -} + this.state = PENDING; + this.value = undefined; + this.deferred = []; -function error(msg) { - if (console) { - console.error(msg); + var promise = this; + + try { + executor(function (x) { + promise.resolve(x); + }, function (r) { + promise.reject(r); + }); + } catch (e) { + promise.reject(e); } } -function nextTick(cb, ctx) { - return util.nextTick(cb, ctx); -} +Promise$2.reject = function (r) { + return new Promise$2(function (resolve, reject) { + reject(r); + }); +}; -function trim(str) { - return str.replace(/^\s*|\s*$/g, ''); -} +Promise$2.resolve = function (x) { + return new Promise$2(function (resolve, reject) { + resolve(x); + }); +}; -function toLower(str) { - return str ? str.toLowerCase() : ''; -} +Promise$2.all = function all(iterable) { + return new Promise$2(function (resolve, reject) { + var count = 0, + result = []; -function isString(val) { - return typeof val === 'string'; -} + if (iterable.length === 0) { + resolve(result); + } -function isFunction(val) { - return typeof val === 'function'; -} + function resolver(i) { + return function (x) { + result[i] = x; + count += 1; -function isObject(obj) { - return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; -} + if (count === iterable.length) { + resolve(result); + } + }; + } -function isPlainObject(obj) { - return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; -} + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolver(i), reject); + } + }); +}; -function options(fn, obj, opts) { +Promise$2.race = function race(iterable) { + return new Promise$2(function (resolve, reject) { + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolve, reject); + } + }); +}; - opts = opts || {}; +var p$1 = Promise$2.prototype; - if (isFunction(opts)) { - opts = opts.call(obj); - } +p$1.resolve = function resolve(x) { + var promise = this; - return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); -} + if (promise.state === PENDING) { + if (x === promise) { + throw new TypeError('Promise settled with itself.'); + } -function each(obj, iterator) { + var called = false; - var i, key; + try { + var then = x && x['then']; - if (typeof obj.length == 'number') { - for (i = 0; i < obj.length; i++) { - iterator.call(obj[i], obj[i], i); - } - } else if (isObject(obj)) { - for (key in obj) { - if (obj.hasOwnProperty(key)) { - iterator.call(obj[key], obj[key], key); + if (x !== null && (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && typeof then === 'function') { + then.call(x, function (x) { + if (!called) { + promise.resolve(x); + } + called = true; + }, function (r) { + if (!called) { + promise.reject(r); + } + called = true; + }); + return; + } + } catch (e) { + if (!called) { + promise.reject(e); } + return; } + + promise.state = RESOLVED; + promise.value = x; + promise.notify(); } +}; - return obj; -} +p$1.reject = function reject(reason) { + var promise = this; -function extend(target) { + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } - var args = array.slice.call(arguments, 1); + promise.state = REJECTED; + promise.value = reason; + promise.notify(); + } +}; - args.forEach(function (arg) { - _merge(target, arg); - }); +p$1.notify = function notify() { + var promise = this; - return target; -} + nextTick(function () { + if (promise.state !== PENDING) { + while (promise.deferred.length) { + var deferred = promise.deferred.shift(), + onResolved = deferred[0], + onRejected = deferred[1], + resolve = deferred[2], + reject = deferred[3]; -function merge(target) { + try { + if (promise.state === RESOLVED) { + if (typeof onResolved === 'function') { + resolve(onResolved.call(undefined, promise.value)); + } else { + resolve(promise.value); + } + } else if (promise.state === REJECTED) { + if (typeof onRejected === 'function') { + resolve(onRejected.call(undefined, promise.value)); + } else { + reject(promise.value); + } + } + } catch (e) { + reject(e); + } + } + } + }); +}; - var args = array.slice.call(arguments, 1); +p$1.then = function then(onResolved, onRejected) { + var promise = this; - args.forEach(function (arg) { - _merge(target, arg, true); + return new Promise$2(function (resolve, reject) { + promise.deferred.push([onResolved, onRejected, resolve, reject]); + promise.notify(); }); +}; - return target; -} - -function _merge(target, source, deep) { - for (var key in source) { - if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { - if (isPlainObject(source[key]) && !isPlainObject(target[key])) { - target[key] = {}; - } - if (isArray(source[key]) && !isArray(target[key])) { - target[key] = []; - } - _merge(target[key], source[key], deep); - } else if (source[key] !== undefined) { - target[key] = source[key]; - } - } -} +p$1.catch = function (onRejected) { + return this.then(undefined, onRejected); +}; -function root (options, next) { +var PromiseObj = window.Promise || Promise$2; - var url = next(options); +function Promise$1(executor, context) { - if (isString(options.root) && !url.match(/^(https?:)?\//)) { - url = options.root + '/' + url; + if (executor instanceof PromiseObj) { + this.promise = executor; + } else { + this.promise = new PromiseObj(executor.bind(context)); } - return url; + this.context = context; } -function query (options, next) { +Promise$1.all = function (iterable, context) { + return new Promise$1(PromiseObj.all(iterable), context); +}; - var urlParams = Object.keys(Url.options.params), - query = {}, - url = next(options); +Promise$1.resolve = function (value, context) { + return new Promise$1(PromiseObj.resolve(value), context); +}; - each(options.params, function (value, key) { - if (urlParams.indexOf(key) === -1) { - query[key] = value; - } - }); +Promise$1.reject = function (reason, context) { + return new Promise$1(PromiseObj.reject(reason), context); +}; - query = Url.params(query); +Promise$1.race = function (iterable, context) { + return new Promise$1(PromiseObj.race(iterable), context); +}; - if (query) { +var p = Promise$1.prototype; + +p.bind = function (context) { + this.context = context; + return this; +}; + +p.then = function (fulfilled, rejected) { + + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.then(fulfilled, rejected); + + return this; +}; + +p.catch = function (rejected) { + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.catch(rejected); + + return this; +}; + +p.finally = function (callback) { + + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return PromiseObj.reject(reason); + }); +}; + +p.success = function (callback) { + + warn('The `success` method has been deprecated. Use the `then` method instead.'); + + return this.then(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); +}; + +p.error = function (callback) { + + warn('The `error` method has been deprecated. Use the `catch` method instead.'); + + return this.catch(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); +}; + +p.always = function (callback) { + + warn('The `always` method has been deprecated. Use the `finally` method instead.'); + + var cb = function cb(response) { + return callback.call(this, response.data, response.status, response) || response; + }; + + return this.then(cb, cb); +}; + +var debug = false; +var util = {}; +var array = []; +function Util (Vue) { + util = Vue.util; + debug = Vue.config.debug || !Vue.config.silent; +} + +var isArray = Array.isArray; + +function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } +} + +function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } +} + +function nextTick(cb, ctx) { + return util.nextTick(cb, ctx); +} + +function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); +} + +function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +function isString(val) { + return typeof val === 'string'; +} + +function isFunction(val) { + return typeof val === 'function'; +} + +function isObject(obj) { + return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; +} + +function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} + +function when(value, fulfilled, rejected) { + + var promise = Promise$1.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); +} + +function options(fn, obj, opts) { + + opts = opts || {}; + + if (isFunction(opts)) { + opts = opts.call(obj); + } + + return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); +} + +function each(obj, iterator) { + + var i, key; + + if (typeof obj.length == 'number') { + for (i = 0; i < obj.length; i++) { + iterator.call(obj[i], obj[i], i); + } + } else if (isObject(obj)) { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(obj[key], obj[key], key); + } + } + } + + return obj; +} + +function extend(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg); + }); + + return target; +} + +function merge(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg, true); + }); + + return target; +} + +function _merge(target, source, deep) { + for (var key in source) { + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) { + target[key] = {}; + } + if (isArray(source[key]) && !isArray(target[key])) { + target[key] = []; + } + _merge(target[key], source[key], deep); + } else if (source[key] !== undefined) { + target[key] = source[key]; + } + } +} + +function root (options, next) { + + var url = next(options); + + if (isString(options.root) && !url.match(/^(https?:)?\//)) { + url = options.root + '/' + url; + } + + return url; +} + +function query (options, next) { + + var urlParams = Object.keys(Url.options.params), + query = {}, + url = next(options); + + each(options.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); + + query = Url.params(query); + + if (query) { url += (url.indexOf('?') == -1 ? '?' : '&') + query; } @@ -377,401 +661,123 @@ var el = document.createElement('a'); function Url(url, params) { var self = this || {}, - options = url, - transform; - - if (isString(url)) { - options = { url: url, params: params }; - } - - options = merge({}, Url.options, self.$options, options); - - Url.transforms.forEach(function (handler) { - transform = factory(handler, transform, self.$vm); - }); - - return transform(options); -} - -/** - * Url options. - */ - -Url.options = { - url: '', - root: null, - params: {} -}; - -/** - * Url transforms. - */ - -Url.transforms = [template, legacy, query, root]; - -/** - * Encodes a Url parameter string. - * - * @param {Object} obj - */ - -Url.params = function (obj) { - - var params = [], - escape = encodeURIComponent; - - params.add = function (key, value) { - - if (isFunction(value)) { - value = value(); - } - - if (value === null) { - value = ''; - } - - this.push(escape(key) + '=' + escape(value)); - }; - - serialize(params, obj); - - return params.join('&').replace(/%20/g, '+'); -}; - -/** - * Parse a URL and return its components. - * - * @param {String} url - */ - -Url.parse = function (url) { - - if (ie) { - el.href = url; - url = el.href; - } - - el.href = url; - - return { - href: el.href, - protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', - port: el.port, - host: el.host, - hostname: el.hostname, - pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, - search: el.search ? el.search.replace(/^\?/, '') : '', - hash: el.hash ? el.hash.replace(/^#/, '') : '' - }; -}; - -function factory(handler, next, vm) { - return function (options) { - return handler.call(vm, options, next); - }; -} - -function serialize(params, obj, scope) { - - var array = isArray(obj), - plain = isPlainObject(obj), - hash; - - each(obj, function (value, key) { - - hash = isObject(value) || isArray(value); - - if (scope) { - key = scope + '[' + (plain || hash ? key : '') + ']'; - } - - if (!scope && array) { - params.add(value.name, value.value); - } else if (hash) { - serialize(params, value, key); - } else { - params.add(key, value); - } - }); -} - -/** - * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) - */ - -var RESOLVED = 0; -var REJECTED = 1; -var PENDING = 2; - -function Promise$2(executor) { - - this.state = PENDING; - this.value = undefined; - this.deferred = []; - - var promise = this; - - try { - executor(function (x) { - promise.resolve(x); - }, function (r) { - promise.reject(r); - }); - } catch (e) { - promise.reject(e); - } -} - -Promise$2.reject = function (r) { - return new Promise$2(function (resolve, reject) { - reject(r); - }); -}; - -Promise$2.resolve = function (x) { - return new Promise$2(function (resolve, reject) { - resolve(x); - }); -}; - -Promise$2.all = function all(iterable) { - return new Promise$2(function (resolve, reject) { - var count = 0, - result = []; - - if (iterable.length === 0) { - resolve(result); - } - - function resolver(i) { - return function (x) { - result[i] = x; - count += 1; - - if (count === iterable.length) { - resolve(result); - } - }; - } - - for (var i = 0; i < iterable.length; i += 1) { - Promise$2.resolve(iterable[i]).then(resolver(i), reject); - } - }); -}; - -Promise$2.race = function race(iterable) { - return new Promise$2(function (resolve, reject) { - for (var i = 0; i < iterable.length; i += 1) { - Promise$2.resolve(iterable[i]).then(resolve, reject); - } - }); -}; - -var p$1 = Promise$2.prototype; - -p$1.resolve = function resolve(x) { - var promise = this; - - if (promise.state === PENDING) { - if (x === promise) { - throw new TypeError('Promise settled with itself.'); - } - - var called = false; - - try { - var then = x && x['then']; - - if (x !== null && (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && typeof then === 'function') { - then.call(x, function (x) { - if (!called) { - promise.resolve(x); - } - called = true; - }, function (r) { - if (!called) { - promise.reject(r); - } - called = true; - }); - return; - } - } catch (e) { - if (!called) { - promise.reject(e); - } - return; - } - - promise.state = RESOLVED; - promise.value = x; - promise.notify(); - } -}; - -p$1.reject = function reject(reason) { - var promise = this; - - if (promise.state === PENDING) { - if (reason === promise) { - throw new TypeError('Promise settled with itself.'); - } - - promise.state = REJECTED; - promise.value = reason; - promise.notify(); - } -}; - -p$1.notify = function notify() { - var promise = this; - - nextTick(function () { - if (promise.state !== PENDING) { - while (promise.deferred.length) { - var deferred = promise.deferred.shift(), - onResolved = deferred[0], - onRejected = deferred[1], - resolve = deferred[2], - reject = deferred[3]; - - try { - if (promise.state === RESOLVED) { - if (typeof onResolved === 'function') { - resolve(onResolved.call(undefined, promise.value)); - } else { - resolve(promise.value); - } - } else if (promise.state === REJECTED) { - if (typeof onRejected === 'function') { - resolve(onRejected.call(undefined, promise.value)); - } else { - reject(promise.value); - } - } - } catch (e) { - reject(e); - } - } - } - }); -}; - -p$1.then = function then(onResolved, onRejected) { - var promise = this; - - return new Promise$2(function (resolve, reject) { - promise.deferred.push([onResolved, onRejected, resolve, reject]); - promise.notify(); - }); -}; - -p$1.catch = function (onRejected) { - return this.then(undefined, onRejected); -}; - -var PromiseObj = window.Promise || Promise$2; - -function Promise$1(executor, context) { - - if (executor instanceof PromiseObj) { - this.promise = executor; - } else { - this.promise = new PromiseObj(executor.bind(context)); + options = url, + transform; + + if (isString(url)) { + options = { url: url, params: params }; } - this.context = context; -} + options = merge({}, Url.options, self.$options, options); -Promise$1.all = function (iterable, context) { - return new Promise$1(PromiseObj.all(iterable), context); -}; + Url.transforms.forEach(function (handler) { + transform = factory(handler, transform, self.$vm); + }); -Promise$1.resolve = function (value, context) { - return new Promise$1(PromiseObj.resolve(value), context); -}; + return transform(options); +} -Promise$1.reject = function (reason, context) { - return new Promise$1(PromiseObj.reject(reason), context); -}; +/** + * Url options. + */ -Promise$1.race = function (iterable, context) { - return new Promise$1(PromiseObj.race(iterable), context); +Url.options = { + url: '', + root: null, + params: {} }; -var p = Promise$1.prototype; +/** + * Url transforms. + */ -p.bind = function (context) { - this.context = context; - return this; -}; +Url.transforms = [template, legacy, query, root]; -p.then = function (fulfilled, rejected) { +/** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ - if (fulfilled && fulfilled.bind && this.context) { - fulfilled = fulfilled.bind(this.context); - } +Url.params = function (obj) { - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } + var params = [], + escape = encodeURIComponent; - this.promise = this.promise.then(fulfilled, rejected); + params.add = function (key, value) { - return this; -}; + if (isFunction(value)) { + value = value(); + } -p.catch = function (rejected) { + if (value === null) { + value = ''; + } - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } + this.push(escape(key) + '=' + escape(value)); + }; - this.promise = this.promise.catch(rejected); + serialize(params, obj); - return this; + return params.join('&').replace(/%20/g, '+'); }; -p.finally = function (callback) { +/** + * Parse a URL and return its components. + * + * @param {String} url + */ - return this.then(function (value) { - callback.call(this); - return value; - }, function (reason) { - callback.call(this); - return PromiseObj.reject(reason); - }); -}; +Url.parse = function (url) { -p.success = function (callback) { + if (ie) { + el.href = url; + url = el.href; + } - warn('The `success` method has been deprecated. Use the `then` method instead.'); + el.href = url; - return this.then(function (response) { - return callback.call(this, response.data, response.status, response) || response; - }); + return { + href: el.href, + protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', + port: el.port, + host: el.host, + hostname: el.hostname, + pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, + search: el.search ? el.search.replace(/^\?/, '') : '', + hash: el.hash ? el.hash.replace(/^#/, '') : '' + }; }; -p.error = function (callback) { +function factory(handler, next, vm) { + return function (options) { + return handler.call(vm, options, next); + }; +} - warn('The `error` method has been deprecated. Use the `catch` method instead.'); +function serialize(params, obj, scope) { - return this.catch(function (response) { - return callback.call(this, response.data, response.status, response) || response; - }); -}; + var array = isArray(obj), + plain = isPlainObject(obj), + hash; -p.always = function (callback) { + each(obj, function (value, key) { - warn('The `always` method has been deprecated. Use the `finally` method instead.'); + hash = isObject(value) || isArray(value); - var cb = function cb(response) { - return callback.call(this, response.data, response.status, response) || response; - }; + if (scope) { + key = scope + '[' + (plain || hash ? key : '') + ']'; + } - return this.then(cb, cb); -}; + if (!scope && array) { + params.add(value.name, value.value); + } else if (hash) { + serialize(params, value, key); + } else { + params.add(key, value); + } + }); +} function xdrClient (request) { return new Promise$1(function (resolve) { @@ -809,25 +815,23 @@ function xdrClient (request) { var originUrl = Url.parse(location.href); var supportCors = 'withCredentials' in new XMLHttpRequest(); -var exports$1 = { - request: function request(_request) { - - if (_request.crossOrigin === null) { - _request.crossOrigin = crossOrigin(_request); - } +function cors (request, next) { - if (_request.crossOrigin) { + if (request.crossOrigin === null) { + request.crossOrigin = crossOrigin(request); + } - if (!supportCors) { - _request.client = xdrClient; - } + if (request.crossOrigin) { - _request.emulateHTTP = false; + if (!supportCors) { + request.client = xdrClient; } - return _request; + request.emulateHTTP = false; } -}; + + next(); +} function crossOrigin(request) { @@ -836,33 +840,28 @@ function crossOrigin(request) { return requestUrl.protocol !== originUrl.protocol || requestUrl.host !== originUrl.host; } -var exports$2 = { - request: function request(_request) { +function mime (request, next) { - if (_request.emulateJSON && isPlainObject(_request.data)) { - _request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; - _request.data = Url.params(_request.data); - } + if (request.emulateJSON && isPlainObject(request.data)) { + request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.data = Url.params(request.data); + } - if (isObject(_request.data) && /FormData/i.test(_request.data.toString())) { - delete _request.headers['Content-Type']; - } + if (isObject(request.data) && /FormData/i.test(request.data.toString())) { + delete request.headers['Content-Type']; + } - if (isPlainObject(_request.data)) { - _request.data = JSON.stringify(_request.data); - } + if (isPlainObject(request.data)) { + request.data = JSON.stringify(request.data); + } - return _request; - }, - response: function response(_response) { + next(function (response) { try { - _response.data = JSON.parse(_response.data); + response.data = JSON.parse(response.data); } catch (e) {} - - return _response; - } -}; + }); +} function jsonpClient (request) { return new Promise$1(function (resolve) { @@ -909,124 +908,69 @@ function jsonpClient (request) { }); } -var exports$3 = { - request: function request(_request) { +function jsonp (request, next) { - if (_request.method == 'JSONP') { - _request.client = jsonpClient; - } - - return _request; + if (request.method == 'JSONP') { + request.client = jsonpClient; } -}; -var exports$4 = { - request: function request(_request) { + next(); +} - if (isFunction(_request.beforeSend)) { - _request.beforeSend.call(this, _request); - } +function before (request, next) { - return _request; + if (isFunction(request.beforeSend)) { + request.beforeSend.call(this, request); } -}; + + next(); +} /** * HTTP method override Interceptor. */ -var exports$5 = { - request: function request(_request) { +function method (request, next) { - if (_request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(_request.method)) { - _request.headers['X-HTTP-Method-Override'] = _request.method; - _request.method = 'POST'; - } - - return _request; + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers['X-HTTP-Method-Override'] = request.method; + request.method = 'POST'; } -}; -var exports$6 = { - request: function request(_request) { + next(); +} - _request.method = _request.method.toUpperCase(); - _request.headers = extend({}, Http.headers.common, !_request.crossOrigin ? Http.headers.custom : {}, Http.headers[_request.method.toLowerCase()], _request.headers); +function header (request, next) { - if (isPlainObject(_request.data) && /^(GET|JSONP)$/i.test(_request.method)) { - extend(_request.params, _request.data); - delete _request.data; - } + request.method = request.method.toUpperCase(); + request.headers = extend({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); - return _request; + if (isPlainObject(request.data) && /^(GET|JSONP)$/i.test(request.method)) { + extend(request.params, request.data); + delete request.data; } -}; + + next(); +} /** * Timeout Interceptor. */ -var exports$7 = function exports() { +function timeout (request, next) { var timeout; - return { - request: function request(_request) { - - if (_request.timeout) { - timeout = setTimeout(function () { - _request.cancel(); - }, _request.timeout); - } - - return _request; - }, - response: function response(_response) { - - clearTimeout(timeout); - - return _response; - } - }; -}; - -function interceptor (handler, vm) { - - return function (client) { - - if (isFunction(handler)) { - handler = handler.call(vm, Promise$1); - } - - return function (request) { - - if (isFunction(handler.request)) { - request = handler.request.call(vm, request); - } - - return when(request, function (request) { - return when(client(request), function (response) { - - if (isFunction(handler.response)) { - response = handler.response.call(vm, response); - } - - return response; - }); - }); - }; - }; -} - -function when(value, fulfilled, rejected) { - - var promise = Promise$1.resolve(value); - - if (arguments.length < 2) { - return promise; + if (request.timeout) { + timeout = setTimeout(function () { + request.cancel(); + }, request.timeout); } - return promise.then(fulfilled, rejected); + next(function (response) { + + clearTimeout(timeout); + }); } function xhrClient (request) { @@ -1047,7 +991,7 @@ function xhrClient (request) { response.data = 'response' in xhr ? xhr.response : xhr.responseText; response.status = xhr.status === 1223 ? 204 : xhr.status; // IE9 status bug response.statusText = trim(xhr.statusText || ''); - response.headers = xhr.getAllResponseHeaders(); + response.allHeaders = xhr.getAllResponseHeaders(); resolve(response); }; @@ -1075,30 +1019,80 @@ function xhrClient (request) { }); } -function Client (request) { +function Client (context) { - var response = (request.client || xhrClient)(request); + var reqHandlers = [sendRequest], + resHandlers = []; - return Promise$1.resolve(response).then(function (response) { + if (!isObject(context)) { + context = null; + } - if (response.headers) { + function Client(request) { + return new Promise$1(function (resolve) { - var headers = parseHeaders(response.headers); + function exec() { + reqHandlers.pop().call(context, request, next); + } - response.headers = function (name) { + function next(response) { + when(response, function (response) { - if (name) { - return headers[toLower(name)]; - } + if (isFunction(response)) { - return headers; - }; - } + resHandlers.unshift(response); + } else if (isObject(response)) { - response.ok = response.status >= 200 && response.status < 300; + processResponse(response); - return response; - }); + resHandlers.forEach(function (handler) { + handler.call(context, response); + }); + + resolve(response); + + return; + } + + exec(); + }); + } + + exec(); + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; +} + +function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + + resolve(client(request)); +} + +function processResponse(response) { + + var headers = response.headers || response.allHeaders; + + if (isString(headers)) { + headers = parseHeaders(headers); + } + + if (isObject(headers)) { + response.headers = function (name) { + return name ? headers[toLower(name)] : headers; + }; + } + + response.ok = response.status >= 200 && response.status < 300; + + return response; } function parseHeaders(str) { @@ -1108,26 +1102,24 @@ function parseHeaders(str) { name, i; - if (isString(str)) { - each(str.split('\n'), function (row) { + each(str.split('\n'), function (row) { - i = row.indexOf(':'); - name = trim(toLower(row.slice(0, i))); - value = trim(row.slice(i + 1)); + i = row.indexOf(':'); + name = trim(toLower(row.slice(0, i))); + value = trim(row.slice(i + 1)); - if (headers[name]) { + if (headers[name]) { - if (isArray(headers[name])) { - headers[name].push(value); - } else { - headers[name] = [headers[name], value]; - } + if (isArray(headers[name])) { + headers[name].push(value); } else { - - headers[name] = value; + headers[name] = [headers[name], value]; } - }); - } + } else { + + headers[name] = value; + } + }); return headers; } @@ -1141,17 +1133,17 @@ var jsonType = { 'Content-Type': 'application/json' }; function Http(url, options) { var self = this || {}, - client = Client, + client = Client(self.$vm), request, promise; Http.interceptors.forEach(function (handler) { - client = interceptor(handler, self.$vm)(client); + client.use(handler); }); options = isObject(url) ? url : extend({ url: url }, options); request = merge({}, Http.options, self.$options, options); - promise = client(request).bind(self.$vm).then(function (response) { + promise = client(request).then(function (response) { return response.ok ? response : Promise$1.reject(response); }, function (response) { @@ -1198,7 +1190,7 @@ Http.headers = { custom: { 'X-Requested-With': 'XMLHttpRequest' } }; -Http.interceptors = [exports$4, exports$7, exports$3, exports$5, exports$2, exports$6, exports$1]; +Http.interceptors = [before, timeout, jsonp, method, mime, header, cors]; ['get', 'put', 'post', 'patch', 'delete', 'jsonp'].forEach(function (method) { diff --git a/dist/vue-resource.es2015.js b/dist/vue-resource.es2015.js new file mode 100644 index 00000000..c7383fe3 --- /dev/null +++ b/dist/vue-resource.es2015.js @@ -0,0 +1,1367 @@ +/*! + * vue-resource v0.8.0 + * https://github.com/vuejs/vue-resource + * Released under the MIT License. + */ + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; +}; + +/** + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + */ + +var RESOLVED = 0; +var REJECTED = 1; +var PENDING = 2; + +function Promise$2(executor) { + + this.state = PENDING; + this.value = undefined; + this.deferred = []; + + var promise = this; + + try { + executor(function (x) { + promise.resolve(x); + }, function (r) { + promise.reject(r); + }); + } catch (e) { + promise.reject(e); + } +} + +Promise$2.reject = function (r) { + return new Promise$2(function (resolve, reject) { + reject(r); + }); +}; + +Promise$2.resolve = function (x) { + return new Promise$2(function (resolve, reject) { + resolve(x); + }); +}; + +Promise$2.all = function all(iterable) { + return new Promise$2(function (resolve, reject) { + var count = 0, + result = []; + + if (iterable.length === 0) { + resolve(result); + } + + function resolver(i) { + return function (x) { + result[i] = x; + count += 1; + + if (count === iterable.length) { + resolve(result); + } + }; + } + + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolver(i), reject); + } + }); +}; + +Promise$2.race = function race(iterable) { + return new Promise$2(function (resolve, reject) { + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolve, reject); + } + }); +}; + +var p$1 = Promise$2.prototype; + +p$1.resolve = function resolve(x) { + var promise = this; + + if (promise.state === PENDING) { + if (x === promise) { + throw new TypeError('Promise settled with itself.'); + } + + var called = false; + + try { + var then = x && x['then']; + + if (x !== null && (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && typeof then === 'function') { + then.call(x, function (x) { + if (!called) { + promise.resolve(x); + } + called = true; + }, function (r) { + if (!called) { + promise.reject(r); + } + called = true; + }); + return; + } + } catch (e) { + if (!called) { + promise.reject(e); + } + return; + } + + promise.state = RESOLVED; + promise.value = x; + promise.notify(); + } +}; + +p$1.reject = function reject(reason) { + var promise = this; + + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } + + promise.state = REJECTED; + promise.value = reason; + promise.notify(); + } +}; + +p$1.notify = function notify() { + var promise = this; + + nextTick(function () { + if (promise.state !== PENDING) { + while (promise.deferred.length) { + var deferred = promise.deferred.shift(), + onResolved = deferred[0], + onRejected = deferred[1], + resolve = deferred[2], + reject = deferred[3]; + + try { + if (promise.state === RESOLVED) { + if (typeof onResolved === 'function') { + resolve(onResolved.call(undefined, promise.value)); + } else { + resolve(promise.value); + } + } else if (promise.state === REJECTED) { + if (typeof onRejected === 'function') { + resolve(onRejected.call(undefined, promise.value)); + } else { + reject(promise.value); + } + } + } catch (e) { + reject(e); + } + } + } + }); +}; + +p$1.then = function then(onResolved, onRejected) { + var promise = this; + + return new Promise$2(function (resolve, reject) { + promise.deferred.push([onResolved, onRejected, resolve, reject]); + promise.notify(); + }); +}; + +p$1.catch = function (onRejected) { + return this.then(undefined, onRejected); +}; + +var PromiseObj = window.Promise || Promise$2; + +function Promise$1(executor, context) { + + if (executor instanceof PromiseObj) { + this.promise = executor; + } else { + this.promise = new PromiseObj(executor.bind(context)); + } + + this.context = context; +} + +Promise$1.all = function (iterable, context) { + return new Promise$1(PromiseObj.all(iterable), context); +}; + +Promise$1.resolve = function (value, context) { + return new Promise$1(PromiseObj.resolve(value), context); +}; + +Promise$1.reject = function (reason, context) { + return new Promise$1(PromiseObj.reject(reason), context); +}; + +Promise$1.race = function (iterable, context) { + return new Promise$1(PromiseObj.race(iterable), context); +}; + +var p = Promise$1.prototype; + +p.bind = function (context) { + this.context = context; + return this; +}; + +p.then = function (fulfilled, rejected) { + + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.then(fulfilled, rejected); + + return this; +}; + +p.catch = function (rejected) { + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.catch(rejected); + + return this; +}; + +p.finally = function (callback) { + + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return PromiseObj.reject(reason); + }); +}; + +p.success = function (callback) { + + warn('The `success` method has been deprecated. Use the `then` method instead.'); + + return this.then(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); +}; + +p.error = function (callback) { + + warn('The `error` method has been deprecated. Use the `catch` method instead.'); + + return this.catch(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); +}; + +p.always = function (callback) { + + warn('The `always` method has been deprecated. Use the `finally` method instead.'); + + var cb = function cb(response) { + return callback.call(this, response.data, response.status, response) || response; + }; + + return this.then(cb, cb); +}; + +var debug = false; +var util = {}; +var array = []; +function Util (Vue) { + util = Vue.util; + debug = Vue.config.debug || !Vue.config.silent; +} + +var isArray = Array.isArray; + +function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } +} + +function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } +} + +function nextTick(cb, ctx) { + return util.nextTick(cb, ctx); +} + +function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); +} + +function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +function isString(val) { + return typeof val === 'string'; +} + +function isFunction(val) { + return typeof val === 'function'; +} + +function isObject(obj) { + return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; +} + +function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} + +function when(value, fulfilled, rejected) { + + var promise = Promise$1.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); +} + +function options(fn, obj, opts) { + + opts = opts || {}; + + if (isFunction(opts)) { + opts = opts.call(obj); + } + + return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); +} + +function each(obj, iterator) { + + var i, key; + + if (typeof obj.length == 'number') { + for (i = 0; i < obj.length; i++) { + iterator.call(obj[i], obj[i], i); + } + } else if (isObject(obj)) { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(obj[key], obj[key], key); + } + } + } + + return obj; +} + +function extend(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg); + }); + + return target; +} + +function merge(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg, true); + }); + + return target; +} + +function _merge(target, source, deep) { + for (var key in source) { + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) { + target[key] = {}; + } + if (isArray(source[key]) && !isArray(target[key])) { + target[key] = []; + } + _merge(target[key], source[key], deep); + } else if (source[key] !== undefined) { + target[key] = source[key]; + } + } +} + +function root (options, next) { + + var url = next(options); + + if (isString(options.root) && !url.match(/^(https?:)?\//)) { + url = options.root + '/' + url; + } + + return url; +} + +function query (options, next) { + + var urlParams = Object.keys(Url.options.params), + query = {}, + url = next(options); + + each(options.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); + + query = Url.params(query); + + if (query) { + url += (url.indexOf('?') == -1 ? '?' : '&') + query; + } + + return url; +} + +function legacy (options, next) { + + var variables = [], + url = next(options); + + url = url.replace(/(\/?):([a-z]\w*)/gi, function (match, slash, name) { + + warn('The `:' + name + '` parameter syntax has been deprecated. Use the `{' + name + '}` syntax instead.'); + + if (options.params[name]) { + variables.push(name); + return slash + encodeUriSegment(options.params[name]); + } + + return ''; + }); + + variables.forEach(function (key) { + delete options.params[key]; + }); + + return url; +} + +function encodeUriSegment(value) { + + return encodeUriQuery(value, true).replace(/%26/gi, '&').replace(/%3D/gi, '=').replace(/%2B/gi, '+'); +} + +function encodeUriQuery(value, spaces) { + + return encodeURIComponent(value).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, spaces ? '%20' : '+'); +} + +/** + * URL Template v2.0.6 (https://github.com/bramstein/url-template) + */ + +function expand(url, params, variables) { + + var tmpl = parse(url), + expanded = tmpl.expand(params); + + if (variables) { + variables.push.apply(variables, tmpl.vars); + } + + return expanded; +} + +function parse(template) { + + var operators = ['+', '#', '.', '/', ';', '?', '&'], + variables = []; + + return { + vars: variables, + expand: function expand(context) { + return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) { + if (expression) { + + var operator = null, + values = []; + + if (operators.indexOf(expression.charAt(0)) !== -1) { + operator = expression.charAt(0); + expression = expression.substr(1); + } + + expression.split(/,/g).forEach(function (variable) { + var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); + values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); + variables.push(tmp[1]); + }); + + if (operator && operator !== '+') { + + var separator = ','; + + if (operator === '?') { + separator = '&'; + } else if (operator !== '#') { + separator = operator; + } + + return (values.length !== 0 ? operator : '') + values.join(separator); + } else { + return values.join(','); + } + } else { + return encodeReserved(literal); + } + }); + } + }; +} + +function getValues(context, operator, key, modifier) { + + var value = context[key], + result = []; + + if (isDefined(value) && value !== '') { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + value = value.toString(); + + if (modifier && modifier !== '*') { + value = value.substring(0, parseInt(modifier, 10)); + } + + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + } else { + if (modifier === '*') { + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + result.push(encodeValue(operator, value[k], k)); + } + }); + } + } else { + var tmp = []; + + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + tmp.push(encodeValue(operator, value)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + tmp.push(encodeURIComponent(k)); + tmp.push(encodeValue(operator, value[k].toString())); + } + }); + } + + if (isKeyOperator(operator)) { + result.push(encodeURIComponent(key) + '=' + tmp.join(',')); + } else if (tmp.length !== 0) { + result.push(tmp.join(',')); + } + } + } + } else { + if (operator === ';') { + result.push(encodeURIComponent(key)); + } else if (value === '' && (operator === '&' || operator === '?')) { + result.push(encodeURIComponent(key) + '='); + } else if (value === '') { + result.push(''); + } + } + + return result; +} + +function isDefined(value) { + return value !== undefined && value !== null; +} + +function isKeyOperator(operator) { + return operator === ';' || operator === '&' || operator === '?'; +} + +function encodeValue(operator, value, key) { + + value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); + + if (key) { + return encodeURIComponent(key) + '=' + value; + } else { + return value; + } +} + +function encodeReserved(str) { + return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { + if (!/%[0-9A-Fa-f]/.test(part)) { + part = encodeURI(part); + } + return part; + }).join(''); +} + +function template (options) { + + var variables = [], + url = expand(options.url, options.params, variables); + + variables.forEach(function (key) { + delete options.params[key]; + }); + + return url; +} + +/** + * Service for URL templating. + */ + +var ie = document.documentMode; +var el = document.createElement('a'); + +function Url(url, params) { + + var self = this || {}, + options = url, + transform; + + if (isString(url)) { + options = { url: url, params: params }; + } + + options = merge({}, Url.options, self.$options, options); + + Url.transforms.forEach(function (handler) { + transform = factory(handler, transform, self.$vm); + }); + + return transform(options); +} + +/** + * Url options. + */ + +Url.options = { + url: '', + root: null, + params: {} +}; + +/** + * Url transforms. + */ + +Url.transforms = [template, legacy, query, root]; + +/** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ + +Url.params = function (obj) { + + var params = [], + escape = encodeURIComponent; + + params.add = function (key, value) { + + if (isFunction(value)) { + value = value(); + } + + if (value === null) { + value = ''; + } + + this.push(escape(key) + '=' + escape(value)); + }; + + serialize(params, obj); + + return params.join('&').replace(/%20/g, '+'); +}; + +/** + * Parse a URL and return its components. + * + * @param {String} url + */ + +Url.parse = function (url) { + + if (ie) { + el.href = url; + url = el.href; + } + + el.href = url; + + return { + href: el.href, + protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', + port: el.port, + host: el.host, + hostname: el.hostname, + pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, + search: el.search ? el.search.replace(/^\?/, '') : '', + hash: el.hash ? el.hash.replace(/^#/, '') : '' + }; +}; + +function factory(handler, next, vm) { + return function (options) { + return handler.call(vm, options, next); + }; +} + +function serialize(params, obj, scope) { + + var array = isArray(obj), + plain = isPlainObject(obj), + hash; + + each(obj, function (value, key) { + + hash = isObject(value) || isArray(value); + + if (scope) { + key = scope + '[' + (plain || hash ? key : '') + ']'; + } + + if (!scope && array) { + params.add(value.name, value.value); + } else if (hash) { + serialize(params, value, key); + } else { + params.add(key, value); + } + }); +} + +function xdrClient (request) { + return new Promise$1(function (resolve) { + + var xdr = new XDomainRequest(), + response = { request: request }, + handler; + + request.cancel = function () { + xdr.abort(); + }; + + xdr.open(request.method, Url(request), true); + + handler = function handler(event) { + + response.data = xdr.responseText; + response.status = xdr.status; + response.statusText = xdr.statusText || ''; + + resolve(response); + }; + + xdr.timeout = 0; + xdr.onload = handler; + xdr.onabort = handler; + xdr.onerror = handler; + xdr.ontimeout = function () {}; + xdr.onprogress = function () {}; + + xdr.send(request.data); + }); +} + +var originUrl = Url.parse(location.href); +var supportCors = 'withCredentials' in new XMLHttpRequest(); + +function cors (request, next) { + + if (request.crossOrigin === null) { + request.crossOrigin = crossOrigin(request); + } + + if (request.crossOrigin) { + + if (!supportCors) { + request.client = xdrClient; + } + + request.emulateHTTP = false; + } + + next(); +} + +function crossOrigin(request) { + + var requestUrl = Url.parse(Url(request)); + + return requestUrl.protocol !== originUrl.protocol || requestUrl.host !== originUrl.host; +} + +function mime (request, next) { + + if (request.emulateJSON && isPlainObject(request.data)) { + request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.data = Url.params(request.data); + } + + if (isObject(request.data) && /FormData/i.test(request.data.toString())) { + delete request.headers['Content-Type']; + } + + if (isPlainObject(request.data)) { + request.data = JSON.stringify(request.data); + } + + next(function (response) { + + try { + response.data = JSON.parse(response.data); + } catch (e) {} + }); +} + +function jsonpClient (request) { + return new Promise$1(function (resolve) { + + var callback = '_jsonp' + Math.random().toString(36).substr(2), + response = { request: request, data: null }, + handler, + script; + + request.params[request.jsonp] = callback; + request.cancel = function () { + handler({ type: 'cancel' }); + }; + + script = document.createElement('script'); + script.src = Url(request); + script.type = 'text/javascript'; + script.async = true; + + window[callback] = function (data) { + response.data = data; + }; + + handler = function handler(event) { + + if (event.type === 'load' && response.data !== null) { + response.status = 200; + } else if (event.type === 'error') { + response.status = 404; + } else { + response.status = 0; + } + + resolve(response); + + delete window[callback]; + document.body.removeChild(script); + }; + + script.onload = handler; + script.onerror = handler; + + document.body.appendChild(script); + }); +} + +function jsonp (request, next) { + + if (request.method == 'JSONP') { + request.client = jsonpClient; + } + + next(); +} + +function before (request, next) { + + if (isFunction(request.beforeSend)) { + request.beforeSend.call(this, request); + } + + next(); +} + +/** + * HTTP method override Interceptor. + */ + +function method (request, next) { + + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers['X-HTTP-Method-Override'] = request.method; + request.method = 'POST'; + } + + next(); +} + +function header (request, next) { + + request.method = request.method.toUpperCase(); + request.headers = extend({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); + + if (isPlainObject(request.data) && /^(GET|JSONP)$/i.test(request.method)) { + extend(request.params, request.data); + delete request.data; + } + + next(); +} + +/** + * Timeout Interceptor. + */ + +function timeout (request, next) { + + var timeout; + + if (request.timeout) { + timeout = setTimeout(function () { + request.cancel(); + }, request.timeout); + } + + next(function (response) { + + clearTimeout(timeout); + }); +} + +function xhrClient (request) { + return new Promise$1(function (resolve) { + + var xhr = new XMLHttpRequest(), + response = { request: request }, + handler; + + request.cancel = function () { + xhr.abort(); + }; + + xhr.open(request.method, Url(request), true); + + handler = function handler(event) { + + response.data = 'response' in xhr ? xhr.response : xhr.responseText; + response.status = xhr.status === 1223 ? 204 : xhr.status; // IE9 status bug + response.statusText = trim(xhr.statusText || ''); + response.allHeaders = xhr.getAllResponseHeaders(); + + resolve(response); + }; + + xhr.timeout = 0; + xhr.onload = handler; + xhr.onabort = handler; + xhr.onerror = handler; + xhr.ontimeout = function () {}; + xhr.onprogress = function () {}; + + if (isPlainObject(request.xhr)) { + extend(xhr, request.xhr); + } + + if (isPlainObject(request.upload)) { + extend(xhr.upload, request.upload); + } + + each(request.headers || {}, function (value, header) { + xhr.setRequestHeader(header, value); + }); + + xhr.send(request.data); + }); +} + +function Client (context) { + + var reqHandlers = [sendRequest], + resHandlers = []; + + if (!isObject(context)) { + context = null; + } + + function Client(request) { + return new Promise$1(function (resolve) { + + function exec() { + reqHandlers.pop().call(context, request, next); + } + + function next(response) { + when(response, function (response) { + + if (isFunction(response)) { + + resHandlers.unshift(response); + } else if (isObject(response)) { + + processResponse(response); + + resHandlers.forEach(function (handler) { + handler.call(context, response); + }); + + resolve(response); + + return; + } + + exec(); + }); + } + + exec(); + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; +} + +function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + + resolve(client(request)); +} + +function processResponse(response) { + + var headers = response.headers || response.allHeaders; + + if (isString(headers)) { + headers = parseHeaders(headers); + } + + if (isObject(headers)) { + response.headers = function (name) { + return name ? headers[toLower(name)] : headers; + }; + } + + response.ok = response.status >= 200 && response.status < 300; + + return response; +} + +function parseHeaders(str) { + + var headers = {}, + value, + name, + i; + + each(str.split('\n'), function (row) { + + i = row.indexOf(':'); + name = trim(toLower(row.slice(0, i))); + value = trim(row.slice(i + 1)); + + if (headers[name]) { + + if (isArray(headers[name])) { + headers[name].push(value); + } else { + headers[name] = [headers[name], value]; + } + } else { + + headers[name] = value; + } + }); + + return headers; +} + +/** + * Service for sending network requests. + */ + +var jsonType = { 'Content-Type': 'application/json' }; + +function Http(url, options) { + + var self = this || {}, + client = Client(self.$vm), + request, + promise; + + Http.interceptors.forEach(function (handler) { + client.use(handler); + }); + + options = isObject(url) ? url : extend({ url: url }, options); + request = merge({}, Http.options, self.$options, options); + promise = client(request).then(function (response) { + + return response.ok ? response : Promise$1.reject(response); + }, function (response) { + + if (response instanceof Error) { + error(response); + } + + return Promise$1.reject(response); + }); + + if (request.success) { + promise.success(request.success); + } + + if (request.error) { + promise.error(request.error); + } + + return promise; +} + +Http.options = { + method: 'get', + data: '', + params: {}, + headers: {}, + xhr: null, + upload: null, + jsonp: 'callback', + beforeSend: null, + crossOrigin: null, + emulateHTTP: false, + emulateJSON: false, + timeout: 0 +}; + +Http.headers = { + put: jsonType, + post: jsonType, + patch: jsonType, + delete: jsonType, + common: { 'Accept': 'application/json, text/plain, */*' }, + custom: { 'X-Requested-With': 'XMLHttpRequest' } +}; + +Http.interceptors = [before, timeout, jsonp, method, mime, header, cors]; + +['get', 'put', 'post', 'patch', 'delete', 'jsonp'].forEach(function (method) { + + Http[method] = function (url, data, success, options) { + + if (isFunction(data)) { + options = success; + success = data; + data = undefined; + } + + if (isObject(success)) { + options = success; + success = undefined; + } + + return this(url, extend({ method: method, data: data, success: success }, options)); + }; +}); + +function Resource(url, params, actions, options) { + + var self = this || {}, + resource = {}; + + actions = extend({}, Resource.actions, actions); + + each(actions, function (action, name) { + + action = merge({ url: url, params: params || {} }, options, action); + + resource[name] = function () { + return (self.$http || Http)(opts(action, arguments)); + }; + }); + + return resource; +} + +function opts(action, args) { + + var options = extend({}, action), + params = {}, + data, + success, + error; + + switch (args.length) { + + case 4: + + error = args[3]; + success = args[2]; + + case 3: + case 2: + + if (isFunction(args[1])) { + + if (isFunction(args[0])) { + + success = args[0]; + error = args[1]; + + break; + } + + success = args[1]; + error = args[2]; + } else { + + params = args[0]; + data = args[1]; + success = args[2]; + + break; + } + + case 1: + + if (isFunction(args[0])) { + success = args[0]; + } else if (/^(POST|PUT|PATCH)$/i.test(options.method)) { + data = args[0]; + } else { + params = args[0]; + } + + break; + + case 0: + + break; + + default: + + throw 'Expected up to 4 arguments [params, data, success, error], got ' + args.length + ' arguments'; + } + + options.data = data; + options.params = extend({}, options.params, params); + + if (success) { + options.success = success; + } + + if (error) { + options.error = error; + } + + return options; +} + +Resource.actions = { + + get: { method: 'GET' }, + save: { method: 'POST' }, + query: { method: 'GET' }, + update: { method: 'PUT' }, + remove: { method: 'DELETE' }, + delete: { method: 'DELETE' } + +}; + +function plugin(Vue) { + + if (plugin.installed) { + return; + } + + Util(Vue); + + Vue.url = Url; + Vue.http = Http; + Vue.resource = Resource; + Vue.Promise = Promise$1; + + Object.defineProperties(Vue.prototype, { + + $url: { + get: function get() { + return options(Vue.url, this, this.$options.url); + } + }, + + $http: { + get: function get() { + return options(Vue.http, this, this.$options.http); + } + }, + + $resource: { + get: function get() { + return Vue.resource.bind(this); + } + }, + + $promise: { + get: function get() { + var _this = this; + + return function (executor) { + return new Vue.Promise(executor, _this); + }; + } + } + + }); +} + +if (typeof window !== 'undefined' && window.Vue) { + window.Vue.use(plugin); +} + +export default plugin; +export { Url, Http, Resource }; \ No newline at end of file diff --git a/dist/vue-resource.js b/dist/vue-resource.js index 266c93f2..c23048b9 100644 --- a/dist/vue-resource.js +++ b/dist/vue-resource.js @@ -1,5 +1,5 @@ /*! - * vue-resource v0.7.4 + * vue-resource v0.8.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ @@ -17,154 +17,438 @@ }; /** - * Utility functions. + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) */ - var util = {}; - var config = {}; - var array = []; - var console = window.console; - function Util (Vue) { - util = Vue.util; - config = Vue.config; - } + var RESOLVED = 0; + var REJECTED = 1; + var PENDING = 2; - var isArray = Array.isArray; + function Promise$2(executor) { - function warn(msg) { - if (console && util.warn && (!config.silent || config.debug)) { - console.warn('[VueResource warn]: ' + msg); - } - } + this.state = PENDING; + this.value = undefined; + this.deferred = []; - function error(msg) { - if (console) { - console.error(msg); + var promise = this; + + try { + executor(function (x) { + promise.resolve(x); + }, function (r) { + promise.reject(r); + }); + } catch (e) { + promise.reject(e); } } - function nextTick(cb, ctx) { - return util.nextTick(cb, ctx); - } + Promise$2.reject = function (r) { + return new Promise$2(function (resolve, reject) { + reject(r); + }); + }; - function trim(str) { - return str.replace(/^\s*|\s*$/g, ''); - } + Promise$2.resolve = function (x) { + return new Promise$2(function (resolve, reject) { + resolve(x); + }); + }; - function toLower(str) { - return str ? str.toLowerCase() : ''; - } + Promise$2.all = function all(iterable) { + return new Promise$2(function (resolve, reject) { + var count = 0, + result = []; - function isString(val) { - return typeof val === 'string'; - } + if (iterable.length === 0) { + resolve(result); + } - function isFunction(val) { - return typeof val === 'function'; - } + function resolver(i) { + return function (x) { + result[i] = x; + count += 1; - function isObject(obj) { - return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; - } + if (count === iterable.length) { + resolve(result); + } + }; + } - function isPlainObject(obj) { - return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; - } + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolver(i), reject); + } + }); + }; - function options(fn, obj, opts) { + Promise$2.race = function race(iterable) { + return new Promise$2(function (resolve, reject) { + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolve, reject); + } + }); + }; - opts = opts || {}; + var p$1 = Promise$2.prototype; - if (isFunction(opts)) { - opts = opts.call(obj); - } + p$1.resolve = function resolve(x) { + var promise = this; - return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); - } + if (promise.state === PENDING) { + if (x === promise) { + throw new TypeError('Promise settled with itself.'); + } - function each(obj, iterator) { + var called = false; - var i, key; + try { + var then = x && x['then']; - if (typeof obj.length == 'number') { - for (i = 0; i < obj.length; i++) { - iterator.call(obj[i], obj[i], i); - } - } else if (isObject(obj)) { - for (key in obj) { - if (obj.hasOwnProperty(key)) { - iterator.call(obj[key], obj[key], key); + if (x !== null && (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && typeof then === 'function') { + then.call(x, function (x) { + if (!called) { + promise.resolve(x); + } + called = true; + }, function (r) { + if (!called) { + promise.reject(r); + } + called = true; + }); + return; + } + } catch (e) { + if (!called) { + promise.reject(e); } + return; } + + promise.state = RESOLVED; + promise.value = x; + promise.notify(); } + }; - return obj; - } + p$1.reject = function reject(reason) { + var promise = this; - function extend(target) { + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } - var args = array.slice.call(arguments, 1); + promise.state = REJECTED; + promise.value = reason; + promise.notify(); + } + }; - args.forEach(function (arg) { - _merge(target, arg); - }); + p$1.notify = function notify() { + var promise = this; - return target; - } + nextTick(function () { + if (promise.state !== PENDING) { + while (promise.deferred.length) { + var deferred = promise.deferred.shift(), + onResolved = deferred[0], + onRejected = deferred[1], + resolve = deferred[2], + reject = deferred[3]; - function merge(target) { + try { + if (promise.state === RESOLVED) { + if (typeof onResolved === 'function') { + resolve(onResolved.call(undefined, promise.value)); + } else { + resolve(promise.value); + } + } else if (promise.state === REJECTED) { + if (typeof onRejected === 'function') { + resolve(onRejected.call(undefined, promise.value)); + } else { + reject(promise.value); + } + } + } catch (e) { + reject(e); + } + } + } + }); + }; - var args = array.slice.call(arguments, 1); + p$1.then = function then(onResolved, onRejected) { + var promise = this; - args.forEach(function (arg) { - _merge(target, arg, true); + return new Promise$2(function (resolve, reject) { + promise.deferred.push([onResolved, onRejected, resolve, reject]); + promise.notify(); }); + }; - return target; - } - - function _merge(target, source, deep) { - for (var key in source) { - if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { - if (isPlainObject(source[key]) && !isPlainObject(target[key])) { - target[key] = {}; - } - if (isArray(source[key]) && !isArray(target[key])) { - target[key] = []; - } - _merge(target[key], source[key], deep); - } else if (source[key] !== undefined) { - target[key] = source[key]; - } - } - } + p$1.catch = function (onRejected) { + return this.then(undefined, onRejected); + }; - function root (options, next) { + var PromiseObj = window.Promise || Promise$2; - var url = next(options); + function Promise$1(executor, context) { - if (isString(options.root) && !url.match(/^(https?:)?\//)) { - url = options.root + '/' + url; + if (executor instanceof PromiseObj) { + this.promise = executor; + } else { + this.promise = new PromiseObj(executor.bind(context)); } - return url; + this.context = context; } - function query (options, next) { + Promise$1.all = function (iterable, context) { + return new Promise$1(PromiseObj.all(iterable), context); + }; - var urlParams = Object.keys(Url.options.params), - query = {}, - url = next(options); + Promise$1.resolve = function (value, context) { + return new Promise$1(PromiseObj.resolve(value), context); + }; - each(options.params, function (value, key) { - if (urlParams.indexOf(key) === -1) { - query[key] = value; - } - }); + Promise$1.reject = function (reason, context) { + return new Promise$1(PromiseObj.reject(reason), context); + }; - query = Url.params(query); + Promise$1.race = function (iterable, context) { + return new Promise$1(PromiseObj.race(iterable), context); + }; - if (query) { + var p = Promise$1.prototype; + + p.bind = function (context) { + this.context = context; + return this; + }; + + p.then = function (fulfilled, rejected) { + + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.then(fulfilled, rejected); + + return this; + }; + + p.catch = function (rejected) { + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + this.promise = this.promise.catch(rejected); + + return this; + }; + + p.finally = function (callback) { + + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return PromiseObj.reject(reason); + }); + }; + + p.success = function (callback) { + + warn('The `success` method has been deprecated. Use the `then` method instead.'); + + return this.then(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); + }; + + p.error = function (callback) { + + warn('The `error` method has been deprecated. Use the `catch` method instead.'); + + return this.catch(function (response) { + return callback.call(this, response.data, response.status, response) || response; + }); + }; + + p.always = function (callback) { + + warn('The `always` method has been deprecated. Use the `finally` method instead.'); + + var cb = function cb(response) { + return callback.call(this, response.data, response.status, response) || response; + }; + + return this.then(cb, cb); + }; + + var debug = false; + var util = {}; + var array = []; + function Util (Vue) { + util = Vue.util; + debug = Vue.config.debug || !Vue.config.silent; + } + + var isArray = Array.isArray; + + function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } + } + + function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } + } + + function nextTick(cb, ctx) { + return util.nextTick(cb, ctx); + } + + function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); + } + + function toLower(str) { + return str ? str.toLowerCase() : ''; + } + + function isString(val) { + return typeof val === 'string'; + } + + function isFunction(val) { + return typeof val === 'function'; + } + + function isObject(obj) { + return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; + } + + function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; + } + + function when(value, fulfilled, rejected) { + + var promise = Promise$1.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); + } + + function options(fn, obj, opts) { + + opts = opts || {}; + + if (isFunction(opts)) { + opts = opts.call(obj); + } + + return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); + } + + function each(obj, iterator) { + + var i, key; + + if (typeof obj.length == 'number') { + for (i = 0; i < obj.length; i++) { + iterator.call(obj[i], obj[i], i); + } + } else if (isObject(obj)) { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(obj[key], obj[key], key); + } + } + } + + return obj; + } + + function extend(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg); + }); + + return target; + } + + function merge(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (arg) { + _merge(target, arg, true); + }); + + return target; + } + + function _merge(target, source, deep) { + for (var key in source) { + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) { + target[key] = {}; + } + if (isArray(source[key]) && !isArray(target[key])) { + target[key] = []; + } + _merge(target[key], source[key], deep); + } else if (source[key] !== undefined) { + target[key] = source[key]; + } + } + } + + function root (options, next) { + + var url = next(options); + + if (isString(options.root) && !url.match(/^(https?:)?\//)) { + url = options.root + '/' + url; + } + + return url; + } + + function query (options, next) { + + var urlParams = Object.keys(Url.options.params), + query = {}, + url = next(options); + + each(options.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); + + query = Url.params(query); + + if (query) { url += (url.indexOf('?') == -1 ? '?' : '&') + query; } @@ -381,401 +665,123 @@ function Url(url, params) { var self = this || {}, - options = url, - transform; - - if (isString(url)) { - options = { url: url, params: params }; - } - - options = merge({}, Url.options, self.$options, options); - - Url.transforms.forEach(function (handler) { - transform = factory(handler, transform, self.$vm); - }); - - return transform(options); - } - - /** - * Url options. - */ - - Url.options = { - url: '', - root: null, - params: {} - }; - - /** - * Url transforms. - */ - - Url.transforms = [template, legacy, query, root]; - - /** - * Encodes a Url parameter string. - * - * @param {Object} obj - */ - - Url.params = function (obj) { - - var params = [], - escape = encodeURIComponent; - - params.add = function (key, value) { - - if (isFunction(value)) { - value = value(); - } - - if (value === null) { - value = ''; - } - - this.push(escape(key) + '=' + escape(value)); - }; - - serialize(params, obj); - - return params.join('&').replace(/%20/g, '+'); - }; - - /** - * Parse a URL and return its components. - * - * @param {String} url - */ - - Url.parse = function (url) { - - if (ie) { - el.href = url; - url = el.href; - } - - el.href = url; - - return { - href: el.href, - protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', - port: el.port, - host: el.host, - hostname: el.hostname, - pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, - search: el.search ? el.search.replace(/^\?/, '') : '', - hash: el.hash ? el.hash.replace(/^#/, '') : '' - }; - }; - - function factory(handler, next, vm) { - return function (options) { - return handler.call(vm, options, next); - }; - } - - function serialize(params, obj, scope) { - - var array = isArray(obj), - plain = isPlainObject(obj), - hash; - - each(obj, function (value, key) { - - hash = isObject(value) || isArray(value); - - if (scope) { - key = scope + '[' + (plain || hash ? key : '') + ']'; - } - - if (!scope && array) { - params.add(value.name, value.value); - } else if (hash) { - serialize(params, value, key); - } else { - params.add(key, value); - } - }); - } - - /** - * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) - */ - - var RESOLVED = 0; - var REJECTED = 1; - var PENDING = 2; - - function Promise$2(executor) { - - this.state = PENDING; - this.value = undefined; - this.deferred = []; - - var promise = this; - - try { - executor(function (x) { - promise.resolve(x); - }, function (r) { - promise.reject(r); - }); - } catch (e) { - promise.reject(e); - } - } - - Promise$2.reject = function (r) { - return new Promise$2(function (resolve, reject) { - reject(r); - }); - }; - - Promise$2.resolve = function (x) { - return new Promise$2(function (resolve, reject) { - resolve(x); - }); - }; - - Promise$2.all = function all(iterable) { - return new Promise$2(function (resolve, reject) { - var count = 0, - result = []; - - if (iterable.length === 0) { - resolve(result); - } - - function resolver(i) { - return function (x) { - result[i] = x; - count += 1; - - if (count === iterable.length) { - resolve(result); - } - }; - } - - for (var i = 0; i < iterable.length; i += 1) { - Promise$2.resolve(iterable[i]).then(resolver(i), reject); - } - }); - }; - - Promise$2.race = function race(iterable) { - return new Promise$2(function (resolve, reject) { - for (var i = 0; i < iterable.length; i += 1) { - Promise$2.resolve(iterable[i]).then(resolve, reject); - } - }); - }; - - var p$1 = Promise$2.prototype; - - p$1.resolve = function resolve(x) { - var promise = this; - - if (promise.state === PENDING) { - if (x === promise) { - throw new TypeError('Promise settled with itself.'); - } - - var called = false; - - try { - var then = x && x['then']; - - if (x !== null && (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && typeof then === 'function') { - then.call(x, function (x) { - if (!called) { - promise.resolve(x); - } - called = true; - }, function (r) { - if (!called) { - promise.reject(r); - } - called = true; - }); - return; - } - } catch (e) { - if (!called) { - promise.reject(e); - } - return; - } - - promise.state = RESOLVED; - promise.value = x; - promise.notify(); - } - }; - - p$1.reject = function reject(reason) { - var promise = this; - - if (promise.state === PENDING) { - if (reason === promise) { - throw new TypeError('Promise settled with itself.'); - } - - promise.state = REJECTED; - promise.value = reason; - promise.notify(); - } - }; - - p$1.notify = function notify() { - var promise = this; - - nextTick(function () { - if (promise.state !== PENDING) { - while (promise.deferred.length) { - var deferred = promise.deferred.shift(), - onResolved = deferred[0], - onRejected = deferred[1], - resolve = deferred[2], - reject = deferred[3]; - - try { - if (promise.state === RESOLVED) { - if (typeof onResolved === 'function') { - resolve(onResolved.call(undefined, promise.value)); - } else { - resolve(promise.value); - } - } else if (promise.state === REJECTED) { - if (typeof onRejected === 'function') { - resolve(onRejected.call(undefined, promise.value)); - } else { - reject(promise.value); - } - } - } catch (e) { - reject(e); - } - } - } - }); - }; - - p$1.then = function then(onResolved, onRejected) { - var promise = this; - - return new Promise$2(function (resolve, reject) { - promise.deferred.push([onResolved, onRejected, resolve, reject]); - promise.notify(); - }); - }; - - p$1.catch = function (onRejected) { - return this.then(undefined, onRejected); - }; - - var PromiseObj = window.Promise || Promise$2; - - function Promise$1(executor, context) { - - if (executor instanceof PromiseObj) { - this.promise = executor; - } else { - this.promise = new PromiseObj(executor.bind(context)); + options = url, + transform; + + if (isString(url)) { + options = { url: url, params: params }; } - this.context = context; - } + options = merge({}, Url.options, self.$options, options); - Promise$1.all = function (iterable, context) { - return new Promise$1(PromiseObj.all(iterable), context); - }; + Url.transforms.forEach(function (handler) { + transform = factory(handler, transform, self.$vm); + }); - Promise$1.resolve = function (value, context) { - return new Promise$1(PromiseObj.resolve(value), context); - }; + return transform(options); + } - Promise$1.reject = function (reason, context) { - return new Promise$1(PromiseObj.reject(reason), context); - }; + /** + * Url options. + */ - Promise$1.race = function (iterable, context) { - return new Promise$1(PromiseObj.race(iterable), context); + Url.options = { + url: '', + root: null, + params: {} }; - var p = Promise$1.prototype; + /** + * Url transforms. + */ - p.bind = function (context) { - this.context = context; - return this; - }; + Url.transforms = [template, legacy, query, root]; - p.then = function (fulfilled, rejected) { + /** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ - if (fulfilled && fulfilled.bind && this.context) { - fulfilled = fulfilled.bind(this.context); - } + Url.params = function (obj) { - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } + var params = [], + escape = encodeURIComponent; - this.promise = this.promise.then(fulfilled, rejected); + params.add = function (key, value) { - return this; - }; + if (isFunction(value)) { + value = value(); + } - p.catch = function (rejected) { + if (value === null) { + value = ''; + } - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } + this.push(escape(key) + '=' + escape(value)); + }; - this.promise = this.promise.catch(rejected); + serialize(params, obj); - return this; + return params.join('&').replace(/%20/g, '+'); }; - p.finally = function (callback) { + /** + * Parse a URL and return its components. + * + * @param {String} url + */ - return this.then(function (value) { - callback.call(this); - return value; - }, function (reason) { - callback.call(this); - return PromiseObj.reject(reason); - }); - }; + Url.parse = function (url) { - p.success = function (callback) { + if (ie) { + el.href = url; + url = el.href; + } - warn('The `success` method has been deprecated. Use the `then` method instead.'); + el.href = url; - return this.then(function (response) { - return callback.call(this, response.data, response.status, response) || response; - }); + return { + href: el.href, + protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', + port: el.port, + host: el.host, + hostname: el.hostname, + pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, + search: el.search ? el.search.replace(/^\?/, '') : '', + hash: el.hash ? el.hash.replace(/^#/, '') : '' + }; }; - p.error = function (callback) { + function factory(handler, next, vm) { + return function (options) { + return handler.call(vm, options, next); + }; + } - warn('The `error` method has been deprecated. Use the `catch` method instead.'); + function serialize(params, obj, scope) { - return this.catch(function (response) { - return callback.call(this, response.data, response.status, response) || response; - }); - }; + var array = isArray(obj), + plain = isPlainObject(obj), + hash; - p.always = function (callback) { + each(obj, function (value, key) { - warn('The `always` method has been deprecated. Use the `finally` method instead.'); + hash = isObject(value) || isArray(value); - var cb = function cb(response) { - return callback.call(this, response.data, response.status, response) || response; - }; + if (scope) { + key = scope + '[' + (plain || hash ? key : '') + ']'; + } - return this.then(cb, cb); - }; + if (!scope && array) { + params.add(value.name, value.value); + } else if (hash) { + serialize(params, value, key); + } else { + params.add(key, value); + } + }); + } function xdrClient (request) { return new Promise$1(function (resolve) { @@ -813,25 +819,23 @@ var originUrl = Url.parse(location.href); var supportCors = 'withCredentials' in new XMLHttpRequest(); - var exports$1 = { - request: function request(_request) { - - if (_request.crossOrigin === null) { - _request.crossOrigin = crossOrigin(_request); - } + function cors (request, next) { - if (_request.crossOrigin) { + if (request.crossOrigin === null) { + request.crossOrigin = crossOrigin(request); + } - if (!supportCors) { - _request.client = xdrClient; - } + if (request.crossOrigin) { - _request.emulateHTTP = false; + if (!supportCors) { + request.client = xdrClient; } - return _request; + request.emulateHTTP = false; } - }; + + next(); + } function crossOrigin(request) { @@ -840,33 +844,28 @@ return requestUrl.protocol !== originUrl.protocol || requestUrl.host !== originUrl.host; } - var exports$2 = { - request: function request(_request) { + function mime (request, next) { - if (_request.emulateJSON && isPlainObject(_request.data)) { - _request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; - _request.data = Url.params(_request.data); - } + if (request.emulateJSON && isPlainObject(request.data)) { + request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.data = Url.params(request.data); + } - if (isObject(_request.data) && /FormData/i.test(_request.data.toString())) { - delete _request.headers['Content-Type']; - } + if (isObject(request.data) && /FormData/i.test(request.data.toString())) { + delete request.headers['Content-Type']; + } - if (isPlainObject(_request.data)) { - _request.data = JSON.stringify(_request.data); - } + if (isPlainObject(request.data)) { + request.data = JSON.stringify(request.data); + } - return _request; - }, - response: function response(_response) { + next(function (response) { try { - _response.data = JSON.parse(_response.data); + response.data = JSON.parse(response.data); } catch (e) {} - - return _response; - } - }; + }); + } function jsonpClient (request) { return new Promise$1(function (resolve) { @@ -913,124 +912,69 @@ }); } - var exports$3 = { - request: function request(_request) { + function jsonp (request, next) { - if (_request.method == 'JSONP') { - _request.client = jsonpClient; - } - - return _request; + if (request.method == 'JSONP') { + request.client = jsonpClient; } - }; - var exports$4 = { - request: function request(_request) { + next(); + } - if (isFunction(_request.beforeSend)) { - _request.beforeSend.call(this, _request); - } + function before (request, next) { - return _request; + if (isFunction(request.beforeSend)) { + request.beforeSend.call(this, request); } - }; + + next(); + } /** * HTTP method override Interceptor. */ - var exports$5 = { - request: function request(_request) { + function method (request, next) { - if (_request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(_request.method)) { - _request.headers['X-HTTP-Method-Override'] = _request.method; - _request.method = 'POST'; - } - - return _request; + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers['X-HTTP-Method-Override'] = request.method; + request.method = 'POST'; } - }; - var exports$6 = { - request: function request(_request) { + next(); + } - _request.method = _request.method.toUpperCase(); - _request.headers = extend({}, Http.headers.common, !_request.crossOrigin ? Http.headers.custom : {}, Http.headers[_request.method.toLowerCase()], _request.headers); + function header (request, next) { - if (isPlainObject(_request.data) && /^(GET|JSONP)$/i.test(_request.method)) { - extend(_request.params, _request.data); - delete _request.data; - } + request.method = request.method.toUpperCase(); + request.headers = extend({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); - return _request; + if (isPlainObject(request.data) && /^(GET|JSONP)$/i.test(request.method)) { + extend(request.params, request.data); + delete request.data; } - }; + + next(); + } /** * Timeout Interceptor. */ - var exports$7 = function exports() { + function timeout (request, next) { var timeout; - return { - request: function request(_request) { - - if (_request.timeout) { - timeout = setTimeout(function () { - _request.cancel(); - }, _request.timeout); - } - - return _request; - }, - response: function response(_response) { - - clearTimeout(timeout); - - return _response; - } - }; - }; - - function interceptor (handler, vm) { - - return function (client) { - - if (isFunction(handler)) { - handler = handler.call(vm, Promise$1); - } - - return function (request) { - - if (isFunction(handler.request)) { - request = handler.request.call(vm, request); - } - - return when(request, function (request) { - return when(client(request), function (response) { - - if (isFunction(handler.response)) { - response = handler.response.call(vm, response); - } - - return response; - }); - }); - }; - }; - } - - function when(value, fulfilled, rejected) { - - var promise = Promise$1.resolve(value); - - if (arguments.length < 2) { - return promise; + if (request.timeout) { + timeout = setTimeout(function () { + request.cancel(); + }, request.timeout); } - return promise.then(fulfilled, rejected); + next(function (response) { + + clearTimeout(timeout); + }); } function xhrClient (request) { @@ -1051,7 +995,7 @@ response.data = 'response' in xhr ? xhr.response : xhr.responseText; response.status = xhr.status === 1223 ? 204 : xhr.status; // IE9 status bug response.statusText = trim(xhr.statusText || ''); - response.headers = xhr.getAllResponseHeaders(); + response.allHeaders = xhr.getAllResponseHeaders(); resolve(response); }; @@ -1079,30 +1023,80 @@ }); } - function Client (request) { + function Client (context) { - var response = (request.client || xhrClient)(request); + var reqHandlers = [sendRequest], + resHandlers = []; - return Promise$1.resolve(response).then(function (response) { + if (!isObject(context)) { + context = null; + } - if (response.headers) { + function Client(request) { + return new Promise$1(function (resolve) { - var headers = parseHeaders(response.headers); + function exec() { + reqHandlers.pop().call(context, request, next); + } - response.headers = function (name) { + function next(response) { + when(response, function (response) { - if (name) { - return headers[toLower(name)]; - } + if (isFunction(response)) { - return headers; - }; - } + resHandlers.unshift(response); + } else if (isObject(response)) { - response.ok = response.status >= 200 && response.status < 300; + processResponse(response); - return response; - }); + resHandlers.forEach(function (handler) { + handler.call(context, response); + }); + + resolve(response); + + return; + } + + exec(); + }); + } + + exec(); + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; + } + + function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + + resolve(client(request)); + } + + function processResponse(response) { + + var headers = response.headers || response.allHeaders; + + if (isString(headers)) { + headers = parseHeaders(headers); + } + + if (isObject(headers)) { + response.headers = function (name) { + return name ? headers[toLower(name)] : headers; + }; + } + + response.ok = response.status >= 200 && response.status < 300; + + return response; } function parseHeaders(str) { @@ -1112,26 +1106,24 @@ name, i; - if (isString(str)) { - each(str.split('\n'), function (row) { + each(str.split('\n'), function (row) { - i = row.indexOf(':'); - name = trim(toLower(row.slice(0, i))); - value = trim(row.slice(i + 1)); + i = row.indexOf(':'); + name = trim(toLower(row.slice(0, i))); + value = trim(row.slice(i + 1)); - if (headers[name]) { + if (headers[name]) { - if (isArray(headers[name])) { - headers[name].push(value); - } else { - headers[name] = [headers[name], value]; - } + if (isArray(headers[name])) { + headers[name].push(value); } else { - - headers[name] = value; + headers[name] = [headers[name], value]; } - }); - } + } else { + + headers[name] = value; + } + }); return headers; } @@ -1145,17 +1137,17 @@ function Http(url, options) { var self = this || {}, - client = Client, + client = Client(self.$vm), request, promise; Http.interceptors.forEach(function (handler) { - client = interceptor(handler, self.$vm)(client); + client.use(handler); }); options = isObject(url) ? url : extend({ url: url }, options); request = merge({}, Http.options, self.$options, options); - promise = client(request).bind(self.$vm).then(function (response) { + promise = client(request).then(function (response) { return response.ok ? response : Promise$1.reject(response); }, function (response) { @@ -1202,7 +1194,7 @@ custom: { 'X-Requested-With': 'XMLHttpRequest' } }; - Http.interceptors = [exports$4, exports$7, exports$3, exports$5, exports$2, exports$6, exports$1]; + Http.interceptors = [before, timeout, jsonp, method, mime, header, cors]; ['get', 'put', 'post', 'patch', 'delete', 'jsonp'].forEach(function (method) { diff --git a/dist/vue-resource.min.js b/dist/vue-resource.min.js index cfff976d..c3e67cda 100644 --- a/dist/vue-resource.min.js +++ b/dist/vue-resource.min.js @@ -1,7 +1,7 @@ /*! - * vue-resource v0.7.4 + * vue-resource v0.8.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueResource=e()}(this,function(){"use strict";function t(t){z=t.util,B=t.config}function e(t){_&&z.warn&&(!B.silent||B.debug)&&_.warn("[VueResource warn]: "+t)}function n(t){_&&_.error(t)}function r(t,e){return z.nextTick(t,e)}function o(t){return t.replace(/^\s*|\s*$/g,"")}function u(t){return t?t.toLowerCase():""}function i(t){return"string"==typeof t}function a(t){return"function"==typeof t}function s(t){return null!==t&&"object"===("undefined"==typeof t?"undefined":G(t))}function c(t){return s(t)&&Object.getPrototypeOf(t)==Object.prototype}function f(t,e,n){return n=n||{},a(n)&&(n=n.call(e)),p(t.bind({$vm:e,$options:n}),t,{$options:n})}function h(t,e){var n,r;if("number"==typeof t.length)for(n=0;n=200&&t.status<300,t})}function M(t){var e,n,r,a={};return i(t)&&h(t.split("\n"),function(t){r=t.indexOf(":"),n=o(u(t.slice(0,r))),e=o(t.slice(r+1)),a[n]?K(a[n])?a[n].push(e):a[n]=[a[n],e]:a[n]=e}),a}function N(t,e){var r,o,u=this||{},i=J;return N.interceptors.forEach(function(t){i=I(t,u.$vm)(i)}),e=s(t)?t:l({url:t},e),r=p({},N.options,u.$options,e),o=i(r).bind(u.$vm).then(function(t){return t.ok?t:U.reject(t)},function(t){return t instanceof Error&&n(t),U.reject(t)}),r.success&&o.success(r.success),r.error&&o.error(r.error),o}function X(t,e,n,r){var o=this||{},u={};return n=l({},X.actions,n),h(n,function(n,i){n=p({url:t,params:e||{}},r,n),u[i]=function(){return(o.$http||N)(V(n,arguments))}}),u}function V(t,e){var n,r,o,u=l({},t),i={};switch(e.length){case 4:o=e[3],r=e[2];case 3:case 2:if(!a(e[1])){i=e[0],n=e[1],r=e[2];break}if(a(e[0])){r=e[0],o=e[1];break}r=e[1],o=e[2];case 1:a(e[0])?r=e[0]:/^(POST|PUT|PATCH)$/i.test(u.method)?n=e[0]:i=e[0];break;case 0:break;default:throw"Expected up to 4 arguments [params, data, success, error], got "+e.length+" arguments"}return u.data=n,u.params=l({},u.params,i),r&&(u.success=r),o&&(u.error=o),u}function F(e){F.installed||(t(e),e.url=C,e.http=N,e.resource=X,e.Promise=U,Object.defineProperties(e.prototype,{$url:{get:function(){return f(e.url,this,this.$options.url)}},$http:{get:function(){return f(e.http,this,this.$options.http)}},$resource:{get:function(){return e.resource.bind(this)}},$promise:{get:function(){var t=this;return function(n){return new e.Promise(n,t)}}}}))}var G="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},z={},B={},W=[],_=window.console,K=Array.isArray,Q=document.documentMode,Y=document.createElement("a");C.options={url:"",root:null,params:{}},C.transforms=[$,y,v,m],C.params=function(t){var e=[],n=encodeURIComponent;return e.add=function(t,e){a(e)&&(e=e()),null===e&&(e=""),this.push(n(t)+"="+n(e))},q(e,t),e.join("&").replace(/%20/g,"+")},C.parse=function(t){return Q&&(Y.href=t,t=Y.href),Y.href=t,{href:Y.href,protocol:Y.protocol?Y.protocol.replace(/:$/,""):"",port:Y.port,host:Y.host,hostname:Y.hostname,pathname:"/"===Y.pathname.charAt(0)?Y.pathname:"/"+Y.pathname,search:Y.search?Y.search.replace(/^\?/,""):"",hash:Y.hash?Y.hash.replace(/^#/,""):""}};var Z=0,tt=1,et=2;R.reject=function(t){return new R(function(e,n){n(t)})},R.resolve=function(t){return new R(function(e,n){e(t)})},R.all=function(t){return new R(function(e,n){function r(n){return function(r){u[n]=r,o+=1,o===t.length&&e(u)}}var o=0,u=[];0===t.length&&e(u);for(var i=0;i=200&&t.status<300,t}function W(t){var e,n,r,o={};return p(t.split("\n"),function(t){r=t.indexOf(":"),n=a(u(t.slice(0,r))),e=a(t.slice(r+1)),o[n]?st(o[n])?o[n].push(e):o[n]=[o[n],e]:o[n]=e}),o}function _(t,n){var r,i,a=this||{},u=G(a.$vm);return _.interceptors.forEach(function(t){u.use(t)}),n=f(t)?t:m({url:t},n),r=v({},_.options,a.$options,n),i=u(r).then(function(t){return t.ok?t:e.reject(t)},function(t){return t instanceof Error&&o(t),e.reject(t)}),r.success&&i.success(r.success),r.error&&i.error(r.error),i}function K(t,e,n,r){var o=this||{},i={};return n=m({},K.actions,n),p(n,function(n,a){n=v({url:t,params:e||{}},r,n),i[a]=function(){return(o.$http||_)(Q(n,arguments))}}),i}function Q(t,e){var n,r,o,i=m({},t),a={};switch(e.length){case 4:o=e[3],r=e[2];case 3:case 2:if(!s(e[1])){a=e[0],n=e[1],r=e[2];break}if(s(e[0])){r=e[0],o=e[1];break}r=e[1],o=e[2];case 1:s(e[0])?r=e[0]:/^(POST|PUT|PATCH)$/i.test(i.method)?n=e[0]:a=e[0];break;case 0:break;default:throw"Expected up to 4 arguments [params, data, success, error], got "+e.length+" arguments"}return i.data=n,i.params=m({},i.params,a),r&&(i.success=r),o&&(i.error=o),i}function Y(t){Y.installed||(n(t),t.url=U,t.http=_,t.resource=K,t.Promise=e,Object.defineProperties(t.prototype,{$url:{get:function(){return d(t.url,this,this.$options.url)}},$http:{get:function(){return d(t.http,this,this.$options.http)}},$resource:{get:function(){return t.resource.bind(this)}},$promise:{get:function(){var e=this;return function(n){return new t.Promise(n,e)}}}}))}var Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},tt=0,et=1,nt=2;t.reject=function(e){return new t(function(t,n){n(e)})},t.resolve=function(e){return new t(function(t,n){t(e)})},t.all=function(e){return new t(function(n,r){function o(t){return function(r){a[t]=r,i+=1,i===e.length&&n(a)}}var i=0,a=[];0===e.length&&n(a);for(var u=0;u { // success callback - }, function (response) { + }, (response) => { // error callback }); @@ -78,10 +78,10 @@ emulateJSON | `boolean` | Send request data as `application/x-www-form-urlencode ```js new Vue({ - ready: function() { + ready() { // GET request - this.$http.get('/someUrl').then(function (response) { + this.$http.get('/someUrl').then((response) => { // get status response.status; @@ -95,7 +95,7 @@ new Vue({ // set data on vm this.$set('someData', response.data) - }, function (response) { + }, (response) => { // error callback }); @@ -109,34 +109,46 @@ new Vue({ Interceptors can be defined globally and are used for pre- and postprocessing of a request. +### Request processing ```js -Vue.http.interceptors.push({ +Vue.http.interceptors.push((request, next) => { - request: function (request) { - return request; - }, - - response: function (response) { - return response; - } + // modify request + resquest.method = 'POST'; + // continue to next interceptor + next(); }); ``` -A factory function can also be used. - +### Request and Response processing ```js -Vue.http.interceptors.push(function () { - return { +Vue.http.interceptors.push((request, next) => { + + // modify request + resquest.method = 'POST'; + + // continue to next interceptor + next((response) => { - request: function (request) { - return request; - }, + // modify response + response.data = '...'; + + }); +}); +``` + +### Return a Response and stop processing +```js +Vue.http.interceptors.push((request, next) => { - response: function (response) { - return response; - } + // modify request ... - }; + // stop and return response object + next({ + data: '...', + status: 404, + statusText: 'Not found' + }); }); ``` diff --git a/docs/resource.md b/docs/resource.md index 5d2478bb..487668b9 100644 --- a/docs/resource.md +++ b/docs/resource.md @@ -22,26 +22,26 @@ delete: {method: 'DELETE'} ```js new Vue({ - ready: function() { + ready() { var resource = this.$resource('someItem{/id}'); // get item - resource.get({id: 1}).then(function (response) { + resource.get({id: 1}).then((response) => { this.$set('item', response.item) }); // save item - resource.save({id: 1}, {item: this.item}).then(function (response) { + resource.save({id: 1}, {item: this.item}).then((response) => { // success callback - }, function (response) { + }, (response) => { // error callback }); // delete item - resource.delete({id: 1}).then(function (response) { + resource.delete({id: 1}).then((response) => { // success callback - }, function (response) { + }, (response) => { // error callback }); diff --git a/package.json b/package.json index 275c6a37..919ef1d4 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "vue-resource", - "version": "0.7.4", + "version": "0.8.0", "description": "A web request service for Vue.js", "main": "dist/vue-resource.common.js", + "jsnext:main": "dist/vue-resource.es2015.js", "scripts": { "build": "node build/build.js", "test": "webpack --config test/webpack.config.js" diff --git a/src/http/before.js b/src/http/before.js index 071e8f7f..f0e1c3a3 100644 --- a/src/http/before.js +++ b/src/http/before.js @@ -4,17 +4,11 @@ import { isFunction } from '../util'; -const exports = { +export default function (request, next) { - request(request) { - - if (isFunction(request.beforeSend)) { - request.beforeSend.call(this, request); - } - - return request; + if (isFunction(request.beforeSend)) { + request.beforeSend.call(this, request); } -}; - -export default exports; + next(); +} diff --git a/src/http/client/index.js b/src/http/client/index.js index c6515b6d..37ff1eb9 100644 --- a/src/http/client/index.js +++ b/src/http/client/index.js @@ -4,62 +4,107 @@ import Promise from '../../promise'; import xhrClient from './xhr'; -import { each, trim, isArray, isString, toLower } from '../../util'; +import { each, trim, when, isArray, isObject, isPlainObject, isString, isFunction, toLower } from '../../util'; -export default function (request) { +export default function (context) { - var response = (request.client || xhrClient)(request); + var reqHandlers = [sendRequest], resHandlers = []; - return Promise.resolve(response).then((response) => { + if (!isObject(context)) { + context = null; + } - if (response.headers) { + function Client(request) { + return new Promise((resolve) => { - var headers = parseHeaders(response.headers); + function exec() { + reqHandlers.pop().call(context, request, next); + } - response.headers = (name) => { + function next(response) { + when(response, (response) => { - if (name) { - return headers[toLower(name)]; - } + if (isFunction(response)) { - return headers; - }; + resHandlers.unshift(response); - } + } else if (isObject(response)) { - response.ok = response.status >= 200 && response.status < 300; + processResponse(response); - return response; - }); + resHandlers.forEach((handler) => { + handler.call(context, response); + }); + + resolve(response); + + return; + } + + exec(); + }); + } + + exec(); + + }, context); + } + + Client.use = (handler) => { + reqHandlers.push(handler); + }; + + return Client; +} + +function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + resolve(client(request)); +} + +function processResponse(response) { + + var headers = response.headers || response.allHeaders; + + if (isString(headers)) { + headers = parseHeaders(headers); + } + + if (isObject(headers)) { + response.headers = (name) => name ? headers[toLower(name)] : headers; + } + + response.ok = response.status >= 200 && response.status < 300; + + return response; } function parseHeaders(str) { var headers = {}, value, name, i; - if (isString(str)) { - each(str.split('\n'), (row) => { - - i = row.indexOf(':'); - name = trim(toLower(row.slice(0, i))); - value = trim(row.slice(i + 1)); + each(str.split('\n'), (row) => { - if (headers[name]) { + i = row.indexOf(':'); + name = trim(toLower(row.slice(0, i))); + value = trim(row.slice(i + 1)); - if (isArray(headers[name])) { - headers[name].push(value); - } else { - headers[name] = [headers[name], value]; - } + if (headers[name]) { + if (isArray(headers[name])) { + headers[name].push(value); } else { - - headers[name] = value; + headers[name] = [headers[name], value]; } - }); - } + } else { + + headers[name] = value; + } + + }); return headers; } diff --git a/src/http/client/xhr.js b/src/http/client/xhr.js index 90f77e3d..d7528c99 100644 --- a/src/http/client/xhr.js +++ b/src/http/client/xhr.js @@ -22,7 +22,7 @@ export default function (request) { response.data = ('response' in xhr) ? xhr.response : xhr.responseText; response.status = xhr.status === 1223 ? 204 : xhr.status; // IE9 status bug response.statusText = trim(xhr.statusText || ''); - response.headers = xhr.getAllResponseHeaders(); + response.allHeaders = xhr.getAllResponseHeaders(); resolve(response); }; diff --git a/src/http/cors.js b/src/http/cors.js index 5713796a..0d28b90b 100644 --- a/src/http/cors.js +++ b/src/http/cors.js @@ -8,27 +8,23 @@ import xdrClient from './client/xdr'; const originUrl = Url.parse(location.href); const supportCors = 'withCredentials' in new XMLHttpRequest(); -const exports = { +export default function (request, next) { - request(request) { - - if (request.crossOrigin === null) { - request.crossOrigin = crossOrigin(request); - } - - if (request.crossOrigin) { + if (request.crossOrigin === null) { + request.crossOrigin = crossOrigin(request); + } - if (!supportCors) { - request.client = xdrClient; - } + if (request.crossOrigin) { - request.emulateHTTP = false; + if (!supportCors) { + request.client = xdrClient; } - return request; + request.emulateHTTP = false; } -}; + next(); +} function crossOrigin(request) { @@ -36,5 +32,3 @@ function crossOrigin(request) { return (requestUrl.protocol !== originUrl.protocol || requestUrl.host !== originUrl.host); } - -export default exports; diff --git a/src/http/header.js b/src/http/header.js index 3d31a813..05b7f854 100644 --- a/src/http/header.js +++ b/src/http/header.js @@ -5,25 +5,19 @@ import Http from './index'; import { extend, isPlainObject } from '../util'; -const exports = { - - request(request) { - - request.method = request.method.toUpperCase(); - request.headers = extend({}, Http.headers.common, - !request.crossOrigin ? Http.headers.custom : {}, - Http.headers[request.method.toLowerCase()], - request.headers - ); - - if (isPlainObject(request.data) && /^(GET|JSONP)$/i.test(request.method)) { - extend(request.params, request.data); - delete request.data; - } - - return request; +export default function (request, next) { + + request.method = request.method.toUpperCase(); + request.headers = extend({}, Http.headers.common, + !request.crossOrigin ? Http.headers.custom : {}, + Http.headers[request.method.toLowerCase()], + request.headers + ); + + if (isPlainObject(request.data) && /^(GET|JSONP)$/i.test(request.method)) { + extend(request.params, request.data); + delete request.data; } -}; - -export default exports; + next(); +} diff --git a/src/http/index.js b/src/http/index.js index 6ddd086f..21ec05ca 100644 --- a/src/http/index.js +++ b/src/http/index.js @@ -11,22 +11,21 @@ import before from './before'; import method from './method'; import header from './header'; import timeout from './timeout'; -import interceptor from './interceptor'; import Client from './client/index'; import Promise from '../promise'; import { error, extend, merge, isFunction, isObject } from '../util'; export default function Http(url, options) { - var self = this || {}, client = Client, request, promise; + var self = this || {}, client = Client(self.$vm), request, promise; Http.interceptors.forEach((handler) => { - client = interceptor(handler, self.$vm)(client); + client.use(handler); }); options = isObject(url) ? url : extend({url: url}, options); request = merge({}, Http.options, self.$options, options); - promise = client(request).bind(self.$vm).then((response) => { + promise = client(request).then((response) => { return response.ok ? response : Promise.reject(response); @@ -76,7 +75,7 @@ Http.headers = { Http.interceptors = [before, timeout, jsonp, method, mime, header, cors]; -['get', 'put', 'post', 'patch', 'delete', 'jsonp'].forEach(function (method) { +['get', 'put', 'post', 'patch', 'delete', 'jsonp'].forEach((method) => { Http[method] = function (url, data, success, options) { diff --git a/src/http/interceptor.js b/src/http/interceptor.js deleted file mode 100644 index 4c0c5b4a..00000000 --- a/src/http/interceptor.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Interceptor factory. - */ - -import Promise from '../promise'; -import { isFunction } from '../util'; - -export default function (handler, vm) { - - return function (client) { - - if (isFunction(handler)) { - handler = handler.call(vm, Promise); - } - - return function (request) { - - if (isFunction(handler.request)) { - request = handler.request.call(vm, request); - } - - return when(request, function (request) { - return when(client(request), function (response) { - - if (isFunction(handler.response)) { - response = handler.response.call(vm, response); - } - - return response; - }); - }); - }; - }; -} - -function when(value, fulfilled, rejected) { - - var promise = Promise.resolve(value); - - if (arguments.length < 2) { - return promise; - } - - return promise.then(fulfilled, rejected); -} diff --git a/src/http/jsonp.js b/src/http/jsonp.js index 6b3d531c..9d9e1496 100644 --- a/src/http/jsonp.js +++ b/src/http/jsonp.js @@ -4,17 +4,11 @@ import jsonpClient from './client/jsonp'; -const exports = { +export default function (request, next) { - request(request) { - - if (request.method == 'JSONP') { - request.client = jsonpClient; - } - - return request; + if (request.method == 'JSONP') { + request.client = jsonpClient; } -}; - -export default exports; + next(); +} diff --git a/src/http/method.js b/src/http/method.js index 00a9be49..8489e98c 100644 --- a/src/http/method.js +++ b/src/http/method.js @@ -2,18 +2,12 @@ * HTTP method override Interceptor. */ -const exports = { +export default function (request, next) { - request(request) { - - if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { - request.headers['X-HTTP-Method-Override'] = request.method; - request.method = 'POST'; - } - - return request; + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers['X-HTTP-Method-Override'] = request.method; + request.method = 'POST'; } -}; - -export default exports; + next(); +} diff --git a/src/http/mime.js b/src/http/mime.js index a6099e9e..cd8e6642 100644 --- a/src/http/mime.js +++ b/src/http/mime.js @@ -5,35 +5,26 @@ import Url from '../url/index'; import { isObject, isPlainObject } from '../util'; -const exports = { +export default function (request, next) { - request(request) { - - if (request.emulateJSON && isPlainObject(request.data)) { - request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; - request.data = Url.params(request.data); - } - - if (isObject(request.data) && /FormData/i.test(request.data.toString())) { - delete request.headers['Content-Type']; - } + if (request.emulateJSON && isPlainObject(request.data)) { + request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.data = Url.params(request.data); + } - if (isPlainObject(request.data)) { - request.data = JSON.stringify(request.data); - } + if (isObject(request.data) && /FormData/i.test(request.data.toString())) { + delete request.headers['Content-Type']; + } - return request; - }, + if (isPlainObject(request.data)) { + request.data = JSON.stringify(request.data); + } - response(response) { + next((response) => { try { response.data = JSON.parse(response.data); } catch (e) {} - return response; - } - -}; - -export default exports; + }); +} diff --git a/src/http/timeout.js b/src/http/timeout.js index a225d7e8..a67ec570 100644 --- a/src/http/timeout.js +++ b/src/http/timeout.js @@ -2,31 +2,19 @@ * Timeout Interceptor. */ -const exports = function () { +export default function (request, next) { var timeout; - return { + if (request.timeout) { + timeout = setTimeout(() => { + request.cancel(); + }, request.timeout); + } - request(request) { + next((response) => { - if (request.timeout) { - timeout = setTimeout(() => { - request.cancel(); - }, request.timeout); - } + clearTimeout(timeout); - return request; - }, - - response(response) { - - clearTimeout(timeout); - - return response; - } - - }; -}; - -export default exports; + }); +} diff --git a/src/lib/url-template.js b/src/lib/url-template.js index 9345eac1..b35d5b03 100644 --- a/src/lib/url-template.js +++ b/src/lib/url-template.js @@ -19,8 +19,8 @@ export function parse(template) { return { vars: variables, - expand: function (context) { - return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) { + expand(context) { + return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, (_, expression, literal) => { if (expression) { var operator = null, values = []; @@ -30,7 +30,7 @@ export function parse(template) { expression = expression.substr(1); } - expression.split(/,/g).forEach(function (variable) { + expression.split(/,/g).forEach((variable) => { var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); variables.push(tmp[1]); @@ -75,11 +75,11 @@ function getValues(context, operator, key, modifier) { } else { if (modifier === '*') { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function (value) { + value.filter(isDefined).forEach((value) => { result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); }); } else { - Object.keys(value).forEach(function (k) { + Object.keys(value).forEach((k) => { if (isDefined(value[k])) { result.push(encodeValue(operator, value[k], k)); } @@ -89,11 +89,11 @@ function getValues(context, operator, key, modifier) { var tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function (value) { + value.filter(isDefined).forEach((value) => { tmp.push(encodeValue(operator, value)); }); } else { - Object.keys(value).forEach(function (k) { + Object.keys(value).forEach((k) => { if (isDefined(value[k])) { tmp.push(encodeURIComponent(k)); tmp.push(encodeValue(operator, value[k].toString())); @@ -141,7 +141,7 @@ function encodeValue(operator, value, key) { } function encodeReserved(str) { - return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { + return str.split(/(%[0-9A-Fa-f]{2})/g).map((part) => { if (!/%[0-9A-Fa-f]/.test(part)) { part = encodeURI(part); } diff --git a/src/util.js b/src/util.js index 5626d4d2..5a407917 100644 --- a/src/util.js +++ b/src/util.js @@ -2,23 +2,25 @@ * Utility functions. */ -var util = {}, config = {}, array = [], console = window.console; +import Promise from './promise'; + +var debug = false, util = {}, array = []; export default function (Vue) { util = Vue.util; - config = Vue.config; + debug = Vue.config.debug || !Vue.config.silent; } export const isArray = Array.isArray; export function warn(msg) { - if (console && util.warn && (!config.silent || config.debug)) { + if (typeof console !== 'undefined' && debug) { console.warn('[VueResource warn]: ' + msg); } } export function error(msg) { - if (console) { + if (typeof console !== 'undefined') { console.error(msg); } } @@ -51,6 +53,17 @@ export function isPlainObject(obj) { return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; } +export function when(value, fulfilled, rejected) { + + var promise = Promise.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); +} + export function options(fn, obj, opts) { opts = opts || {};