From 5367951285729fd1c06349dfbef506d63b4d3da8 Mon Sep 17 00:00:00 2001 From: Steffan Date: Fri, 1 Jul 2016 18:45:31 +0200 Subject: [PATCH 01/26] update keywords --- bower.json | 8 +++++++- package.json | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/bower.json b/bower.json index cd073e2c..afe9d003 100644 --- a/bower.json +++ b/bower.json @@ -1,10 +1,16 @@ { "name": "vue-resource", "main": "dist/vue-resource.js", - "description": "A web request service for Vue.js", "version": "0.9.3", + "description": "A web request service for Vue.js", "homepage": "https://github.com/vuejs/vue-resource", "license": "MIT", + "keywords": [ + "vue", + "xhr", + "http", + "ajax" + ], "ignore": [ ".*", "build", diff --git a/package.json b/package.json index 6f71c44a..14189147 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,20 @@ { "name": "vue-resource", "version": "0.9.3", - "description": "A web request service for Vue.js", "main": "dist/vue-resource.common.js", "jsnext:main": "dist/vue-resource.es2015.js", + "description": "A web request service for Vue.js", + "homepage": "https://github.com/vuejs/vue-resource#readme", + "license": "MIT", + "keywords": [ + "vue", + "xhr", + "http", + "ajax" + ], + "bugs": { + "url": "https://github.com/vuejs/vue-resource/issues" + }, "scripts": { "test": "webpack --config test/webpack.config.js", "build": "node build/build.js", @@ -13,17 +24,6 @@ "type": "git", "url": "git+https://github.com/vuejs/vue-resource.git" }, - "keywords": [ - "vue", - "vuejs", - "resource", - "mvvm" - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/vuejs/vue-resource/issues" - }, - "homepage": "https://github.com/vuejs/vue-resource#readme", "devDependencies": { "babel-core": "^6.10.4", "babel-loader": "^6.2.4", From 34cfcf90113bf6238c43e69234eafb6f76d570b1 Mon Sep 17 00:00:00 2001 From: Steffan Date: Fri, 1 Jul 2016 18:46:35 +0200 Subject: [PATCH 02/26] update description --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index afe9d003..db3680ae 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "vue-resource", "main": "dist/vue-resource.js", "version": "0.9.3", - "description": "A web request service for Vue.js", + "description": "The HTTP client for Vue.js", "homepage": "https://github.com/vuejs/vue-resource", "license": "MIT", "keywords": [ diff --git a/package.json b/package.json index 14189147..9d4c7be3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.9.3", "main": "dist/vue-resource.common.js", "jsnext:main": "dist/vue-resource.es2015.js", - "description": "A web request service for Vue.js", + "description": "The HTTP client for Vue.js", "homepage": "https://github.com/vuejs/vue-resource#readme", "license": "MIT", "keywords": [ From 193a161fc08fa79abe9cf5dc8fad763958be5b1c Mon Sep 17 00:00:00 2001 From: Steffan Date: Fri, 1 Jul 2016 18:47:41 +0200 Subject: [PATCH 03/26] update package.json --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9d4c7be3..d5649c04 100644 --- a/package.json +++ b/package.json @@ -15,15 +15,15 @@ "bugs": { "url": "https://github.com/vuejs/vue-resource/issues" }, + "repository": { + "type": "git", + "url": "git+https://github.com/vuejs/vue-resource.git" + }, "scripts": { "test": "webpack --config test/webpack.config.js", "build": "node build/build.js", "release": "node build/release.js" }, - "repository": { - "type": "git", - "url": "git+https://github.com/vuejs/vue-resource.git" - }, "devDependencies": { "babel-core": "^6.10.4", "babel-loader": "^6.2.4", From 0dc5954ccfc7b501e37e95603b9555efdc80db4a Mon Sep 17 00:00:00 2001 From: Steffan Date: Mon, 4 Jul 2016 10:53:29 +0200 Subject: [PATCH 04/26] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 700916bc..00b0965d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# vue-resource [![npm package](https://img.shields.io/npm/v/vue-resource.svg)](https://www.npmjs.com/package/vue-resource) +# vue-resource [![Downloads](https://img.shields.io/npm/dt/vue-resource.svg)](https://www.npmjs.com/package/vue-resource) [![Version](https://img.shields.io/npm/v/vue-resource.svg)](https://www.npmjs.com/package/vue-resource) [![License](https://img.shields.io/npm/l/vue-resource.svg)](https://www.npmjs.com/package/vue-resource) The plugin for [Vue.js](http://vuejs.org) provides services for making web requests and handle responses using a [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) or JSONP. From 627be7c9e54557b43e93e5ef6e45f3e5d27a1e99 Mon Sep 17 00:00:00 2001 From: Steffan Date: Mon, 4 Jul 2016 20:05:50 +0200 Subject: [PATCH 05/26] add headers class --- src/http/client/xhr.js | 41 +++++---------------- src/http/headers.js | 65 ++++++++++++++++++++++++++++++++++ src/http/interceptor/body.js | 6 ++-- src/http/interceptor/header.js | 14 +++++--- src/http/interceptor/method.js | 2 +- src/http/request.js | 10 +++--- src/http/response.js | 4 ++- src/util.js | 10 +++++- test/http.js | 6 ++-- 9 files changed, 107 insertions(+), 51 deletions(-) create mode 100644 src/http/headers.js diff --git a/src/http/client/xhr.js b/src/http/client/xhr.js index 61ea7bc0..8961f116 100644 --- a/src/http/client/xhr.js +++ b/src/http/client/xhr.js @@ -3,7 +3,7 @@ */ import Promise from '../../promise'; -import { each, trim, isArray } from '../../util'; +import { each, trim } from '../../util'; export default function (request) { return new Promise((resolve) => { @@ -13,11 +13,14 @@ export default function (request) { var response = request.respondWith( 'response' in xhr ? xhr.response : xhr.responseText, { status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug - statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText), - headers: parseHeaders(xhr.getAllResponseHeaders()), + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) } ); + each(trim(xhr.getAllResponseHeaders()).split('\n'), (row) => { + response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); + }); + resolve(response); }; @@ -40,38 +43,10 @@ export default function (request) { xhr.withCredentials = true; } - each(request.headers || {}, (value, header) => { - xhr.setRequestHeader(header, value); + request.headers.forEach((value, name) => { + xhr.setRequestHeader(name, value); }); xhr.send(request.getBody()); }); } - -function parseHeaders(str) { - - var headers = {}, value, name, i; - - each(trim(str).split('\n'), (row) => { - - i = row.indexOf(':'); - name = trim(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; -} diff --git a/src/http/headers.js b/src/http/headers.js new file mode 100644 index 00000000..b758d0e0 --- /dev/null +++ b/src/http/headers.js @@ -0,0 +1,65 @@ +/** + * HTTP Headers. + */ + +import { each, trim, toLower } from '../util'; + +export default class Headers { + + constructor(headers) { + + this.map = {}; + + each(headers, (value, name) => this.append(name, value)); + } + + has(name) { + return this.map.hasOwnProperty(normalizeName(name)); + } + + get(name) { + + var list = this.map[normalizeName(name)]; + + return list ? list[0] : null; + } + + getAll(name) { + return this.map[normalizeName(name)] || []; + } + + set(name, value) { + this.map[normalizeName(name)] = [trim(value)]; + } + + append(name, value){ + + var list = this.map[normalizeName(name)]; + + if (!list) { + list = this.map[normalizeName(name)] = []; + } + + list.push(trim(value)); + } + + delete(name){ + delete this.map[normalizeName(name)]; + } + + forEach(callback, thisArg) { + each(this.map, (list, name) => { + each(list, value => callback.call(thisArg, value, name, this)); + }); + } + +} + +function normalizeName(name) { + + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name'); + } + + return toLower(trim(name)); +} diff --git a/src/http/interceptor/body.js b/src/http/interceptor/body.js index e71c3947..9bec4bba 100644 --- a/src/http/interceptor/body.js +++ b/src/http/interceptor/body.js @@ -9,11 +9,11 @@ export default function (request, next) { if (request.emulateJSON && isPlainObject(request.body)) { request.body = Url.params(request.body); - request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); } if (isFormData(request.body)) { - delete request.headers['Content-Type']; + request.headers.delete('Content-Type'); } if (isPlainObject(request.body)) { @@ -22,7 +22,7 @@ export default function (request, next) { next((response) => { - var contentType = response.headers['Content-Type']; + var contentType = response.headers.get('Content-Type'); if (isString(contentType) && contentType.indexOf('application/json') === 0) { diff --git a/src/http/interceptor/header.js b/src/http/interceptor/header.js index 8d2e4eb1..193b8db2 100644 --- a/src/http/interceptor/header.js +++ b/src/http/interceptor/header.js @@ -3,16 +3,20 @@ */ import Http from '../index'; -import { assign } from '../../util'; +import { assign, each, toLower } from '../../util'; export default function (request, next) { - request.method = request.method.toUpperCase(); - request.headers = assign({}, Http.headers.common, + var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, - Http.headers[request.method.toLowerCase()], - request.headers + Http.headers[toLower(request.method)] ); + each(headers, (value, name) => { + if (!request.headers.has(name)) { + request.headers.set(name, value); + } + }); + next(); } diff --git a/src/http/interceptor/method.js b/src/http/interceptor/method.js index 8489e98c..ad393ce2 100644 --- a/src/http/interceptor/method.js +++ b/src/http/interceptor/method.js @@ -5,7 +5,7 @@ export default function (request, next) { if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { - request.headers['X-HTTP-Method-Override'] = request.method; + request.headers.set('X-HTTP-Method-Override', request.method); request.method = 'POST'; } diff --git a/src/http/request.js b/src/http/request.js index cd7c41c2..070afa42 100644 --- a/src/http/request.js +++ b/src/http/request.js @@ -3,19 +3,21 @@ */ import Url from '../url/index'; +import Headers from './headers'; import Response from './response'; -import { assign } from '../util'; +import { assign, toUpper } from '../util'; export default class Request { constructor(options) { - this.method = 'GET'; this.body = null; this.params = {}; - this.headers = {}; - assign(this, options); + assign(this, options, { + method: toUpper(options.method || 'GET'), + headers: new Headers(options.headers) + }); } getUrl(){ diff --git a/src/http/response.js b/src/http/response.js index 2de5519b..028c771b 100644 --- a/src/http/response.js +++ b/src/http/response.js @@ -2,13 +2,15 @@ * HTTP Response. */ +import Headers from './headers'; + export default class Response { constructor(body, {url, headers, status, statusText}) { this.url = url; this.body = body; - this.headers = headers || {}; + this.headers = new Headers(headers); this.status = status || 0; this.statusText = statusText || ''; this.ok = status >= 200 && status < 300; diff --git a/src/util.js b/src/util.js index b252621a..d44d8d51 100644 --- a/src/util.js +++ b/src/util.js @@ -31,6 +31,14 @@ export function trim(str) { return str.replace(/^\s*|\s*$/g, ''); } +export function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +export function toUpper(str) { + return str ? str.toUpperCase() : ''; +} + export const isArray = Array.isArray; export function isString(val) { @@ -83,7 +91,7 @@ export function each(obj, iterator) { var i, key; - if (typeof obj.length == 'number') { + if (obj && typeof obj.length == 'number') { for (i = 0; i < obj.length; i++) { iterator.call(obj[i], obj[i], i); } diff --git a/test/http.js b/test/http.js index ae201b2f..62117804 100644 --- a/test/http.js +++ b/test/http.js @@ -10,8 +10,8 @@ describe('Vue.http', function () { expect(res.status).toBe(200); expect(res.data).toBe('text'); expect(res.blob() instanceof Blob).toBe(true); - expect(res.headers['Content-Type']).toBe('text/plain'); - expect(res.headers['Content-Length']).toBe('4'); + expect(res.headers.get('Content-Type')).toBe('text/plain'); + expect(res.headers.get('Content-Length')).toBe('4'); done(); }); @@ -52,7 +52,7 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); expect(res.data.shift().requestType).toBe('cors'); - expect(res.headers['Content-Type']).toBe('application/json'); + expect(res.headers.get('Content-Type')).toBe('application/json'); expect(typeof res.json()).toBe('object'); done(); From 2cc37e8c57ba37c85d9cbf4fe190018a5c320b77 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 10 Jul 2016 11:26:28 +0200 Subject: [PATCH 06/26] fix blob issue #320 --- package.json | 1 + src/http/client/xhr.js | 22 +++++++++++++++++++++- src/http/response.js | 30 ++++++++++++++++++++++-------- src/index.js | 13 +++++++++++-- src/promise.js | 4 +--- src/util.js | 12 ++++++++---- test/http.js | 14 ++++++++++++++ 7 files changed, 78 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index d5649c04..49e25380 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "babel-preset-es2015-loose": "^7.0.0", "babel-preset-es2015-loose-rollup": "^7.0.0", "babel-runtime": "^6.9.2", + "generate-release": "^0.10.1", "jasmine-core": "^2.3.4", "replace-in-file": "^1.1.1", "rollup": "^0.33.0", diff --git a/src/http/client/xhr.js b/src/http/client/xhr.js index 8961f116..98d6ca10 100644 --- a/src/http/client/xhr.js +++ b/src/http/client/xhr.js @@ -21,7 +21,19 @@ export default function (request) { response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); }); - resolve(response); + if (isBlobText(response.blob())) { + + var reader = new FileReader(); + + reader.readAsText(response.blob()); + reader.onload = () => { + response.initBody(reader.result); + resolve(response); + }; + + } else { + resolve(response); + } }; request.abort = () => xhr.abort(); @@ -39,6 +51,10 @@ export default function (request) { } } + if ('responseType' in xhr) { + xhr.responseType = 'blob'; + } + if (request.credentials === true) { xhr.withCredentials = true; } @@ -50,3 +66,7 @@ export default function (request) { xhr.send(request.getBody()); }); } + +function isBlobText(body) { + return body && (body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1); +} diff --git a/src/http/response.js b/src/http/response.js index 028c771b..42198ae5 100644 --- a/src/http/response.js +++ b/src/http/response.js @@ -3,30 +3,44 @@ */ import Headers from './headers'; +import { isBlob, isString } from '../util'; export default class Response { constructor(body, {url, headers, status, statusText}) { this.url = url; - this.body = body; - this.headers = new Headers(headers); + this.ok = status >= 200 && status < 300; this.status = status || 0; this.statusText = statusText || ''; - this.ok = status >= 200 && status < 300; + this.headers = new Headers(headers); + this.bodyBlob = null; + this.bodyText = ''; + this.initBody(body); } - text() { - return this.body; + blob() { + return this.bodyBlob; } - blob() { - return new Blob([this.body]); + text() { + return this.bodyText; } json() { - return JSON.parse(this.body); + return JSON.parse(this.text()); + } + + initBody(body) { + + if (isBlob(body)) { + this.bodyBlob = body; + } + + if (isString(body)) { + this.bodyText = body; + } } } diff --git a/src/index.js b/src/index.js index fb4a40af..8c68e092 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import Url from './url/index'; import Http from './http/index'; import Promise from './promise'; +import PromiseLib from './lib/promise'; import Resource from './resource'; import Util, { options } from './util'; @@ -50,8 +51,16 @@ function plugin(Vue) { }); } -if (typeof window !== 'undefined' && window.Vue) { - window.Vue.use(plugin); +if (typeof window !== 'undefined') { + + if (!window.Promise) { + window.Promise = PromiseLib; + } + + if (window.Vue) { + window.Vue.use(plugin); + } + } export default plugin; diff --git a/src/promise.js b/src/promise.js index 1286acef..83acdc7d 100644 --- a/src/promise.js +++ b/src/promise.js @@ -2,9 +2,7 @@ * Promise adapter. */ -import PromiseLib from './lib/promise'; - -var PromiseObj = window.Promise || PromiseLib; +var PromiseObj = window.Promise; export default function Promise(executor, context) { diff --git a/src/util.js b/src/util.js index d44d8d51..33b4ded6 100644 --- a/src/util.js +++ b/src/util.js @@ -4,7 +4,7 @@ import Promise from './promise'; -var debug = false, util = {}, array = []; +var debug = false, util = {}, { slice } = []; export default function (Vue) { util = Vue.util; @@ -61,6 +61,10 @@ export function isPlainObject(obj) { return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; } +export function isBlob(obj) { + return typeof Blob !== 'undefined' && obj instanceof Blob; +} + export function isFormData(obj) { return typeof FormData !== 'undefined' && obj instanceof FormData; } @@ -110,7 +114,7 @@ export const assign = Object.assign || _assign; export function merge(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach((source) => { _merge(target, source, true); @@ -121,7 +125,7 @@ export function merge(target) { export function defaults(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach((source) => { @@ -138,7 +142,7 @@ export function defaults(target) { function _assign(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach((source) => { _merge(target, source); diff --git a/test/http.js b/test/http.js index 62117804..f61faa31 100644 --- a/test/http.js +++ b/test/http.js @@ -45,6 +45,20 @@ describe('Vue.http', function () { }); + it('get("github.com/avatar")', (done) => { + + Vue.http.get('https://avatars1.githubusercontent.com/u/6128107').then((res) => { + + expect(res.ok).toBe(true); + expect(res.status).toBe(200); + expect(res.text()).toBe(''); + expect(res.blob() instanceof Blob).toBe(true); + + done(); + }); + + }); + it('get("cors-api.appspot.com")', (done) => { Vue.http.get('http://server.cors-api.appspot.com/server?id=1&enable=true').then((res) => { From 6bfded6ff9c815c0301c62bb97f0f01957f9969e Mon Sep 17 00:00:00 2001 From: Steffan Date: Tue, 16 Aug 2016 10:23:57 +0200 Subject: [PATCH 07/26] update dev dependencies --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 49e25380..4aff7657 100644 --- a/package.json +++ b/package.json @@ -25,18 +25,18 @@ "release": "node build/release.js" }, "devDependencies": { - "babel-core": "^6.10.4", + "babel-core": "^6.13.2", "babel-loader": "^6.2.4", - "babel-plugin-transform-runtime": "^6.9.0", + "babel-plugin-transform-runtime": "^6.12.0", "babel-preset-es2015-loose": "^7.0.0", "babel-preset-es2015-loose-rollup": "^7.0.0", - "babel-runtime": "^6.9.2", + "babel-runtime": "^6.11.6", "generate-release": "^0.10.1", "jasmine-core": "^2.3.4", - "replace-in-file": "^1.1.1", - "rollup": "^0.33.0", + "replace-in-file": "^2.0.1", + "rollup": "^0.34.8", "rollup-plugin-babel": "^2.6.1", - "uglify-js": "^2.6.4", + "uglify-js": "^2.7.1", "vue": "^1.0.26", "webpack": "^1.13.1" } From 91fefa21faa88bc98271b43adbc23384ba46b93f Mon Sep 17 00:00:00 2001 From: Steffan Date: Tue, 16 Aug 2016 11:14:45 +0200 Subject: [PATCH 08/26] update body interceptor --- src/http/client/xhr.js | 18 +--------------- src/http/interceptor/body.js | 42 +++++++++++++++++++++++++++--------- src/http/response.js | 23 ++++++++++---------- test/http.js | 2 +- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/http/client/xhr.js b/src/http/client/xhr.js index 98d6ca10..87ad48ac 100644 --- a/src/http/client/xhr.js +++ b/src/http/client/xhr.js @@ -21,19 +21,7 @@ export default function (request) { response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); }); - if (isBlobText(response.blob())) { - - var reader = new FileReader(); - - reader.readAsText(response.blob()); - reader.onload = () => { - response.initBody(reader.result); - resolve(response); - }; - - } else { - resolve(response); - } + resolve(response); }; request.abort = () => xhr.abort(); @@ -66,7 +54,3 @@ export default function (request) { xhr.send(request.getBody()); }); } - -function isBlobText(body) { - return body && (body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1); -} diff --git a/src/http/interceptor/body.js b/src/http/interceptor/body.js index 9bec4bba..e6fbe03e 100644 --- a/src/http/interceptor/body.js +++ b/src/http/interceptor/body.js @@ -3,6 +3,7 @@ */ import Url from '../../url/index'; +import Promise from '../../promise'; import { isString, isFormData, isPlainObject } from '../../util'; export default function (request, next) { @@ -22,19 +23,40 @@ export default function (request, next) { next((response) => { - var contentType = response.headers.get('Content-Type'); + return isBlobText(response.blob()) ? new Promise((resolve) => { - if (isString(contentType) && contentType.indexOf('application/json') === 0) { + var reader = new FileReader(); - try { - response.data = response.json(); - } catch (e) { - response.data = null; - } + reader.readAsText(response.blob()); + reader.onload = () => { + response.init(reader.result); + resolve(initData(response)); + }; - } else { - response.data = response.text(); - } + }) : initData(response); }); } + +function initData(response) { + + var contentType = response.headers.get('Content-Type'); + + if (isString(contentType) && contentType.indexOf('application/json') === 0) { + + try { + response.data = response.json(); + } catch (e) { + response.data = null; + } + + } else { + response.data = response.text(); + } + + return response; +} + +function isBlobText(body) { + return body && (body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1); +} diff --git a/src/http/response.js b/src/http/response.js index 42198ae5..55888945 100644 --- a/src/http/response.js +++ b/src/http/response.js @@ -16,7 +16,17 @@ export default class Response { this.headers = new Headers(headers); this.bodyBlob = null; this.bodyText = ''; - this.initBody(body); + this.init(body); + + } + + init(body) { + + if (isBlob(body)) { + this.bodyBlob = body; + } else if (isString(body)) { + this.bodyText = body; + } } @@ -32,15 +42,4 @@ export default class Response { return JSON.parse(this.text()); } - initBody(body) { - - if (isBlob(body)) { - this.bodyBlob = body; - } - - if (isString(body)) { - this.bodyText = body; - } - } - } diff --git a/test/http.js b/test/http.js index f61faa31..d6fbfa3c 100644 --- a/test/http.js +++ b/test/http.js @@ -9,7 +9,7 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); expect(res.data).toBe('text'); - expect(res.blob() instanceof Blob).toBe(true); + expect(res.text()).toBe('text'); expect(res.headers.get('Content-Type')).toBe('text/plain'); expect(res.headers.get('Content-Length')).toBe('4'); From 1e1f851ba6f4495e8369ba8af070c75b3ce375bc Mon Sep 17 00:00:00 2001 From: Steffan Date: Mon, 22 Aug 2016 13:05:13 +0200 Subject: [PATCH 09/26] add response.body property change response blob(), text(), json(), to return a Promise --- src/http/interceptor/body.js | 50 ++++++++++++++++------------------- src/http/interceptor/jsonp.js | 9 ++++++- src/http/response.js | 44 +++++++++++++++++++++--------- test/http.js | 25 +++++++++--------- 4 files changed, 74 insertions(+), 54 deletions(-) diff --git a/src/http/interceptor/body.js b/src/http/interceptor/body.js index e6fbe03e..583a0d88 100644 --- a/src/http/interceptor/body.js +++ b/src/http/interceptor/body.js @@ -3,8 +3,7 @@ */ import Url from '../../url/index'; -import Promise from '../../promise'; -import { isString, isFormData, isPlainObject } from '../../util'; +import { when, isString, isFormData, isPlainObject } from '../../util'; export default function (request, next) { @@ -23,40 +22,37 @@ export default function (request, next) { next((response) => { - return isBlobText(response.blob()) ? new Promise((resolve) => { + Object.defineProperty(response, 'data', { - var reader = new FileReader(); + get() { + return this.body; + }, - reader.readAsText(response.blob()); - reader.onload = () => { - response.init(reader.result); - resolve(initData(response)); - }; + set(body) { + this.body = body; + } - }) : initData(response); + }); - }); -} + return response.bodyText ? when(response.text(), text => { -function initData(response) { + var type = response.headers.get('Content-Type'); - var contentType = response.headers.get('Content-Type'); + if (isString(type) && type.indexOf('application/json') === 0) { - if (isString(contentType) && contentType.indexOf('application/json') === 0) { + try { + response.body = JSON.parse(text); + } catch (e) { + response.body = null; + } - try { - response.data = response.json(); - } catch (e) { - response.data = null; - } + } else { + response.body = text; + } - } else { - response.data = response.text(); - } + return response; - return response; -} + }) : response; -function isBlobText(body) { - return body && (body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1); + }); } diff --git a/src/http/interceptor/jsonp.js b/src/http/interceptor/jsonp.js index ab92da94..160c508a 100644 --- a/src/http/interceptor/jsonp.js +++ b/src/http/interceptor/jsonp.js @@ -3,6 +3,7 @@ */ import jsonpClient from '../client/jsonp'; +import { when } from '../../util'; export default function (request, next) { @@ -13,7 +14,13 @@ export default function (request, next) { next((response) => { if (request.method == 'JSONP') { - response.data = response.json(); + + return when(response.json(), json => { + + response.body = json; + + return response; + }); } }); diff --git a/src/http/response.js b/src/http/response.js index 55888945..8c5792d9 100644 --- a/src/http/response.js +++ b/src/http/response.js @@ -3,7 +3,8 @@ */ import Headers from './headers'; -import { isBlob, isString } from '../util'; +import Promise from '../promise'; +import { when, isBlob, isString } from '../util'; export default class Response { @@ -14,32 +15,49 @@ export default class Response { this.status = status || 0; this.statusText = statusText || ''; this.headers = new Headers(headers); - this.bodyBlob = null; - this.bodyText = ''; - this.init(body); + this.body = body; - } + if (isString(body)) { + + this.bodyText = body; - init(body) { + } else if (isBlob(body)) { - if (isBlob(body)) { this.bodyBlob = body; - } else if (isString(body)) { - this.bodyText = body; - } + if (isBlobText(body)) { + this.bodyText = blobText(body); + } + } } blob() { - return this.bodyBlob; + return when(this.bodyBlob); } text() { - return this.bodyText; + return when(this.bodyText); } json() { - return JSON.parse(this.text()); + return when(this.text(), text => JSON.parse(text)); } } + +function blobText(body) { + return new Promise((resolve) => { + + var reader = new FileReader(); + + reader.readAsText(body); + reader.onload = () => { + resolve(reader.result); + }; + + }); +} + +function isBlobText(body) { + return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; +} diff --git a/test/http.js b/test/http.js index d6fbfa3c..f0262157 100644 --- a/test/http.js +++ b/test/http.js @@ -8,8 +8,7 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data).toBe('text'); - expect(res.text()).toBe('text'); + expect(res.body).toBe('text'); expect(res.headers.get('Content-Type')).toBe('text/plain'); expect(res.headers.get('Content-Length')).toBe('4'); @@ -24,8 +23,8 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data.foo).toBe('bar'); - expect(typeof res.json()).toBe('object'); + expect(typeof res.body).toBe('object'); + expect(res.body.foo).toBe('bar'); done(); }); @@ -38,7 +37,7 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data).toBeNull(); + expect(res.body).toBeNull(); done(); }); @@ -51,8 +50,8 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.text()).toBe(''); - expect(res.blob() instanceof Blob).toBe(true); + expect(res.body instanceof Blob).toBe(true); + expect(res.body.type).toBe('image/png'); done(); }); @@ -65,9 +64,9 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data.shift().requestType).toBe('cors'); + expect(typeof res.body).toBe('object'); + expect(res.body.shift().requestType).toBe('cors'); expect(res.headers.get('Content-Type')).toBe('application/json'); - expect(typeof res.json()).toBe('object'); done(); }); @@ -80,8 +79,8 @@ describe('Vue.http', function () { expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data.foo).toBe('bar'); - expect(typeof res.json()).toBe('object'); + expect(typeof res.body).toBe('object'); + expect(res.body.foo).toBe('bar'); done(); }); @@ -103,8 +102,8 @@ describe('this.$http', function () { expect(this).toBe(vm); expect(res.ok).toBe(true); expect(res.status).toBe(200); - expect(res.data.foo).toBe('bar'); - expect(typeof res.json()).toBe('object'); + expect(typeof res.body).toBe('object'); + expect(res.body.foo).toBe('bar'); done(); From 2cc53321464e6792a4102afc014191457266a5be Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 12:32:10 +0200 Subject: [PATCH 10/26] add api reference --- README.md | 1 + docs/api.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 docs/api.md diff --git a/README.md b/README.md index 00b0965d..8c11d131 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Available on [jsdelivr](https://cdn.jsdelivr.net/vue.resource/0.9.3/vue-resource - [HTTP Requests/Response](docs/http.md) - [Creating Resources](docs/resource.md) - [Code Recipes](docs/recipes.md) +- [API Reference](docs/api.md) ## Changelog diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000..ea6a8036 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,71 @@ +# API Reference + +## Request + +```js +{ + // Constructor + constructor(object: options) + + // Properties + url (string) + body (any) + headers (Headers) + method (string) + params (object) + timeout (number) + credentials (boolean) + emulateHTTP (boolean) + emulateJSON (boolean) + before (function(Request)) + progress (function(Event)) + + // Methods + getUrl() (string) + getBody() (any) + respondWith(any: body, object: options) (Response) +} +``` + +## Response + +```js +{ + // Constructor + constructor(any: body, object: {string: url, object: headers, number: status, string: statusText}) + + // Properties + url (string) + body (any) + headers (Headers) + ok (boolean) + status (number) + statusText (string) + + // Methods + blob() (Promise) + text() (Promise) + json() (Promise) +} +``` + +## Headers + +```js +{ + // Constructor + constructor(object: headers) + + // Properties + map (object) + + // Methods + has(string: name) (boolean) + get(string: name) (string) + getAll() (string[]) + set(string: name, string: value) (void) + append(string: name, string: value) (void) + delete(string: name) (void) + forEach(function: callback, any: thisArg) (void) +} +``` From 9d92f8af71619e4828b8ac5e26f9745105475051 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 12:42:23 +0200 Subject: [PATCH 11/26] update readme --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index 7af4d678..5f503c45 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,3 +4,4 @@ - [HTTP Requests/Response](http.md) - [Creating Resources](resource.md) - [Code Recipes](recipes.md) +- [API Reference](api.md) From d19e5811b5940d00f94a67a1d4ef4f290acf1812 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 12:46:02 +0200 Subject: [PATCH 12/26] update examples --- docs/http.md | 58 ++++++++++++++----------------- docs/resource.md | 90 ++++++++++++++++++++++-------------------------- 2 files changed, 66 insertions(+), 82 deletions(-) diff --git a/docs/http.md b/docs/http.md index b22e9209..a3bce8aa 100644 --- a/docs/http.md +++ b/docs/http.md @@ -7,20 +7,16 @@ The http service can be used globally `Vue.http` or in a Vue instance `this.$htt A Vue instance provides the `this.$http` service which can send HTTP requests. A request method call returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that resolves to the response. Also the Vue instance will be automatically bound to `this` in all function callbacks. ```js -new Vue({ +{ - ready() { + // GET /someUrl + this.$http.get('/someUrl').then((response) => { + // success callback + }, (response) => { + // error callback + }); - // GET /someUrl - this.$http.get('/someUrl').then((response) => { - // success callback - }, (response) => { - // error callback - }); - - } - -}) +} ``` ## Methods @@ -80,35 +76,31 @@ headers | `Object` | HTTP headers of the response ## Example ```js -new Vue({ - - ready() { - - // POST /someUrl - this.$http.post('/someUrl', {foo: 'bar'}).then((response) => { +{ - // get status - response.status; + // POST /someUrl + this.$http.post('/someUrl', {foo: 'bar'}).then((response) => { - // get status text - response.statusText; + // get status + response.status; - // get all headers - response.headers; + // get status text + response.statusText; - // get 'Expires' header - response.headers['Expires']; + // get all headers + response.headers; - // set data on vm - this.$set('someData', response.json()) + // get 'Expires' header + response.headers['Expires']; - }, (response) => { - // error callback - }); + // set data on vm + this.$set('someData', response.json()) - } + }, (response) => { + // error callback + }); -}) +} ``` ## Interceptors diff --git a/docs/resource.md b/docs/resource.md index 7834f589..3484283c 100644 --- a/docs/resource.md +++ b/docs/resource.md @@ -20,63 +20,55 @@ delete: {method: 'DELETE'} ## Example ```js -new Vue({ - - ready() { - - var resource = this.$resource('someItem{/id}'); - - // GET someItem/1 - resource.get({id: 1}).then((response) => { - this.$set('item', response.json()) - }); - - // POST someItem/1 - resource.save({id: 1}, {item: this.item}).then((response) => { - // success callback - }, (response) => { - // error callback - }); - - // DELETE someItem/1 - resource.delete({id: 1}).then((response) => { - // success callback - }, (response) => { - // error callback - }); - - } - -}) +{ + + var resource = this.$resource('someItem{/id}'); + + // GET someItem/1 + resource.get({id: 1}).then((response) => { + this.$set('item', response.json()) + }); + + // POST someItem/1 + resource.save({id: 1}, {item: this.item}).then((response) => { + // success callback + }, (response) => { + // error callback + }); + + // DELETE someItem/1 + resource.delete({id: 1}).then((response) => { + // success callback + }, (response) => { + // error callback + }); + +} ``` ## Custom Actions ```js -new Vue({ - - ready() { - - var customActions = { - foo: {method: 'GET', url: 'someItem/foo{/id}'}, - bar: {method: 'POST', url: 'someItem/bar{/id}'} - } +{ - var resource = this.$resource('someItem{/id}', {}, customActions); + var customActions = { + foo: {method: 'GET', url: 'someItem/foo{/id}'}, + bar: {method: 'POST', url: 'someItem/bar{/id}'} + } - // GET someItem/foo/1 - resource.foo({id: 1}).then((response) => { - this.$set('item', response.json()) - }); + var resource = this.$resource('someItem{/id}', {}, customActions); - // POST someItem/bar/1 - resource.bar({id: 1}, {item: this.item}).then((response) => { - // success callback - }, (response) => { - // error callback - }); + // GET someItem/foo/1 + resource.foo({id: 1}).then((response) => { + this.$set('item', response.json()) + }); - } + // POST someItem/bar/1 + resource.bar({id: 1}, {item: this.item}).then((response) => { + // success callback + }, (response) => { + // error callback + }); -}) +} ``` From b04d0e2ca8e3006908e3a6da172bef52d66331ce Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 12:48:32 +0200 Subject: [PATCH 13/26] update examples --- docs/http.md | 4 ---- docs/recipes.md | 62 ++++++++++++++++++++++++------------------------ docs/resource.md | 4 ---- 3 files changed, 31 insertions(+), 39 deletions(-) diff --git a/docs/http.md b/docs/http.md index a3bce8aa..7852cc89 100644 --- a/docs/http.md +++ b/docs/http.md @@ -8,14 +8,12 @@ A Vue instance provides the `this.$http` service which can send HTTP requests. A ```js { - // GET /someUrl this.$http.get('/someUrl').then((response) => { // success callback }, (response) => { // error callback }); - } ``` @@ -77,7 +75,6 @@ headers | `Object` | HTTP headers of the response ```js { - // POST /someUrl this.$http.post('/someUrl', {foo: 'bar'}).then((response) => { @@ -99,7 +96,6 @@ headers | `Object` | HTTP headers of the response }, (response) => { // error callback }); - } ``` diff --git a/docs/recipes.md b/docs/recipes.md index 0da6c0b5..201692db 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -8,20 +8,20 @@ Sending forms using [FormData](https://developer.mozilla.org/en-US/docs/Web/API/ ```js { - var formData = new FormData(); + var formData = new FormData(); - // append string - formData.append('foo', 'bar'); + // append string + formData.append('foo', 'bar'); - // append Blob/File object - formData.append('pic', fileInput, 'mypic.jpg'); + // append Blob/File object + formData.append('pic', fileInput, 'mypic.jpg'); - // POST /someUrl - this.$http.post('/someUrl', formData).then((response) => { - // success callback - }, (response) => { - // error callback - }); + // POST /someUrl + this.$http.post('/someUrl', formData).then((response) => { + // success callback + }, (response) => { + // error callback + }); } ``` @@ -31,25 +31,25 @@ Abort a previous request when a new request is about to be sent. For example whe ```js { - // GET /someUrl - this.$http.get('/someUrl', { - - // use before callback - before(request) { - - // abort previous request, if exists - if (this.previousRequest) { - this.previousRequest.abort(); - } - - // set previous request on Vue instance - this.previousRequest = request; - } - - }).then((response) => { - // success callback - }, (response) => { - // error callback - }); + // GET /someUrl + this.$http.get('/someUrl', { + + // use before callback + before(request) { + + // abort previous request, if exists + if (this.previousRequest) { + this.previousRequest.abort(); + } + + // set previous request on Vue instance + this.previousRequest = request; + } + + }).then((response) => { + // success callback + }, (response) => { + // error callback + }); } ``` diff --git a/docs/resource.md b/docs/resource.md index 3484283c..70a1d3af 100644 --- a/docs/resource.md +++ b/docs/resource.md @@ -21,7 +21,6 @@ delete: {method: 'DELETE'} ```js { - var resource = this.$resource('someItem{/id}'); // GET someItem/1 @@ -42,7 +41,6 @@ delete: {method: 'DELETE'} }, (response) => { // error callback }); - } ``` @@ -50,7 +48,6 @@ delete: {method: 'DELETE'} ```js { - var customActions = { foo: {method: 'GET', url: 'someItem/foo{/id}'}, bar: {method: 'POST', url: 'someItem/bar{/id}'} @@ -69,6 +66,5 @@ delete: {method: 'DELETE'} }, (response) => { // error callback }); - } ``` From cb028daf4b74264e3f5cb09352057988851316c1 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 12:51:03 +0200 Subject: [PATCH 14/26] update readme --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 8c11d131..d692282a 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,18 @@ Available on [jsdelivr](https://cdn.jsdelivr.net/vue.resource/0.9.3/vue-resource ``` +## Example +```js +{ + // GET /someUrl + this.$http.get('/someUrl').then((response) => { + // success callback + }, (response) => { + // error callback + }); +} +``` + ## Documentation - [Configuration](docs/config.md) From cca6387e62e61e37d078555baafb092bf8bf23cf Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:02:26 +0200 Subject: [PATCH 15/26] Update api.md --- docs/api.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/api.md b/docs/api.md index ea6a8036..3932a382 100644 --- a/docs/api.md +++ b/docs/api.md @@ -49,6 +49,19 @@ } ``` +Property | Type | Description +-------- | ---- | ----------- +url | `string` | Response URL origin +body | `any` | Response body data +headers | `Header` | Response Headers object +ok | `boolean` | HTTP status code between 200 and 299 +status | `number` | HTTP status code of the response +statusText | `string` | HTTP status text of the response +**Method** | **Type** | **Description** +text() | `Promise` | Resolves the body as string +json() | `Promise` | Resolves the body as parsed JSON object +blob() | `Promise` | Resolves the body as Blob object + ## Headers ```js From 799819c8207419ea325fbd6deaf88c3890bbbe3c Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:04:16 +0200 Subject: [PATCH 16/26] update docs --- docs/api.md | 17 ++--------------- docs/http.md | 14 ++++++++------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/docs/api.md b/docs/api.md index 3932a382..9f7bfd22 100644 --- a/docs/api.md +++ b/docs/api.md @@ -15,8 +15,8 @@ params (object) timeout (number) credentials (boolean) - emulateHTTP (boolean) - emulateJSON (boolean) + emulateHTTP (boolean) + emulateJSON (boolean) before (function(Request)) progress (function(Event)) @@ -49,19 +49,6 @@ } ``` -Property | Type | Description --------- | ---- | ----------- -url | `string` | Response URL origin -body | `any` | Response body data -headers | `Header` | Response Headers object -ok | `boolean` | HTTP status code between 200 and 299 -status | `number` | HTTP status code of the response -statusText | `string` | HTTP status text of the response -**Method** | **Type** | **Description** -text() | `Promise` | Resolves the body as string -json() | `Promise` | Resolves the body as parsed JSON object -blob() | `Promise` | Resolves the body as Blob object - ## Headers ```js diff --git a/docs/http.md b/docs/http.md index 7852cc89..d0078625 100644 --- a/docs/http.md +++ b/docs/http.md @@ -60,16 +60,18 @@ emulateJSON | `boolean` | Send request body as `application/x-www-form-urlencode A request resolves to a response object with the following properties and methods: -Method | Type | Description +Property | Type | Description -------- | ---- | ----------- -text() | `string` | Response body as string -json() | `Object` | Response body as parsed JSON object -blob() | `Blob` | Response body as Blob object -**Property** | **Type** | **Description** +url | `string` | Response URL origin +body | `any` | Response body data +headers | `Header` | Response Headers object ok | `boolean` | HTTP status code between 200 and 299 status | `number` | HTTP status code of the response statusText | `string` | HTTP status text of the response -headers | `Object` | HTTP headers of the response +**Method** | **Type** | **Description** +text() | `Promise` | Resolves the body as string +json() | `Promise` | Resolves the body as parsed JSON object +blob() | `Promise` | Resolves the body as Blob object ## Example From 2961d300e8444c085e7d79c7b6489b3c9428c212 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:09:44 +0200 Subject: [PATCH 17/26] update docs --- docs/http.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/http.md b/docs/http.md index d0078625..5266f168 100644 --- a/docs/http.md +++ b/docs/http.md @@ -45,10 +45,10 @@ List of shortcut methods: Parameter | Type | Description --------- | ---- | ----------- url | `string` | URL to which the request is sent +body | `Object`, `FormData`, `string` | Data to be sent as the request body +headers | `Object` | Headers object to be sent as HTTP request headers method | `string` | HTTP method (e.g. GET, POST, ...) -body | `Object`, `FormData` `string` | Data to be sent as the request body params | `Object` | Parameters object to be sent as URL parameters -headers | `Object` | Headers object to be sent as HTTP request headers timeout | `number` | Request timeout in milliseconds (`0` means no timeout) before | `function(request)` | Callback function to modify the request options before it is sent progress | `function(event)` | Callback function to handle the [ProgressEvent](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent) of uploads @@ -63,7 +63,7 @@ A request resolves to a response object with the following properties and method Property | Type | Description -------- | ---- | ----------- url | `string` | Response URL origin -body | `any` | Response body data +body | `Object`, `Blob`, `string` | Response body data headers | `Header` | Response Headers object ok | `boolean` | HTTP status code between 200 and 299 status | `number` | HTTP status code of the response From 7b2de56d8a29ce73e5aa87cd791e148d5b47cb17 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:13:14 +0200 Subject: [PATCH 18/26] update docs --- docs/http.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/http.md b/docs/http.md index 5266f168..effe862c 100644 --- a/docs/http.md +++ b/docs/http.md @@ -86,14 +86,11 @@ blob() | `Promise` | Resolves the body as Blob object // get status text response.statusText; - // get all headers - response.headers; - // get 'Expires' header - response.headers['Expires']; + response.headers.get('Expires'); // set data on vm - this.$set('someData', response.json()) + this.$set('someData', response.body) }, (response) => { // error callback From f4460184cd2dbb346bbe5bf6635a0eb1a0838fdd Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:14:12 +0200 Subject: [PATCH 19/26] update docs --- docs/http.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/http.md b/docs/http.md index effe862c..440ddc36 100644 --- a/docs/http.md +++ b/docs/http.md @@ -90,7 +90,7 @@ blob() | `Promise` | Resolves the body as Blob object response.headers.get('Expires'); // set data on vm - this.$set('someData', response.body) + this.$set('someData', response.body); }, (response) => { // error callback From 22991bf61c4cf921ef9593a954410241d5b4ad47 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:23:43 +0200 Subject: [PATCH 20/26] add image example --- docs/http.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/http.md b/docs/http.md index 440ddc36..92b9cf1c 100644 --- a/docs/http.md +++ b/docs/http.md @@ -98,6 +98,22 @@ blob() | `Promise` | Resolves the body as Blob object } ``` +Fetch an Image and use the blob() method to extract the image body content from the response. + +```js +{ + // GET /image.jpg + this.$http.get('/image.jpg').then((response) => { + + // resolve to Blob + return response.blob(); + + }).then(blob) => { + // use image Blob + }); +} +``` + ## Interceptors Interceptors can be defined globally and are used for pre- and postprocessing of a request. From 6cf0097188ef9939629cead8667418d3442ee1a8 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:26:34 +0200 Subject: [PATCH 21/26] update docs --- docs/http.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/http.md b/docs/http.md index 92b9cf1c..a7ea754f 100644 --- a/docs/http.md +++ b/docs/http.md @@ -47,8 +47,8 @@ Parameter | Type | Description url | `string` | URL to which the request is sent body | `Object`, `FormData`, `string` | Data to be sent as the request body headers | `Object` | Headers object to be sent as HTTP request headers -method | `string` | HTTP method (e.g. GET, POST, ...) params | `Object` | Parameters object to be sent as URL parameters +method | `string` | HTTP method (e.g. GET, POST, ...) timeout | `number` | Request timeout in milliseconds (`0` means no timeout) before | `function(request)` | Callback function to modify the request options before it is sent progress | `function(event)` | Callback function to handle the [ProgressEvent](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent) of uploads From a70de8e8c5a67c8da4eb936ae6ea4aa4e1fb18ed Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:27:39 +0200 Subject: [PATCH 22/26] update docs --- docs/http.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/http.md b/docs/http.md index a7ea754f..7177a9bb 100644 --- a/docs/http.md +++ b/docs/http.md @@ -98,7 +98,7 @@ blob() | `Promise` | Resolves the body as Blob object } ``` -Fetch an Image and use the blob() method to extract the image body content from the response. +Fetch an image and use the blob() method to extract the image body content from the response. ```js { From 1a38c6c1835c580cf2187f899eac3943f4c685ad Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:31:00 +0200 Subject: [PATCH 23/26] update docs --- docs/config.md | 10 +++++----- docs/http.md | 52 ++++++++++++++++++++++++------------------------ docs/resource.md | 20 +++++++++---------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/docs/config.md b/docs/config.md index 4dd02170..4a0e11b1 100644 --- a/docs/config.md +++ b/docs/config.md @@ -12,12 +12,12 @@ Set default values inside your Vue component options. ```js new Vue({ - http: { - root: '/root', - headers: { - Authorization: 'Basic YXBpOnBhc3N3b3Jk' - } + http: { + root: '/root', + headers: { + Authorization: 'Basic YXBpOnBhc3N3b3Jk' } + } }) ``` diff --git a/docs/http.md b/docs/http.md index 7177a9bb..41ca2fdb 100644 --- a/docs/http.md +++ b/docs/http.md @@ -80,20 +80,20 @@ blob() | `Promise` | Resolves the body as Blob object // POST /someUrl this.$http.post('/someUrl', {foo: 'bar'}).then((response) => { - // get status - response.status; + // get status + response.status; - // get status text - response.statusText; + // get status text + response.statusText; - // get 'Expires' header - response.headers.get('Expires'); + // get 'Expires' header + response.headers.get('Expires'); - // set data on vm - this.$set('someData', response.body); + // set data on vm + this.$set('someData', response.body); }, (response) => { - // error callback + // error callback }); } ``` @@ -122,11 +122,11 @@ Interceptors can be defined globally and are used for pre- and postprocessing of ```js Vue.http.interceptors.push((request, next) => { - // modify request - request.method = 'POST'; + // modify request + request.method = 'POST'; - // continue to next interceptor - next(); + // continue to next interceptor + next(); }); ``` @@ -134,16 +134,16 @@ Vue.http.interceptors.push((request, next) => { ```js Vue.http.interceptors.push((request, next) => { - // modify request - request.method = 'POST'; + // modify request + request.method = 'POST'; - // continue to next interceptor - next((response) => { + // continue to next interceptor + next((response) => { - // modify response - response.body = '...'; + // modify response + response.body = '...'; - }); + }); }); ``` @@ -151,12 +151,12 @@ Vue.http.interceptors.push((request, next) => { ```js Vue.http.interceptors.push((request, next) => { - // modify request ... + // modify request ... - // stop and return response - next(request.respondWith(body, { - status: 404, - statusText: 'Not found' - })); + // stop and return response + next(request.respondWith(body, { + status: 404, + statusText: 'Not found' + })); }); ``` diff --git a/docs/resource.md b/docs/resource.md index 70a1d3af..cc390fd1 100644 --- a/docs/resource.md +++ b/docs/resource.md @@ -25,21 +25,21 @@ delete: {method: 'DELETE'} // GET someItem/1 resource.get({id: 1}).then((response) => { - this.$set('item', response.json()) + this.$set('item', response.json()) }); // POST someItem/1 resource.save({id: 1}, {item: this.item}).then((response) => { - // success callback + // success callback }, (response) => { - // error callback + // error callback }); // DELETE someItem/1 resource.delete({id: 1}).then((response) => { - // success callback + // success callback }, (response) => { - // error callback + // error callback }); } ``` @@ -49,22 +49,22 @@ delete: {method: 'DELETE'} ```js { var customActions = { - foo: {method: 'GET', url: 'someItem/foo{/id}'}, - bar: {method: 'POST', url: 'someItem/bar{/id}'} + foo: {method: 'GET', url: 'someItem/foo{/id}'}, + bar: {method: 'POST', url: 'someItem/bar{/id}'} } var resource = this.$resource('someItem{/id}', {}, customActions); // GET someItem/foo/1 resource.foo({id: 1}).then((response) => { - this.$set('item', response.json()) + this.$set('item', response.json()) }); // POST someItem/bar/1 resource.bar({id: 1}, {item: this.item}).then((response) => { - // success callback + // success callback }, (response) => { - // error callback + // error callback }); } ``` From 3fb8afd9f64a15fd09a1cf4275e3dec6ba0c087c Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 13:41:47 +0200 Subject: [PATCH 24/26] fix merge bug, #367 --- src/resource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resource.js b/src/resource.js index a79fdd8b..dd90d8df 100644 --- a/src/resource.js +++ b/src/resource.js @@ -16,7 +16,7 @@ export default function Resource(url, params, actions, options) { each(actions, (action, name) => { - action = merge({url, params: params || {}}, options, action); + action = merge({url, params: assign({}, params)}, options, action); resource[name] = function () { return (self.$http || Http)(opts(action, arguments)); From 64c214f89e62ae9658172c8a15de799112b3e9c3 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 14:15:16 +0200 Subject: [PATCH 25/26] update dev dependencies --- README.md | 2 +- package.json | 17 ++++++++--------- test/webpack.config.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d692282a..61dc5389 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The plugin for [Vue.js](http://vuejs.org) provides services for making web reque - Supports the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) API and [URI Templates](https://medialize.github.io/URI.js/uri-template.html) - Supports [interceptors](docs/http.md#interceptors) for request and response - Supports latest Firefox, Chrome, Safari, Opera and IE9+ -- Compact size 12KB (4.5KB gzipped) +- Compact size 14KB (5.3KB gzipped) ## Installation diff --git a/package.json b/package.json index 4aff7657..c5a25fab 100644 --- a/package.json +++ b/package.json @@ -25,19 +25,18 @@ "release": "node build/release.js" }, "devDependencies": { - "babel-core": "^6.13.2", - "babel-loader": "^6.2.4", - "babel-plugin-transform-runtime": "^6.12.0", - "babel-preset-es2015-loose": "^7.0.0", + "babel-core": "^6.14.0", + "babel-loader": "^6.2.5", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-preset-es2015": "^6.14.0", "babel-preset-es2015-loose-rollup": "^7.0.0", - "babel-runtime": "^6.11.6", "generate-release": "^0.10.1", - "jasmine-core": "^2.3.4", + "jasmine-core": "^2.5.0", "replace-in-file": "^2.0.1", - "rollup": "^0.34.8", + "rollup": "^0.34.13", "rollup-plugin-babel": "^2.6.1", - "uglify-js": "^2.7.1", + "uglify-js": "^2.7.3", "vue": "^1.0.26", - "webpack": "^1.13.1" + "webpack": "2.1.0-beta.21" } } diff --git a/test/webpack.config.js b/test/webpack.config.js index e5022a69..a7c5910c 100644 --- a/test/webpack.config.js +++ b/test/webpack.config.js @@ -6,7 +6,7 @@ module.exports = { }, module: { loaders: [ - {test: /.js/, exclude: /node_modules/, loader: 'babel', query: {presets: ['es2015-loose']}} + {test: /.js/, exclude: /node_modules/, loader: 'babel', query: {presets: [['es2015', {modules: false}]]}} ] } }; From 93d687e29af773bf4d012760dd569a1f881d8126 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 4 Sep 2016 14:24:22 +0200 Subject: [PATCH 26/26] v1.0.0 --- README.md | 4 +- bower.json | 2 +- dist/vue-resource.common.js | 681 +++++++---- dist/vue-resource.es2015.js | 681 +++++++---- dist/vue-resource.js | 2235 +++++++++++++++++++---------------- dist/vue-resource.min.js | 4 +- package.json | 2 +- 7 files changed, 2097 insertions(+), 1512 deletions(-) diff --git a/README.md b/README.md index 61dc5389..03372e32 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ $ bower install vue-resource ``` ### CDN -Available on [jsdelivr](https://cdn.jsdelivr.net/vue.resource/0.9.3/vue-resource.min.js), [cdnjs](https://cdnjs.com/libraries/vue-resource) or [npmcdn](https://npmcdn.com/vue-resource@0.9.3/dist/vue-resource.min.js). +Available on [jsdelivr](https://cdn.jsdelivr.net/vue.resource/1.0.0/vue-resource.min.js), [cdnjs](https://cdnjs.com/libraries/vue-resource) or [npmcdn](https://npmcdn.com/vue-resource@1.0.0/dist/vue-resource.min.js). ```html - + ``` ## Example diff --git a/bower.json b/bower.json index db3680ae..035cef1f 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "vue-resource", "main": "dist/vue-resource.js", - "version": "0.9.3", + "version": "1.0.0", "description": "The HTTP client for Vue.js", "homepage": "https://github.com/vuejs/vue-resource", "license": "MIT", diff --git a/dist/vue-resource.common.js b/dist/vue-resource.common.js index 51e4d79e..97a08f12 100644 --- a/dist/vue-resource.common.js +++ b/dist/vue-resource.common.js @@ -1,5 +1,5 @@ /*! - * vue-resource v0.9.3 + * vue-resource v1.0.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ @@ -7,182 +7,10 @@ 'use strict'; /** - * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + * Promise adapter. */ -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 === '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; +var PromiseObj = window.Promise; function Promise$1(executor, context) { @@ -251,9 +79,13 @@ p.finally = function (callback) { }); }; -var debug = false; -var util = {}; -var array = []; +/** + * Utility functions. + */ + +var debug = false;var util = {};var slice = [].slice; + + function Util (Vue) { util = Vue.util; debug = Vue.config.debug || !Vue.config.silent; @@ -279,6 +111,14 @@ function trim(str) { return str.replace(/^\s*|\s*$/g, ''); } +function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +function toUpper(str) { + return str ? str.toUpperCase() : ''; +} + var isArray = Array.isArray; function isString(val) { @@ -301,6 +141,10 @@ function isPlainObject(obj) { return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; } +function isBlob(obj) { + return typeof Blob !== 'undefined' && obj instanceof Blob; +} + function isFormData(obj) { return typeof FormData !== 'undefined' && obj instanceof FormData; } @@ -331,7 +175,7 @@ function each(obj, iterator) { var i, key; - if (typeof obj.length == 'number') { + if (obj && typeof obj.length == 'number') { for (i = 0; i < obj.length; i++) { iterator.call(obj[i], obj[i], i); } @@ -350,7 +194,7 @@ var assign = Object.assign || _assign; function merge(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { _merge(target, source, true); @@ -361,7 +205,7 @@ function merge(target) { function defaults(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { @@ -377,7 +221,7 @@ function defaults(target) { function _assign(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { _merge(target, source); @@ -402,6 +246,10 @@ function _merge(target, source, deep) { } } +/** + * Root Prefix Transform. + */ + function root (options, next) { var url = next(options); @@ -413,6 +261,10 @@ function root (options, next) { return url; } +/** + * Query Parameter Transform. + */ + function query (options, next) { var urlParams = Object.keys(Url.options.params), @@ -588,6 +440,10 @@ function encodeReserved(str) { }).join(''); } +/** + * URL Template (RFC 6570) Transform. + */ + function template (options) { var variables = [], @@ -728,6 +584,10 @@ function serialize(params, obj, scope) { }); } +/** + * XDomain client (Internet Explorer). + */ + function xdrClient (request) { return new Promise$1(function (resolve) { @@ -756,6 +616,10 @@ function xdrClient (request) { }); } +/** + * CORS Interceptor. + */ + var ORIGIN_URL = Url.parse(location.href); var SUPPORTS_CORS = 'withCredentials' in new XMLHttpRequest(); @@ -784,15 +648,19 @@ function crossOrigin(request) { return requestUrl.protocol !== ORIGIN_URL.protocol || requestUrl.host !== ORIGIN_URL.host; } +/** + * Body Interceptor. + */ + function body (request, next) { if (request.emulateJSON && isPlainObject(request.body)) { request.body = Url.params(request.body); - request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); } if (isFormData(request.body)) { - delete request.headers['Content-Type']; + request.headers.delete('Content-Type'); } if (isPlainObject(request.body)) { @@ -801,21 +669,39 @@ function body (request, next) { next(function (response) { - var contentType = response.headers['Content-Type']; + Object.defineProperty(response, 'data', { + get: function () { + return this.body; + }, + set: function (body) { + this.body = body; + } + }); + + return response.bodyText ? when(response.text(), function (text) { - if (isString(contentType) && contentType.indexOf('application/json') === 0) { + var type = response.headers.get('Content-Type'); - try { - response.data = response.json(); - } catch (e) { - response.data = null; + if (isString(type) && type.indexOf('application/json') === 0) { + + try { + response.body = JSON.parse(text); + } catch (e) { + response.body = null; + } + } else { + response.body = text; } - } else { - response.data = response.text(); - } + + return response; + }) : response; }); } +/** + * JSONP client. + */ + function jsonpClient (request) { return new Promise$1(function (resolve) { @@ -858,6 +744,10 @@ function jsonpClient (request) { }); } +/** + * JSONP Interceptor. + */ + function jsonp (request, next) { if (request.method == 'JSONP') { @@ -867,11 +757,21 @@ function jsonp (request, next) { next(function (response) { if (request.method == 'JSONP') { - response.data = response.json(); + + return when(response.json(), function (json) { + + response.body = json; + + return response; + }); } }); } +/** + * Before Interceptor. + */ + function before (request, next) { if (isFunction(request.before)) { @@ -888,17 +788,26 @@ function before (request, next) { function method (request, next) { if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { - request.headers['X-HTTP-Method-Override'] = request.method; + request.headers.set('X-HTTP-Method-Override', request.method); request.method = 'POST'; } next(); } +/** + * Header Interceptor. + */ + function header (request, next) { - request.method = request.method.toUpperCase(); - request.headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); + var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[toLower(request.method)]); + + each(headers, function (value, name) { + if (!request.headers.has(name)) { + request.headers.set(name, value); + } + }); next(); } @@ -923,6 +832,10 @@ function timeout (request, next) { }); } +/** + * XMLHttp client. + */ + function xhrClient (request) { return new Promise$1(function (resolve) { @@ -931,8 +844,11 @@ function xhrClient (request) { var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug - statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText), - headers: parseHeaders(xhr.getAllResponseHeaders()) + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) + }); + + each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { + response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); }); resolve(response); @@ -955,46 +871,25 @@ function xhrClient (request) { } } + if ('responseType' in xhr) { + xhr.responseType = 'blob'; + } + if (request.credentials === true) { xhr.withCredentials = true; } - each(request.headers || {}, function (value, header) { - xhr.setRequestHeader(header, value); + request.headers.forEach(function (value, name) { + xhr.setRequestHeader(name, value); }); xhr.send(request.getBody()); }); } -function parseHeaders(str) { - - var headers = {}, - value, - name, - i; - - each(trim(str).split('\n'), function (row) { - - i = row.indexOf(':'); - name = trim(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; -} +/** + * Base client. + */ function Client (context) { @@ -1066,6 +961,80 @@ var classCallCheck = function (instance, Constructor) { } }; +/** + * HTTP Headers. + */ + +var Headers = function () { + function Headers(headers) { + var _this = this; + + classCallCheck(this, Headers); + + + this.map = {}; + + each(headers, function (value, name) { + return _this.append(name, value); + }); + } + + Headers.prototype.has = function has(name) { + return this.map.hasOwnProperty(normalizeName(name)); + }; + + Headers.prototype.get = function get(name) { + + var list = this.map[normalizeName(name)]; + + return list ? list[0] : null; + }; + + Headers.prototype.getAll = function getAll(name) { + return this.map[normalizeName(name)] || []; + }; + + Headers.prototype.set = function set(name, value) { + this.map[normalizeName(name)] = [trim(value)]; + }; + + Headers.prototype.append = function append(name, value) { + + var list = this.map[normalizeName(name)]; + + if (!list) { + list = this.map[normalizeName(name)] = []; + } + + list.push(trim(value)); + }; + + Headers.prototype.delete = function _delete(name) { + delete this.map[normalizeName(name)]; + }; + + Headers.prototype.forEach = function forEach(callback, thisArg) { + var _this2 = this; + + each(this.map, function (list, name) { + each(list, function (value) { + return callback.call(thisArg, value, name, _this2); + }); + }); + }; + + return Headers; +}(); + +function normalizeName(name) { + + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name'); + } + + return toLower(trim(name)); +} + /** * HTTP Response. */ @@ -1080,39 +1049,74 @@ var Response = function () { this.url = url; - this.body = body; - this.headers = headers || {}; + this.ok = status >= 200 && status < 300; this.status = status || 0; this.statusText = statusText || ''; - this.ok = status >= 200 && status < 300; + this.headers = new Headers(headers); + this.body = body; + + if (isString(body)) { + + this.bodyText = body; + } else if (isBlob(body)) { + + this.bodyBlob = body; + + if (isBlobText(body)) { + this.bodyText = blobText(body); + } + } } - Response.prototype.text = function text() { - return this.body; + Response.prototype.blob = function blob() { + return when(this.bodyBlob); }; - Response.prototype.blob = function blob() { - return new Blob([this.body]); + Response.prototype.text = function text() { + return when(this.bodyText); }; Response.prototype.json = function json() { - return JSON.parse(this.body); + return when(this.text(), function (text) { + return JSON.parse(text); + }); }; return Response; }(); +function blobText(body) { + return new Promise$1(function (resolve) { + + var reader = new FileReader(); + + reader.readAsText(body); + reader.onload = function () { + resolve(reader.result); + }; + }); +} + +function isBlobText(body) { + return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; +} + +/** + * HTTP Request. + */ + var Request = function () { function Request(options) { classCallCheck(this, Request); - this.method = 'GET'; this.body = null; this.params = {}; - this.headers = {}; - assign(this, options); + assign(this, options, { + method: toUpper(options.method || 'GET'), + headers: new Headers(options.headers) + }); } Request.prototype.getUrl = function getUrl() { @@ -1189,6 +1193,186 @@ Http.interceptors = [before, timeout, method, body, jsonp, header, cors]; }; }); +/** + * 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 === '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); +}; + +/** + * Service for interacting with RESTful services. + */ + function Resource(url, params, actions, options) { var self = this || {}, @@ -1198,7 +1382,7 @@ function Resource(url, params, actions, options) { each(actions, function (action, name) { - action = merge({ url: url, params: params || {} }, options, action); + action = merge({ url: url, params: assign({}, params) }, options, action); resource[name] = function () { return (self.$http || Http)(opts(action, arguments)); @@ -1259,6 +1443,10 @@ Resource.actions = { }; +/** + * Install plugin. + */ + function plugin(Vue) { if (plugin.installed) { @@ -1305,8 +1493,15 @@ function plugin(Vue) { }); } -if (typeof window !== 'undefined' && window.Vue) { - window.Vue.use(plugin); +if (typeof window !== 'undefined') { + + if (!window.Promise) { + window.Promise = Promise$2; + } + + if (window.Vue) { + window.Vue.use(plugin); + } } module.exports = plugin; \ No newline at end of file diff --git a/dist/vue-resource.es2015.js b/dist/vue-resource.es2015.js index bfc12498..e2aa1f7b 100644 --- a/dist/vue-resource.es2015.js +++ b/dist/vue-resource.es2015.js @@ -1,186 +1,14 @@ /*! - * vue-resource v0.9.3 + * vue-resource v1.0.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ /** - * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + * Promise adapter. */ -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 === '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; +var PromiseObj = window.Promise; function Promise$1(executor, context) { @@ -249,9 +77,13 @@ p.finally = function (callback) { }); }; -var debug = false; -var util = {}; -var array = []; +/** + * Utility functions. + */ + +var debug = false;var util = {};var slice = [].slice; + + function Util (Vue) { util = Vue.util; debug = Vue.config.debug || !Vue.config.silent; @@ -277,6 +109,14 @@ function trim(str) { return str.replace(/^\s*|\s*$/g, ''); } +function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +function toUpper(str) { + return str ? str.toUpperCase() : ''; +} + var isArray = Array.isArray; function isString(val) { @@ -299,6 +139,10 @@ function isPlainObject(obj) { return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; } +function isBlob(obj) { + return typeof Blob !== 'undefined' && obj instanceof Blob; +} + function isFormData(obj) { return typeof FormData !== 'undefined' && obj instanceof FormData; } @@ -329,7 +173,7 @@ function each(obj, iterator) { var i, key; - if (typeof obj.length == 'number') { + if (obj && typeof obj.length == 'number') { for (i = 0; i < obj.length; i++) { iterator.call(obj[i], obj[i], i); } @@ -348,7 +192,7 @@ var assign = Object.assign || _assign; function merge(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { _merge(target, source, true); @@ -359,7 +203,7 @@ function merge(target) { function defaults(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { @@ -375,7 +219,7 @@ function defaults(target) { function _assign(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); args.forEach(function (source) { _merge(target, source); @@ -400,6 +244,10 @@ function _merge(target, source, deep) { } } +/** + * Root Prefix Transform. + */ + function root (options, next) { var url = next(options); @@ -411,6 +259,10 @@ function root (options, next) { return url; } +/** + * Query Parameter Transform. + */ + function query (options, next) { var urlParams = Object.keys(Url.options.params), @@ -586,6 +438,10 @@ function encodeReserved(str) { }).join(''); } +/** + * URL Template (RFC 6570) Transform. + */ + function template (options) { var variables = [], @@ -726,6 +582,10 @@ function serialize(params, obj, scope) { }); } +/** + * XDomain client (Internet Explorer). + */ + function xdrClient (request) { return new Promise$1(function (resolve) { @@ -754,6 +614,10 @@ function xdrClient (request) { }); } +/** + * CORS Interceptor. + */ + var ORIGIN_URL = Url.parse(location.href); var SUPPORTS_CORS = 'withCredentials' in new XMLHttpRequest(); @@ -782,15 +646,19 @@ function crossOrigin(request) { return requestUrl.protocol !== ORIGIN_URL.protocol || requestUrl.host !== ORIGIN_URL.host; } +/** + * Body Interceptor. + */ + function body (request, next) { if (request.emulateJSON && isPlainObject(request.body)) { request.body = Url.params(request.body); - request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); } if (isFormData(request.body)) { - delete request.headers['Content-Type']; + request.headers.delete('Content-Type'); } if (isPlainObject(request.body)) { @@ -799,21 +667,39 @@ function body (request, next) { next(function (response) { - var contentType = response.headers['Content-Type']; + Object.defineProperty(response, 'data', { + get: function () { + return this.body; + }, + set: function (body) { + this.body = body; + } + }); + + return response.bodyText ? when(response.text(), function (text) { - if (isString(contentType) && contentType.indexOf('application/json') === 0) { + var type = response.headers.get('Content-Type'); - try { - response.data = response.json(); - } catch (e) { - response.data = null; + if (isString(type) && type.indexOf('application/json') === 0) { + + try { + response.body = JSON.parse(text); + } catch (e) { + response.body = null; + } + } else { + response.body = text; } - } else { - response.data = response.text(); - } + + return response; + }) : response; }); } +/** + * JSONP client. + */ + function jsonpClient (request) { return new Promise$1(function (resolve) { @@ -856,6 +742,10 @@ function jsonpClient (request) { }); } +/** + * JSONP Interceptor. + */ + function jsonp (request, next) { if (request.method == 'JSONP') { @@ -865,11 +755,21 @@ function jsonp (request, next) { next(function (response) { if (request.method == 'JSONP') { - response.data = response.json(); + + return when(response.json(), function (json) { + + response.body = json; + + return response; + }); } }); } +/** + * Before Interceptor. + */ + function before (request, next) { if (isFunction(request.before)) { @@ -886,17 +786,26 @@ function before (request, next) { function method (request, next) { if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { - request.headers['X-HTTP-Method-Override'] = request.method; + request.headers.set('X-HTTP-Method-Override', request.method); request.method = 'POST'; } next(); } +/** + * Header Interceptor. + */ + function header (request, next) { - request.method = request.method.toUpperCase(); - request.headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); + var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[toLower(request.method)]); + + each(headers, function (value, name) { + if (!request.headers.has(name)) { + request.headers.set(name, value); + } + }); next(); } @@ -921,6 +830,10 @@ function timeout (request, next) { }); } +/** + * XMLHttp client. + */ + function xhrClient (request) { return new Promise$1(function (resolve) { @@ -929,8 +842,11 @@ function xhrClient (request) { var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug - statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText), - headers: parseHeaders(xhr.getAllResponseHeaders()) + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) + }); + + each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { + response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); }); resolve(response); @@ -953,46 +869,25 @@ function xhrClient (request) { } } + if ('responseType' in xhr) { + xhr.responseType = 'blob'; + } + if (request.credentials === true) { xhr.withCredentials = true; } - each(request.headers || {}, function (value, header) { - xhr.setRequestHeader(header, value); + request.headers.forEach(function (value, name) { + xhr.setRequestHeader(name, value); }); xhr.send(request.getBody()); }); } -function parseHeaders(str) { - - var headers = {}, - value, - name, - i; - - each(trim(str).split('\n'), function (row) { - - i = row.indexOf(':'); - name = trim(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; -} +/** + * Base client. + */ function Client (context) { @@ -1064,6 +959,80 @@ var classCallCheck = function (instance, Constructor) { } }; +/** + * HTTP Headers. + */ + +var Headers = function () { + function Headers(headers) { + var _this = this; + + classCallCheck(this, Headers); + + + this.map = {}; + + each(headers, function (value, name) { + return _this.append(name, value); + }); + } + + Headers.prototype.has = function has(name) { + return this.map.hasOwnProperty(normalizeName(name)); + }; + + Headers.prototype.get = function get(name) { + + var list = this.map[normalizeName(name)]; + + return list ? list[0] : null; + }; + + Headers.prototype.getAll = function getAll(name) { + return this.map[normalizeName(name)] || []; + }; + + Headers.prototype.set = function set(name, value) { + this.map[normalizeName(name)] = [trim(value)]; + }; + + Headers.prototype.append = function append(name, value) { + + var list = this.map[normalizeName(name)]; + + if (!list) { + list = this.map[normalizeName(name)] = []; + } + + list.push(trim(value)); + }; + + Headers.prototype.delete = function _delete(name) { + delete this.map[normalizeName(name)]; + }; + + Headers.prototype.forEach = function forEach(callback, thisArg) { + var _this2 = this; + + each(this.map, function (list, name) { + each(list, function (value) { + return callback.call(thisArg, value, name, _this2); + }); + }); + }; + + return Headers; +}(); + +function normalizeName(name) { + + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name'); + } + + return toLower(trim(name)); +} + /** * HTTP Response. */ @@ -1078,39 +1047,74 @@ var Response = function () { this.url = url; - this.body = body; - this.headers = headers || {}; + this.ok = status >= 200 && status < 300; this.status = status || 0; this.statusText = statusText || ''; - this.ok = status >= 200 && status < 300; + this.headers = new Headers(headers); + this.body = body; + + if (isString(body)) { + + this.bodyText = body; + } else if (isBlob(body)) { + + this.bodyBlob = body; + + if (isBlobText(body)) { + this.bodyText = blobText(body); + } + } } - Response.prototype.text = function text() { - return this.body; + Response.prototype.blob = function blob() { + return when(this.bodyBlob); }; - Response.prototype.blob = function blob() { - return new Blob([this.body]); + Response.prototype.text = function text() { + return when(this.bodyText); }; Response.prototype.json = function json() { - return JSON.parse(this.body); + return when(this.text(), function (text) { + return JSON.parse(text); + }); }; return Response; }(); +function blobText(body) { + return new Promise$1(function (resolve) { + + var reader = new FileReader(); + + reader.readAsText(body); + reader.onload = function () { + resolve(reader.result); + }; + }); +} + +function isBlobText(body) { + return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; +} + +/** + * HTTP Request. + */ + var Request = function () { function Request(options) { classCallCheck(this, Request); - this.method = 'GET'; this.body = null; this.params = {}; - this.headers = {}; - assign(this, options); + assign(this, options, { + method: toUpper(options.method || 'GET'), + headers: new Headers(options.headers) + }); } Request.prototype.getUrl = function getUrl() { @@ -1187,6 +1191,186 @@ Http.interceptors = [before, timeout, method, body, jsonp, header, cors]; }; }); +/** + * 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 === '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); +}; + +/** + * Service for interacting with RESTful services. + */ + function Resource(url, params, actions, options) { var self = this || {}, @@ -1196,7 +1380,7 @@ function Resource(url, params, actions, options) { each(actions, function (action, name) { - action = merge({ url: url, params: params || {} }, options, action); + action = merge({ url: url, params: assign({}, params) }, options, action); resource[name] = function () { return (self.$http || Http)(opts(action, arguments)); @@ -1257,6 +1441,10 @@ Resource.actions = { }; +/** + * Install plugin. + */ + function plugin(Vue) { if (plugin.installed) { @@ -1303,8 +1491,15 @@ function plugin(Vue) { }); } -if (typeof window !== 'undefined' && window.Vue) { - window.Vue.use(plugin); +if (typeof window !== 'undefined') { + + if (!window.Promise) { + window.Promise = Promise$2; + } + + if (window.Vue) { + window.Vue.use(plugin); + } } export default plugin; diff --git a/dist/vue-resource.js b/dist/vue-resource.js index d7981dbe..0c09255f 100644 --- a/dist/vue-resource.js +++ b/dist/vue-resource.js @@ -1,5 +1,5 @@ /*! - * vue-resource v0.9.3 + * vue-resource v1.0.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ @@ -8,1311 +8,1506 @@ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.VueResource = factory()); -}(this, function () { 'use strict'; +}(this, (function () { 'use strict'; - /** - * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) - */ +/** + * Promise adapter. + */ - var RESOLVED = 0; - var REJECTED = 1; - var PENDING = 2; +var PromiseObj = window.Promise; - function Promise$2(executor) { +function Promise$1(executor, context) { - this.state = PENDING; - this.value = undefined; - this.deferred = []; + if (executor instanceof PromiseObj) { + this.promise = executor; + } else { + this.promise = new PromiseObj(executor.bind(context)); + } - var promise = this; + this.context = context; +} - try { - executor(function (x) { - promise.resolve(x); - }, function (r) { - promise.reject(r); - }); - } catch (e) { - promise.reject(e); - } - } +Promise$1.all = function (iterable, context) { + return new Promise$1(PromiseObj.all(iterable), context); +}; - 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 === '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.resolve = function (value, context) { + return new Promise$1(PromiseObj.resolve(value), context); +}; - Promise$1.all = function (iterable, context) { - return new Promise$1(PromiseObj.all(iterable), context); - }; +Promise$1.reject = function (reason, context) { + return new Promise$1(PromiseObj.reject(reason), context); +}; - Promise$1.resolve = function (value, context) { - return new Promise$1(PromiseObj.resolve(value), context); - }; +Promise$1.race = function (iterable, context) { + return new Promise$1(PromiseObj.race(iterable), context); +}; - Promise$1.reject = function (reason, context) { - return new Promise$1(PromiseObj.reject(reason), context); - }; +var p = Promise$1.prototype; - Promise$1.race = function (iterable, context) { - return new Promise$1(PromiseObj.race(iterable), context); - }; +p.bind = function (context) { + this.context = context; + return this; +}; - var p = Promise$1.prototype; +p.then = function (fulfilled, rejected) { - p.bind = function (context) { - this.context = context; - return this; - }; + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } - p.then = function (fulfilled, rejected) { + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } - if (fulfilled && fulfilled.bind && this.context) { - fulfilled = fulfilled.bind(this.context); - } + return new Promise$1(this.promise.then(fulfilled, rejected), this.context); +}; - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } +p.catch = function (rejected) { - return new Promise$1(this.promise.then(fulfilled, rejected), this.context); - }; + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } - p.catch = function (rejected) { + return new Promise$1(this.promise.catch(rejected), this.context); +}; - if (rejected && rejected.bind && this.context) { - rejected = rejected.bind(this.context); - } +p.finally = function (callback) { - return new Promise$1(this.promise.catch(rejected), this.context); - }; + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return PromiseObj.reject(reason); + }); +}; - p.finally = function (callback) { +/** + * Utility functions. + */ - return this.then(function (value) { - callback.call(this); - return value; - }, function (reason) { - callback.call(this); - return PromiseObj.reject(reason); - }); - }; +var debug = false;var util = {};var slice = [].slice; - var debug = false; - var util = {}; - var array = []; - function Util (Vue) { - util = Vue.util; - debug = Vue.config.debug || !Vue.config.silent; - } - function warn(msg) { - if (typeof console !== 'undefined' && debug) { - console.warn('[VueResource warn]: ' + msg); - } - } +function Util (Vue) { + util = Vue.util; + debug = Vue.config.debug || !Vue.config.silent; +} - function error(msg) { - if (typeof console !== 'undefined') { - console.error(msg); - } - } +function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } +} - function nextTick(cb, ctx) { - return util.nextTick(cb, ctx); - } +function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } +} - function trim(str) { - return str.replace(/^\s*|\s*$/g, ''); - } +function nextTick(cb, ctx) { + return util.nextTick(cb, ctx); +} - var isArray = Array.isArray; +function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); +} - function isString(val) { - return typeof val === 'string'; - } +function toLower(str) { + return str ? str.toLowerCase() : ''; +} - function isBoolean(val) { - return val === true || val === false; - } +function toUpper(str) { + return str ? str.toUpperCase() : ''; +} - function isFunction(val) { - return typeof val === 'function'; - } +var isArray = Array.isArray; - function isObject(obj) { - return obj !== null && typeof obj === 'object'; - } +function isString(val) { + return typeof val === 'string'; +} - function isPlainObject(obj) { - return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; - } +function isBoolean(val) { + return val === true || val === false; +} - function isFormData(obj) { - return typeof FormData !== 'undefined' && obj instanceof FormData; - } +function isFunction(val) { + return typeof val === 'function'; +} - function when(value, fulfilled, rejected) { +function isObject(obj) { + return obj !== null && typeof obj === 'object'; +} - var promise = Promise$1.resolve(value); +function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} - if (arguments.length < 2) { - return promise; - } +function isBlob(obj) { + return typeof Blob !== 'undefined' && obj instanceof Blob; +} - return promise.then(fulfilled, rejected); - } +function isFormData(obj) { + return typeof FormData !== 'undefined' && obj instanceof FormData; +} - function options(fn, obj, opts) { +function when(value, fulfilled, rejected) { - opts = opts || {}; + var promise = Promise$1.resolve(value); - if (isFunction(opts)) { - opts = opts.call(obj); - } + if (arguments.length < 2) { + return promise; + } - return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); - } + return promise.then(fulfilled, rejected); +} - function each(obj, iterator) { +function options(fn, obj, opts) { - var i, key; + opts = opts || {}; - 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 (isFunction(opts)) { + opts = opts.call(obj); + } - return obj; - } + return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); +} - var assign = Object.assign || _assign; +function each(obj, iterator) { - function merge(target) { + var i, key; - var args = array.slice.call(arguments, 1); + if (obj && 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); + } + } + } - args.forEach(function (source) { - _merge(target, source, true); - }); + return obj; +} - return target; - } +var assign = Object.assign || _assign; - function defaults(target) { +function merge(target) { - var args = array.slice.call(arguments, 1); + var args = slice.call(arguments, 1); - args.forEach(function (source) { + args.forEach(function (source) { + _merge(target, source, true); + }); - for (var key in source) { - if (target[key] === undefined) { - target[key] = source[key]; - } - } - }); + return target; +} - return target; - } +function defaults(target) { - function _assign(target) { + var args = slice.call(arguments, 1); - var args = array.slice.call(arguments, 1); + args.forEach(function (source) { - args.forEach(function (source) { - _merge(target, source); - }); + for (var key in source) { + if (target[key] === undefined) { + target[key] = source[key]; + } + } + }); - return target; - } + 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 _assign(target) { - function root (options, next) { + var args = slice.call(arguments, 1); - var url = next(options); + args.forEach(function (source) { + _merge(target, source); + }); - if (isString(options.root) && !url.match(/^(https?:)?\//)) { - url = options.root + '/' + url; - } + return target; +} - return url; - } +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 query (options, next) { +/** + * Root Prefix Transform. + */ - var urlParams = Object.keys(Url.options.params), - query = {}, - url = next(options); +function root (options, next) { - each(options.params, function (value, key) { - if (urlParams.indexOf(key) === -1) { - query[key] = value; - } - }); + var url = next(options); - query = Url.params(query); + if (isString(options.root) && !url.match(/^(https?:)?\//)) { + url = options.root + '/' + url; + } - if (query) { - url += (url.indexOf('?') == -1 ? '?' : '&') + query; - } + return url; +} - return url; - } +/** + * Query Parameter Transform. + */ - /** - * URL Template v2.0.6 (https://github.com/bramstein/url-template) - */ +function query (options, next) { - function expand(url, params, variables) { + var urlParams = Object.keys(Url.options.params), + query = {}, + url = next(options); - var tmpl = parse(url), - expanded = tmpl.expand(params); + each(options.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); - if (variables) { - variables.push.apply(variables, tmpl.vars); - } + query = Url.params(query); - return expanded; - } + if (query) { + url += (url.indexOf('?') == -1 ? '?' : '&') + query; + } - function parse(template) { - - var operators = ['+', '#', '.', '/', ';', '?', '&'], - variables = []; - - return { - vars: variables, - expand: function (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); - } - }); - } - }; - } + return url; +} - 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; - } +/** + * URL Template v2.0.6 (https://github.com/bramstein/url-template) + */ - function isDefined(value) { - return value !== undefined && value !== null; - } +function expand(url, params, variables) { - function isKeyOperator(operator) { - return operator === ';' || operator === '&' || operator === '?'; - } + var tmpl = parse(url), + expanded = tmpl.expand(params); - function encodeValue(operator, value, key) { + if (variables) { + variables.push.apply(variables, tmpl.vars); + } - value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); + return expanded; +} + +function parse(template) { + + var operators = ['+', '#', '.', '/', ';', '?', '&'], + variables = []; + + return { + vars: variables, + expand: function (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(''); + } + } - if (key) { - return encodeURIComponent(key) + '=' + value; - } else { - return value; - } - } + return result; +} - 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 isDefined(value) { + return value !== undefined && value !== null; +} - function template (options) { +function isKeyOperator(operator) { + return operator === ';' || operator === '&' || operator === '?'; +} - var variables = [], - url = expand(options.url, options.params, variables); +function encodeValue(operator, value, key) { - variables.forEach(function (key) { - delete options.params[key]; - }); + value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); - return url; - } + 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(''); +} + +/** + * URL Template (RFC 6570) Transform. + */ - /** - * Service for URL templating. - */ +function template (options) { - var ie = document.documentMode; - var el = document.createElement('a'); + var variables = [], + url = expand(options.url, options.params, variables); - function Url(url, params) { + variables.forEach(function (key) { + delete options.params[key]; + }); - var self = this || {}, - options = url, - transform; + return url; +} - if (isString(url)) { - options = { url: url, params: params }; - } +/** + * Service for URL templating. + */ - options = merge({}, Url.options, self.$options, options); +var ie = document.documentMode; +var el = document.createElement('a'); - Url.transforms.forEach(function (handler) { - transform = factory(handler, transform, self.$vm); - }); +function Url(url, params) { - return transform(options); - } + var self = this || {}, + options = url, + transform; - /** - * Url options. - */ + if (isString(url)) { + options = { url: url, params: params }; + } - Url.options = { - url: '', - root: null, - params: {} - }; + options = merge({}, Url.options, self.$options, options); - /** - * Url transforms. - */ + Url.transforms.forEach(function (handler) { + transform = factory(handler, transform, self.$vm); + }); - Url.transforms = [template, query, root]; + return transform(options); +} - /** - * Encodes a Url parameter string. - * - * @param {Object} obj - */ +/** + * Url options. + */ - Url.params = function (obj) { +Url.options = { + url: '', + root: null, + params: {} +}; - var params = [], - escape = encodeURIComponent; +/** + * Url transforms. + */ - params.add = function (key, value) { +Url.transforms = [template, query, root]; - if (isFunction(value)) { - value = value(); - } +/** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ - if (value === null) { - value = ''; - } +Url.params = function (obj) { - this.push(escape(key) + '=' + escape(value)); - }; + var params = [], + escape = encodeURIComponent; - serialize(params, obj); + params.add = function (key, value) { - return params.join('&').replace(/%20/g, '+'); - }; + if (isFunction(value)) { + value = value(); + } - /** - * Parse a URL and return its components. - * - * @param {String} url - */ + if (value === null) { + value = ''; + } - Url.parse = function (url) { + this.push(escape(key) + '=' + escape(value)); + }; - if (ie) { - el.href = url; - url = el.href; - } + serialize(params, obj); - el.href = url; + return params.join('&').replace(/%20/g, '+'); +}; - 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(/^#/, '') : '' - }; - }; +/** + * Parse a URL and return its components. + * + * @param {String} url + */ - function factory(handler, next, vm) { - return function (options) { - return handler.call(vm, options, next); - }; - } +Url.parse = function (url) { - function serialize(params, obj, scope) { + if (ie) { + el.href = url; + url = el.href; + } - var array = isArray(obj), - plain = isPlainObject(obj), - hash; + 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); + } + }); +} + +/** + * XDomain client (Internet Explorer). + */ - each(obj, function (value, key) { +function xdrClient (request) { + return new Promise$1(function (resolve) { - hash = isObject(value) || isArray(value); + var xdr = new XDomainRequest(), + handler = function (event) { - if (scope) { - key = scope + '[' + (plain || hash ? key : '') + ']'; - } + var response = request.respondWith(xdr.responseText, { + status: xdr.status, + statusText: xdr.statusText + }); - if (!scope && array) { - params.add(value.name, value.value); - } else if (hash) { - serialize(params, value, key); - } else { - params.add(key, value); - } - }); - } + resolve(response); + }; - function xdrClient (request) { - return new Promise$1(function (resolve) { + request.abort = function () { + return xdr.abort(); + }; - var xdr = new XDomainRequest(), - handler = function (event) { + xdr.open(request.method, request.getUrl(), true); + xdr.timeout = 0; + xdr.onload = handler; + xdr.onerror = handler; + xdr.ontimeout = function () {}; + xdr.onprogress = function () {}; + xdr.send(request.getBody()); + }); +} - var response = request.respondWith(xdr.responseText, { - status: xdr.status, - statusText: xdr.statusText - }); +/** + * CORS Interceptor. + */ - resolve(response); - }; +var ORIGIN_URL = Url.parse(location.href); +var SUPPORTS_CORS = 'withCredentials' in new XMLHttpRequest(); - request.abort = function () { - return xdr.abort(); - }; +function cors (request, next) { - xdr.open(request.method, request.getUrl(), true); - xdr.timeout = 0; - xdr.onload = handler; - xdr.onerror = handler; - xdr.ontimeout = function () {}; - xdr.onprogress = function () {}; - xdr.send(request.getBody()); - }); - } + if (!isBoolean(request.crossOrigin) && crossOrigin(request)) { + request.crossOrigin = true; + } - var ORIGIN_URL = Url.parse(location.href); - var SUPPORTS_CORS = 'withCredentials' in new XMLHttpRequest(); + if (request.crossOrigin) { - function cors (request, next) { + if (!SUPPORTS_CORS) { + request.client = xdrClient; + } - if (!isBoolean(request.crossOrigin) && crossOrigin(request)) { - request.crossOrigin = true; - } + delete request.emulateHTTP; + } - if (request.crossOrigin) { + next(); +} - if (!SUPPORTS_CORS) { - request.client = xdrClient; - } +function crossOrigin(request) { - delete request.emulateHTTP; - } + var requestUrl = Url.parse(Url(request)); - next(); - } + return requestUrl.protocol !== ORIGIN_URL.protocol || requestUrl.host !== ORIGIN_URL.host; +} - function crossOrigin(request) { +/** + * Body Interceptor. + */ - var requestUrl = Url.parse(Url(request)); +function body (request, next) { - return requestUrl.protocol !== ORIGIN_URL.protocol || requestUrl.host !== ORIGIN_URL.host; - } + if (request.emulateJSON && isPlainObject(request.body)) { + request.body = Url.params(request.body); + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); + } - function body (request, next) { + if (isFormData(request.body)) { + request.headers.delete('Content-Type'); + } - if (request.emulateJSON && isPlainObject(request.body)) { - request.body = Url.params(request.body); - request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + if (isPlainObject(request.body)) { + request.body = JSON.stringify(request.body); + } - if (isFormData(request.body)) { - delete request.headers['Content-Type']; - } + next(function (response) { - if (isPlainObject(request.body)) { - request.body = JSON.stringify(request.body); - } + Object.defineProperty(response, 'data', { + get: function () { + return this.body; + }, + set: function (body) { + this.body = body; + } + }); - next(function (response) { + return response.bodyText ? when(response.text(), function (text) { - var contentType = response.headers['Content-Type']; + var type = response.headers.get('Content-Type'); - if (isString(contentType) && contentType.indexOf('application/json') === 0) { + if (isString(type) && type.indexOf('application/json') === 0) { - try { - response.data = response.json(); - } catch (e) { - response.data = null; - } - } else { - response.data = response.text(); - } - }); - } + try { + response.body = JSON.parse(text); + } catch (e) { + response.body = null; + } + } else { + response.body = text; + } - function jsonpClient (request) { - return new Promise$1(function (resolve) { + return response; + }) : response; + }); +} - var name = request.jsonp || 'callback', - callback = '_jsonp' + Math.random().toString(36).substr(2), - body = null, - handler, - script; +/** + * JSONP client. + */ - handler = function (event) { +function jsonpClient (request) { + return new Promise$1(function (resolve) { - var status = 0; + var name = request.jsonp || 'callback', + callback = '_jsonp' + Math.random().toString(36).substr(2), + body = null, + handler, + script; - if (event.type === 'load' && body !== null) { - status = 200; - } else if (event.type === 'error') { - status = 404; - } + handler = function (event) { - resolve(request.respondWith(body, { status: status })); + var status = 0; - delete window[callback]; - document.body.removeChild(script); - }; + if (event.type === 'load' && body !== null) { + status = 200; + } else if (event.type === 'error') { + status = 404; + } - request.params[name] = callback; + resolve(request.respondWith(body, { status: status })); - window[callback] = function (result) { - body = JSON.stringify(result); - }; + delete window[callback]; + document.body.removeChild(script); + }; - script = document.createElement('script'); - script.src = request.getUrl(); - script.type = 'text/javascript'; - script.async = true; - script.onload = handler; - script.onerror = handler; + request.params[name] = callback; - document.body.appendChild(script); - }); - } + window[callback] = function (result) { + body = JSON.stringify(result); + }; - function jsonp (request, next) { + script = document.createElement('script'); + script.src = request.getUrl(); + script.type = 'text/javascript'; + script.async = true; + script.onload = handler; + script.onerror = handler; - if (request.method == 'JSONP') { - request.client = jsonpClient; - } + document.body.appendChild(script); + }); +} - next(function (response) { +/** + * JSONP Interceptor. + */ - if (request.method == 'JSONP') { - response.data = response.json(); - } - }); - } +function jsonp (request, next) { - function before (request, next) { + if (request.method == 'JSONP') { + request.client = jsonpClient; + } - if (isFunction(request.before)) { - request.before.call(this, request); - } + next(function (response) { - next(); - } + if (request.method == 'JSONP') { - /** - * HTTP method override Interceptor. - */ + return when(response.json(), function (json) { - function method (request, next) { + response.body = json; - if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { - request.headers['X-HTTP-Method-Override'] = request.method; - request.method = 'POST'; - } + return response; + }); + } + }); +} - next(); - } +/** + * Before Interceptor. + */ - function header (request, next) { +function before (request, next) { - request.method = request.method.toUpperCase(); - request.headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); + if (isFunction(request.before)) { + request.before.call(this, request); + } - next(); - } + next(); +} - /** - * Timeout Interceptor. - */ +/** + * HTTP method override Interceptor. + */ - function timeout (request, next) { +function method (request, next) { - var timeout; + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers.set('X-HTTP-Method-Override', request.method); + request.method = 'POST'; + } - if (request.timeout) { - timeout = setTimeout(function () { - request.abort(); - }, request.timeout); - } + next(); +} - next(function (response) { +/** + * Header Interceptor. + */ - clearTimeout(timeout); - }); - } +function header (request, next) { - function xhrClient (request) { - return new Promise$1(function (resolve) { + var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[toLower(request.method)]); - var xhr = new XMLHttpRequest(), - handler = function (event) { + each(headers, function (value, name) { + if (!request.headers.has(name)) { + request.headers.set(name, value); + } + }); - var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { - status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug - statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText), - headers: parseHeaders(xhr.getAllResponseHeaders()) - }); + next(); +} - resolve(response); - }; +/** + * Timeout Interceptor. + */ - request.abort = function () { - return xhr.abort(); - }; +function timeout (request, next) { - xhr.open(request.method, request.getUrl(), true); - xhr.timeout = 0; - xhr.onload = handler; - xhr.onerror = handler; + var timeout; - if (request.progress) { - if (request.method === 'GET') { - xhr.addEventListener('progress', request.progress); - } else if (/^(POST|PUT)$/i.test(request.method)) { - xhr.upload.addEventListener('progress', request.progress); - } - } + if (request.timeout) { + timeout = setTimeout(function () { + request.abort(); + }, request.timeout); + } - if (request.credentials === true) { - xhr.withCredentials = true; - } + next(function (response) { - each(request.headers || {}, function (value, header) { - xhr.setRequestHeader(header, value); - }); + clearTimeout(timeout); + }); +} - xhr.send(request.getBody()); - }); - } +/** + * XMLHttp client. + */ - function parseHeaders(str) { +function xhrClient (request) { + return new Promise$1(function (resolve) { - var headers = {}, - value, - name, - i; + var xhr = new XMLHttpRequest(), + handler = function (event) { - each(trim(str).split('\n'), function (row) { + var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { + status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) + }); - i = row.indexOf(':'); - name = trim(row.slice(0, i)); - value = trim(row.slice(i + 1)); + each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { + response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); + }); - if (headers[name]) { + resolve(response); + }; - if (isArray(headers[name])) { - headers[name].push(value); - } else { - headers[name] = [headers[name], value]; - } - } else { + request.abort = function () { + return xhr.abort(); + }; - headers[name] = value; - } - }); + xhr.open(request.method, request.getUrl(), true); + xhr.timeout = 0; + xhr.onload = handler; + xhr.onerror = handler; - return headers; - } + if (request.progress) { + if (request.method === 'GET') { + xhr.addEventListener('progress', request.progress); + } else if (/^(POST|PUT)$/i.test(request.method)) { + xhr.upload.addEventListener('progress', request.progress); + } + } - function Client (context) { + if ('responseType' in xhr) { + xhr.responseType = 'blob'; + } - var reqHandlers = [sendRequest], - resHandlers = [], - handler; + if (request.credentials === true) { + xhr.withCredentials = true; + } - if (!isObject(context)) { - context = null; - } + request.headers.forEach(function (value, name) { + xhr.setRequestHeader(name, value); + }); - function Client(request) { - return new Promise$1(function (resolve) { + xhr.send(request.getBody()); + }); +} - function exec() { +/** + * Base client. + */ - handler = reqHandlers.pop(); +function Client (context) { - if (isFunction(handler)) { - handler.call(context, request, next); - } else { - warn('Invalid interceptor of type ' + typeof handler + ', must be a function'); - next(); - } - } + var reqHandlers = [sendRequest], + resHandlers = [], + handler; - function next(response) { + if (!isObject(context)) { + context = null; + } - if (isFunction(response)) { + function Client(request) { + return new Promise$1(function (resolve) { - resHandlers.unshift(response); - } else if (isObject(response)) { + function exec() { - resHandlers.forEach(function (handler) { - response = when(response, function (response) { - return handler.call(context, response) || response; - }); - }); + handler = reqHandlers.pop(); - when(response, resolve); + if (isFunction(handler)) { + handler.call(context, request, next); + } else { + warn('Invalid interceptor of type ' + typeof handler + ', must be a function'); + next(); + } + } - return; - } + function next(response) { - exec(); - } + if (isFunction(response)) { - exec(); - }, context); - } + resHandlers.unshift(response); + } else if (isObject(response)) { - Client.use = function (handler) { - reqHandlers.push(handler); - }; + resHandlers.forEach(function (handler) { + response = when(response, function (response) { + return handler.call(context, response) || response; + }); + }); - return Client; - } + when(response, resolve); - function sendRequest(request, resolve) { + return; + } - var client = request.client || xhrClient; + exec(); + } - resolve(client(request)); + exec(); + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; +} + +function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + + resolve(client(request)); +} + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); } +}; + +/** + * HTTP Headers. + */ + +var Headers = function () { + function Headers(headers) { + var _this = this; - var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); + classCallCheck(this, Headers); + + + this.map = {}; + + each(headers, function (value, name) { + return _this.append(name, value); + }); } - }; - /** - * HTTP Response. - */ + Headers.prototype.has = function has(name) { + return this.map.hasOwnProperty(normalizeName(name)); + }; - var Response = function () { - function Response(body, _ref) { - var url = _ref.url; - var headers = _ref.headers; - var status = _ref.status; - var statusText = _ref.statusText; - classCallCheck(this, Response); + Headers.prototype.get = function get(name) { + var list = this.map[normalizeName(name)]; - this.url = url; - this.body = body; - this.headers = headers || {}; - this.status = status || 0; - this.statusText = statusText || ''; - this.ok = status >= 200 && status < 300; - } + return list ? list[0] : null; + }; - Response.prototype.text = function text() { - return this.body; - }; + Headers.prototype.getAll = function getAll(name) { + return this.map[normalizeName(name)] || []; + }; - Response.prototype.blob = function blob() { - return new Blob([this.body]); - }; + Headers.prototype.set = function set(name, value) { + this.map[normalizeName(name)] = [trim(value)]; + }; - Response.prototype.json = function json() { - return JSON.parse(this.body); - }; + Headers.prototype.append = function append(name, value) { - return Response; - }(); + var list = this.map[normalizeName(name)]; - var Request = function () { - function Request(options) { - classCallCheck(this, Request); + if (!list) { + list = this.map[normalizeName(name)] = []; + } + list.push(trim(value)); + }; - this.method = 'GET'; - this.body = null; - this.params = {}; - this.headers = {}; + Headers.prototype.delete = function _delete(name) { + delete this.map[normalizeName(name)]; + }; - assign(this, options); - } + Headers.prototype.forEach = function forEach(callback, thisArg) { + var _this2 = this; - Request.prototype.getUrl = function getUrl() { - return Url(this); - }; + each(this.map, function (list, name) { + each(list, function (value) { + return callback.call(thisArg, value, name, _this2); + }); + }); + }; - Request.prototype.getBody = function getBody() { - return this.body; - }; + return Headers; +}(); - Request.prototype.respondWith = function respondWith(body, options) { - return new Response(body, assign(options || {}, { url: this.getUrl() })); - }; +function normalizeName(name) { - return Request; - }(); + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name'); + } - /** - * Service for sending network requests. - */ + return toLower(trim(name)); +} - var CUSTOM_HEADERS = { 'X-Requested-With': 'XMLHttpRequest' }; - var COMMON_HEADERS = { 'Accept': 'application/json, text/plain, */*' }; - var JSON_CONTENT_TYPE = { 'Content-Type': 'application/json;charset=utf-8' }; +/** + * HTTP Response. + */ - function Http(options) { +var Response = function () { + function Response(body, _ref) { + var url = _ref.url; + var headers = _ref.headers; + var status = _ref.status; + var statusText = _ref.statusText; + classCallCheck(this, Response); - var self = this || {}, - client = Client(self.$vm); - defaults(options || {}, self.$options, Http.options); + this.url = url; + this.ok = status >= 200 && status < 300; + this.status = status || 0; + this.statusText = statusText || ''; + this.headers = new Headers(headers); + this.body = body; - Http.interceptors.forEach(function (handler) { - client.use(handler); - }); + if (isString(body)) { - return client(new Request(options)).then(function (response) { + this.bodyText = body; + } else if (isBlob(body)) { - return response.ok ? response : Promise$1.reject(response); - }, function (response) { + this.bodyBlob = body; - if (response instanceof Error) { - error(response); - } + if (isBlobText(body)) { + this.bodyText = blobText(body); + } + } + } - return Promise$1.reject(response); - }); - } + Response.prototype.blob = function blob() { + return when(this.bodyBlob); + }; - Http.options = {}; + Response.prototype.text = function text() { + return when(this.bodyText); + }; - Http.headers = { - put: JSON_CONTENT_TYPE, - post: JSON_CONTENT_TYPE, - patch: JSON_CONTENT_TYPE, - delete: JSON_CONTENT_TYPE, - custom: CUSTOM_HEADERS, - common: COMMON_HEADERS - }; + Response.prototype.json = function json() { + return when(this.text(), function (text) { + return JSON.parse(text); + }); + }; - Http.interceptors = [before, timeout, method, body, jsonp, header, cors]; + return Response; +}(); - ['get', 'delete', 'head', 'jsonp'].forEach(function (method) { +function blobText(body) { + return new Promise$1(function (resolve) { - Http[method] = function (url, options) { - return this(assign(options || {}, { url: url, method: method })); - }; - }); + var reader = new FileReader(); - ['post', 'put', 'patch'].forEach(function (method) { + reader.readAsText(body); + reader.onload = function () { + resolve(reader.result); + }; + }); +} - Http[method] = function (url, body, options) { - return this(assign(options || {}, { url: url, method: method, body: body })); - }; - }); +function isBlobText(body) { + return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; +} - function Resource(url, params, actions, options) { +/** + * HTTP Request. + */ - var self = this || {}, - resource = {}; +var Request = function () { + function Request(options) { + classCallCheck(this, Request); - actions = assign({}, Resource.actions, actions); - each(actions, function (action, name) { + this.body = null; + this.params = {}; - action = merge({ url: url, params: params || {} }, options, action); + assign(this, options, { + method: toUpper(options.method || 'GET'), + headers: new Headers(options.headers) + }); + } - resource[name] = function () { - return (self.$http || Http)(opts(action, arguments)); - }; - }); + Request.prototype.getUrl = function getUrl() { + return Url(this); + }; - return resource; - } + Request.prototype.getBody = function getBody() { + return this.body; + }; - function opts(action, args) { + Request.prototype.respondWith = function respondWith(body, options) { + return new Response(body, assign(options || {}, { url: this.getUrl() })); + }; - var options = assign({}, action), - params = {}, - body; + return Request; +}(); - switch (args.length) { +/** + * Service for sending network requests. + */ - case 2: +var CUSTOM_HEADERS = { 'X-Requested-With': 'XMLHttpRequest' }; +var COMMON_HEADERS = { 'Accept': 'application/json, text/plain, */*' }; +var JSON_CONTENT_TYPE = { 'Content-Type': 'application/json;charset=utf-8' }; - params = args[0]; - body = args[1]; +function Http(options) { - break; + var self = this || {}, + client = Client(self.$vm); - case 1: + defaults(options || {}, self.$options, Http.options); - if (/^(POST|PUT|PATCH)$/i.test(options.method)) { - body = args[0]; - } else { - params = args[0]; - } + Http.interceptors.forEach(function (handler) { + client.use(handler); + }); - break; + return client(new Request(options)).then(function (response) { - case 0: + return response.ok ? response : Promise$1.reject(response); + }, function (response) { - break; + if (response instanceof Error) { + error(response); + } - default: + return Promise$1.reject(response); + }); +} - throw 'Expected up to 4 arguments [params, body], got ' + args.length + ' arguments'; - } +Http.options = {}; - options.body = body; - options.params = assign({}, options.params, params); +Http.headers = { + put: JSON_CONTENT_TYPE, + post: JSON_CONTENT_TYPE, + patch: JSON_CONTENT_TYPE, + delete: JSON_CONTENT_TYPE, + custom: CUSTOM_HEADERS, + common: COMMON_HEADERS +}; - return options; - } +Http.interceptors = [before, timeout, method, body, jsonp, header, cors]; + +['get', 'delete', 'head', 'jsonp'].forEach(function (method) { - Resource.actions = { + Http[method] = function (url, options) { + return this(assign(options || {}, { url: url, method: method })); + }; +}); - get: { method: 'GET' }, - save: { method: 'POST' }, - query: { method: 'GET' }, - update: { method: 'PUT' }, - remove: { method: 'DELETE' }, - delete: { method: 'DELETE' } +['post', 'put', 'patch'].forEach(function (method) { - }; + Http[method] = function (url, body, options) { + return this(assign(options || {}, { url: url, method: method, body: body })); + }; +}); - function plugin(Vue) { +/** + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + */ - if (plugin.installed) { - return; - } +var RESOLVED = 0; +var REJECTED = 1; +var PENDING = 2; - Util(Vue); +function Promise$2(executor) { - Vue.url = Url; - Vue.http = Http; - Vue.resource = Resource; - Vue.Promise = Promise$1; + this.state = PENDING; + this.value = undefined; + this.deferred = []; - Object.defineProperties(Vue.prototype, { + 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 === '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(); + } +}; - $url: { - get: function () { - return options(Vue.url, this, this.$options.url); - } - }, +p$1.reject = function reject(reason) { + var promise = this; - $http: { - get: function () { - return options(Vue.http, this, this.$options.http); - } - }, + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } - $resource: { - get: function () { - return Vue.resource.bind(this); - } - }, + 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); +}; + +/** + * Service for interacting with RESTful services. + */ - $promise: { - get: function () { - var _this = this; +function Resource(url, params, actions, options) { - return function (executor) { - return new Vue.Promise(executor, _this); - }; - } - } + var self = this || {}, + resource = {}; - }); - } + actions = assign({}, Resource.actions, actions); - if (typeof window !== 'undefined' && window.Vue) { - window.Vue.use(plugin); - } + each(actions, function (action, name) { + + action = merge({ url: url, params: assign({}, params) }, options, action); + + resource[name] = function () { + return (self.$http || Http)(opts(action, arguments)); + }; + }); + + return resource; +} + +function opts(action, args) { + + var options = assign({}, action), + params = {}, + body; + + switch (args.length) { + + case 2: + + params = args[0]; + body = args[1]; + + break; + + case 1: + + if (/^(POST|PUT|PATCH)$/i.test(options.method)) { + body = args[0]; + } else { + params = args[0]; + } + + break; + + case 0: + + break; + + default: + + throw 'Expected up to 4 arguments [params, body], got ' + args.length + ' arguments'; + } + + options.body = body; + options.params = assign({}, options.params, params); + + return options; +} + +Resource.actions = { + + get: { method: 'GET' }, + save: { method: 'POST' }, + query: { method: 'GET' }, + update: { method: 'PUT' }, + remove: { method: 'DELETE' }, + delete: { method: 'DELETE' } + +}; + +/** + * Install plugin. + */ + +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 () { + return options(Vue.url, this, this.$options.url); + } + }, + + $http: { + get: function () { + return options(Vue.http, this, this.$options.http); + } + }, + + $resource: { + get: function () { + return Vue.resource.bind(this); + } + }, + + $promise: { + get: function () { + var _this = this; + + return function (executor) { + return new Vue.Promise(executor, _this); + }; + } + } + + }); +} + +if (typeof window !== 'undefined') { + + if (!window.Promise) { + window.Promise = Promise$2; + } + + if (window.Vue) { + window.Vue.use(plugin); + } +} - return plugin; +return plugin; -})); \ No newline at end of file +}))); \ No newline at end of file diff --git a/dist/vue-resource.min.js b/dist/vue-resource.min.js index 6bff73a2..87766ee7 100644 --- a/dist/vue-resource.min.js +++ b/dist/vue-resource.min.js @@ -1,7 +1,7 @@ /*! - * vue-resource v0.9.3 + * vue-resource v1.0.0 * https://github.com/vuejs/vue-resource * Released under the MIT License. */ -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):t.VueResource=n()}(this,function(){"use strict";function t(t){this.state=Z,this.value=void 0,this.deferred=[];var n=this;try{t(function(t){n.resolve(t)},function(t){n.reject(t)})}catch(e){n.reject(e)}}function n(t,n){t instanceof nt?this.promise=t:this.promise=new nt(t.bind(n)),this.context=n}function e(t){rt=t.util,ot=t.config.debug||!t.config.silent}function o(t){"undefined"!=typeof console&&ot&&console.warn("[VueResource warn]: "+t)}function r(t){"undefined"!=typeof console&&console.error(t)}function i(t,n){return rt.nextTick(t,n)}function u(t){return t.replace(/^\s*|\s*$/g,"")}function s(t){return"string"==typeof t}function c(t){return t===!0||t===!1}function a(t){return"function"==typeof t}function f(t){return null!==t&&"object"==typeof t}function h(t){return f(t)&&Object.getPrototypeOf(t)==Object.prototype}function p(t){return"undefined"!=typeof FormData&&t instanceof FormData}function l(t,e,o){var r=n.resolve(t);return arguments.length<2?r:r.then(e,o)}function d(t,n,e){return e=e||{},a(e)&&(e=e.call(n)),v(t.bind({$vm:n,$options:e}),t,{$options:e})}function m(t,n){var e,o;if("number"==typeof t.length)for(e=0;e=200&&i<300}return t.prototype.text=function(){return this.body},t.prototype.blob=function(){return new Blob([this.body])},t.prototype.json=function(){return JSON.parse(this.body)},t}(),dt=function(){function t(n){pt(this,t),this.method="GET",this.body=null,this.params={},this.headers={},st(this,n)}return t.prototype.getUrl=function(){return R(this)},t.prototype.getBody=function(){return this.body},t.prototype.respondWith=function(t,n){return new lt(t,st(n||{},{url:this.getUrl()}))},t}(),mt={"X-Requested-With":"XMLHttpRequest"},vt={Accept:"application/json, text/plain, */*"},yt={"Content-Type":"application/json;charset=utf-8"};return V.options={},V.headers={put:yt,post:yt,patch:yt,"delete":yt,custom:mt,common:vt},V.interceptors=[D,X,J,L,N,M,H],["get","delete","head","jsonp"].forEach(function(t){V[t]=function(n,e){return this(st(e||{},{url:n,method:t}))}}),["post","put","patch"].forEach(function(t){V[t]=function(n,e,o){return this(st(o||{},{url:n,method:t,body:e}))}}),_.actions={get:{method:"GET"},save:{method:"POST"},query:{method:"GET"},update:{method:"PUT"},remove:{method:"DELETE"},"delete":{method:"DELETE"}},"undefined"!=typeof window&&window.Vue&&window.Vue.use(K),K}); \ No newline at end of file +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):t.VueResource=n()}(this,function(){"use strict";function t(t,n){t instanceof et?this.promise=t:this.promise=new et(t.bind(n)),this.context=n}function n(t){it=t.util,rt=t.config.debug||!t.config.silent}function e(t){"undefined"!=typeof console&&rt&&console.warn("[VueResource warn]: "+t)}function o(t){"undefined"!=typeof console&&console.error(t)}function r(t,n){return it.nextTick(t,n)}function i(t){return t.replace(/^\s*|\s*$/g,"")}function u(t){return t?t.toLowerCase():""}function s(t){return t?t.toUpperCase():""}function c(t){return"string"==typeof t}function a(t){return t===!0||t===!1}function f(t){return"function"==typeof t}function p(t){return null!==t&&"object"==typeof t}function h(t){return p(t)&&Object.getPrototypeOf(t)==Object.prototype}function l(t){return"undefined"!=typeof Blob&&t instanceof Blob}function d(t){return"undefined"!=typeof FormData&&t instanceof FormData}function m(n,e,o){var r=t.resolve(n);return arguments.length<2?r:r.then(e,o)}function y(t,n,e){return e=e||{},f(e)&&(e=e.call(n)),b(t.bind({$vm:n,$options:e}),t,{$options:e})}function v(t,n){var e,o;if(t&&"number"==typeof t.length)for(e=0;e=200&&i<300,this.status=i||0,this.statusText=u||"",this.headers=new dt(r),this.body=n,c(n)?this.bodyText=n:l(n)&&(this.bodyBlob=n,K(n)&&(this.bodyText=z(n)))}return t.prototype.blob=function(){return m(this.bodyBlob)},t.prototype.text=function(){return m(this.bodyText)},t.prototype.json=function(){return m(this.text(),function(t){return JSON.parse(t)})},t}(),yt=function(){function t(n){lt(this,t),this.body=null,this.params={},ct(this,n,{method:s(n.method||"GET"),headers:new dt(n.headers)})}return t.prototype.getUrl=function(){return S(this)},t.prototype.getBody=function(){return this.body},t.prototype.respondWith=function(t,n){return new mt(t,ct(n||{},{url:this.getUrl()}))},t}(),vt={"X-Requested-With":"XMLHttpRequest"},bt={Accept:"application/json, text/plain, */*"},wt={"Content-Type":"application/json;charset=utf-8"};Q.options={},Q.headers={put:wt,post:wt,patch:wt,delete:wt,custom:vt,common:bt},Q.interceptors=[D,F,M,q,J,X,L],["get","delete","head","jsonp"].forEach(function(t){Q[t]=function(n,e){return this(ct(e||{},{url:n,method:t}))}}),["post","put","patch"].forEach(function(t){Q[t]=function(n,e,o){return this(ct(o||{},{url:n,method:t,body:e}))}});var gt=0,Tt=1,xt=2;Y.reject=function(t){return new Y(function(n,e){e(t)})},Y.resolve=function(t){return new Y(function(n,e){n(t)})},Y.all=function(t){return new Y(function(n,e){function o(e){return function(o){i[e]=o,r+=1,r===t.length&&n(i)}}var r=0,i=[];0===t.length&&n(i);for(var u=0;u