├── .babelrc.js ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bower.json ├── build ├── build.js └── release.js ├── dist ├── README.md ├── vue-resource.common.js ├── vue-resource.esm.js ├── vue-resource.js └── vue-resource.min.js ├── docs ├── README.md ├── api.md ├── config.md ├── http.md ├── recipes.md └── resource.md ├── package.json ├── src ├── http │ ├── client │ │ ├── index.js │ │ ├── jsonp.js │ │ ├── node.js │ │ ├── xdr.js │ │ └── xhr.js │ ├── headers.js │ ├── index.js │ ├── interceptor │ │ ├── before.js │ │ ├── cors.js │ │ ├── form.js │ │ ├── header.js │ │ ├── json.js │ │ ├── jsonp.js │ │ └── method.js │ ├── request.js │ └── response.js ├── index.js ├── lib │ ├── promise.js │ └── url-template.js ├── promise.js ├── resource.js ├── url │ ├── index.js │ ├── query.js │ ├── root.js │ └── template.js └── util.js ├── test ├── data │ ├── invalid.json │ ├── text.txt │ └── valid.json ├── http.js ├── http.test.js ├── index.html ├── index.js ├── karma.conf.js ├── promise.js ├── resource.js ├── url.js └── webpack.config.js ├── types ├── index.d.ts ├── vue.d.ts └── vue_resource.ts └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | presets: [ 4 | ['@babel/preset-env', { 5 | loose: true, 6 | modules: false 7 | }] 8 | ] 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: circleci/node:14-browsers 6 | environment: 7 | CHROME_BIN: /usr/bin/google-chrome 8 | working_directory: ~/vue-resource 9 | 10 | jobs: 11 | build: 12 | <<: *defaults 13 | steps: 14 | - checkout 15 | - restore_cache: 16 | key: yarn-{{ checksum "yarn.lock" }} 17 | - run: 18 | name: Install Dependencies 19 | command: yarn --pure-lockfile 20 | - run: 21 | name: Run Tests 22 | command: | 23 | yarn test 24 | yarn karma --browsers Chrome 25 | - run: 26 | name: Build Release 27 | command: yarn build 28 | - save_cache: 29 | key: yarn-{{ checksum "yarn.lock" }} 30 | paths: 31 | - ./node_modules 32 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /test 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "root":true, 3 | "env": { 4 | "es6": true, 5 | "browser": true, 6 | "commonjs": true, 7 | }, 8 | "extends": [ 9 | "eslint:recommended" 10 | ], 11 | "parserOptions": { 12 | "sourceType": "module" 13 | }, 14 | "rules": { 15 | "brace-style": ["error", "1tbs", {"allowSingleLine": true}], 16 | "comma-style": "error", 17 | "comma-spacing": "error", 18 | "eqeqeq": ["off", "smart"], 19 | "indent": "off", 20 | "indent-legacy": ["error", 4, {"SwitchCase": 1}], 21 | "key-spacing": "error", 22 | "keyword-spacing": "error", 23 | "linebreak-style": ["error", "unix"], 24 | "no-multi-spaces": "error", 25 | "no-trailing-spaces": "error", 26 | "no-lone-blocks": "error", 27 | "no-extend-native": "error", 28 | "no-unused-vars": ["error", {"vars": "local", "args": "none"}], 29 | "no-empty": ["error", {"allowEmptyCatch": true}], 30 | "no-duplicate-imports": "error", 31 | "no-array-constructor": "error", 32 | "no-multiple-empty-lines": "error", 33 | "no-template-curly-in-string": "error", 34 | "no-console": "off", 35 | "object-curly-spacing": "error", 36 | "quotes": ["error", "single", {"avoidEscape": true}], 37 | "semi": ["error", "always"], 38 | "space-infix-ops": "error", 39 | "space-unary-ops": "error", 40 | "space-in-parens": "error", 41 | "space-before-blocks": "error", 42 | "template-curly-spacing": "error" 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | ### Reproduction Link 14 | 15 | 16 | 17 | ### Steps to reproduce 18 | 19 | 20 | ### What is Expected? 21 | 22 | ### What is actually happening? 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test/specs.js 3 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build 2 | docs 3 | bower.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 steffans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-resource [![Build](https://circleci.com/gh/pagekit/vue-resource.svg?style=shield)](https://circleci.com/gh/pagekit/vue-resource) [![Downloads](https://img.shields.io/npm/dm/vue-resource.svg)](https://www.npmjs.com/package/vue-resource) [![jsdelivr](https://data.jsdelivr.com/v1/package/npm/vue-resource/badge?style=rounded)](https://www.jsdelivr.com/package/npm/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) 2 | 3 | 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. 4 | 5 | ## Features 6 | 7 | - 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) 8 | - Supports [interceptors](docs/http.md#interceptors) for request and response 9 | - Supports latest Firefox, Chrome, Safari, Opera and IE9+ 10 | - Supports Vue 1.0 & Vue 2.0 11 | - Compact size 14KB (5.3KB gzipped) 12 | 13 | ## Installation 14 | You can install it via [yarn](https://yarnpkg.com/) or [NPM](http://npmjs.org/). 15 | ``` 16 | $ yarn add vue-resource 17 | $ npm install vue-resource 18 | ``` 19 | 20 | ### CDN 21 | Available on [jsdelivr](https://cdn.jsdelivr.net/npm/vue-resource@1.5.3), [unpkg](https://unpkg.com/vue-resource@1.5.3) or [cdnjs](https://cdnjs.com/libraries/vue-resource). 22 | ```html 23 | 24 | ``` 25 | 26 | ## Example 27 | ```js 28 | { 29 | // GET /someUrl 30 | this.$http.get('/someUrl').then(response => { 31 | 32 | // get body data 33 | this.someData = response.body; 34 | 35 | }, response => { 36 | // error callback 37 | }); 38 | } 39 | ``` 40 | 41 | ## Documentation 42 | 43 | - [Configuration](docs/config.md) 44 | - [HTTP Requests/Response](docs/http.md) 45 | - [Creating Resources](docs/resource.md) 46 | - [Code Recipes](docs/recipes.md) 47 | - [API Reference](docs/api.md) 48 | 49 | ## Changelog 50 | 51 | Details changes for each release are documented in the [release notes](https://github.com/pagekit/vue-resource/releases). 52 | 53 | ## Contribution 54 | 55 | If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/pagekit/vue-resource/issues) or a [pull request](https://github.com/pagekit/vue-resource/pulls). 56 | 57 | ## License 58 | 59 | [MIT](http://opensource.org/licenses/MIT) 60 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-resource", 3 | "main": "dist/vue-resource.js", 4 | "version": "1.5.3", 5 | "description": "The HTTP client for Vue.js", 6 | "homepage": "https://github.com/pagekit/vue-resource", 7 | "license": "MIT", 8 | "keywords": [ 9 | "vue", 10 | "xhr", 11 | "http", 12 | "ajax" 13 | ], 14 | "ignore": [ 15 | ".*", 16 | "build", 17 | "docs", 18 | "package.json" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const fs = require('fs'); 4 | const zlib = require('zlib'); 5 | const rollup = require('rollup'); 6 | const uglify = require('uglify-js'); 7 | const babel = require('rollup-plugin-babel'); 8 | const replace = require('rollup-plugin-replace'); 9 | const {name, version, homepage} = require('../package.json'); 10 | const banner = `/*!\n * ${name} v${version}\n * ${homepage}\n * Released under the MIT License.\n */\n`; 11 | 12 | rollup.rollup({ 13 | input: 'src/index.js', 14 | plugins: [babel(), replace({__VERSION__: version})] 15 | }) 16 | .then(bundle => 17 | bundle.generate({ 18 | banner, 19 | format: 'umd', 20 | name: 'VueResource' 21 | }).then(({code}) => write(`dist/${name}.js`, code, bundle)) 22 | ) 23 | .then(bundle => 24 | write(`dist/${name}.min.js`, banner + '\n' + 25 | uglify.minify(read(`dist/${name}.js`)).code, bundle, true) 26 | ) 27 | .then(bundle => 28 | bundle.generate({ 29 | banner, 30 | format: 'es', 31 | footer: 'export { Url, Http, Resource };' 32 | }).then(({code}) => write(`dist/${name}.esm.js`, code, bundle)) 33 | ) 34 | .then(bundle => 35 | bundle.generate({ 36 | banner, 37 | format: 'cjs' 38 | }).then(({code}) => write(`dist/${name}.common.js`, code, bundle)) 39 | ) 40 | .catch(logError); 41 | 42 | function read(path) { 43 | return fs.readFileSync(path, 'utf8'); 44 | } 45 | 46 | function write(dest, code, bundle, zip) { 47 | return new Promise((resolve, reject) => { 48 | fs.writeFile(dest, code, err => { 49 | if (err) return reject(err); 50 | 51 | if (zip) { 52 | zlib.gzip(code, (err, zipped) => { 53 | if (err) return reject(err); 54 | console.log(blue(dest) + ' ' + getSize(code) + ' (' + getSize(zipped) + ' gzipped)'); 55 | }); 56 | } else { 57 | console.log(blue(dest) + ' ' + getSize(code)); 58 | } 59 | 60 | resolve(bundle); 61 | }); 62 | }); 63 | } 64 | 65 | function getSize(code) { 66 | return (code.length / 1024).toFixed(2) + 'kb'; 67 | } 68 | 69 | function logError(e) { 70 | console.log(e); 71 | } 72 | 73 | function blue(str) { 74 | return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'; 75 | } 76 | -------------------------------------------------------------------------------- /build/release.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | var replace = require('replace-in-file'); 4 | var version = process.argv[2]; 5 | 6 | replace({ 7 | files: 'bower.json', 8 | from: /("version"\s*:\s*")\d+\.\d+\.\d+("\s*,)/g, 9 | to: '$1' + version + '$2' 10 | }); 11 | 12 | replace({ 13 | files: 'package.json', 14 | from: /("version"\s*:\s*")\d+\.\d+\.\d+("\s*,)/g, 15 | to: '$1' + version + '$2' 16 | }); 17 | 18 | replace({ 19 | files: 'README.md', 20 | from: /(\/|@)\d+\.\d+\.\d+/g, 21 | to: '$1' + version 22 | }); 23 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # NOTE! 2 | 3 | The `dist` folder contains the standalone build for vue-resource, however files here are only checked-in when a release happens. If you are on the `dev` branch, files here are **NOT** up to date. Only the `master` branch contains the built files for the latest stable version. 4 | -------------------------------------------------------------------------------- /dist/vue-resource.common.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-resource v1.5.3 3 | * https://github.com/pagekit/vue-resource 4 | * Released under the MIT License. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) 11 | */ 12 | var RESOLVED = 0; 13 | var REJECTED = 1; 14 | var PENDING = 2; 15 | function Promise$1(executor) { 16 | this.state = PENDING; 17 | this.value = undefined; 18 | this.deferred = []; 19 | var promise = this; 20 | 21 | try { 22 | executor(function (x) { 23 | promise.resolve(x); 24 | }, function (r) { 25 | promise.reject(r); 26 | }); 27 | } catch (e) { 28 | promise.reject(e); 29 | } 30 | } 31 | 32 | Promise$1.reject = function (r) { 33 | return new Promise$1(function (resolve, reject) { 34 | reject(r); 35 | }); 36 | }; 37 | 38 | Promise$1.resolve = function (x) { 39 | return new Promise$1(function (resolve, reject) { 40 | resolve(x); 41 | }); 42 | }; 43 | 44 | Promise$1.all = function all(iterable) { 45 | return new Promise$1(function (resolve, reject) { 46 | var count = 0, 47 | result = []; 48 | 49 | if (iterable.length === 0) { 50 | resolve(result); 51 | } 52 | 53 | function resolver(i) { 54 | return function (x) { 55 | result[i] = x; 56 | count += 1; 57 | 58 | if (count === iterable.length) { 59 | resolve(result); 60 | } 61 | }; 62 | } 63 | 64 | for (var i = 0; i < iterable.length; i += 1) { 65 | Promise$1.resolve(iterable[i]).then(resolver(i), reject); 66 | } 67 | }); 68 | }; 69 | 70 | Promise$1.race = function race(iterable) { 71 | return new Promise$1(function (resolve, reject) { 72 | for (var i = 0; i < iterable.length; i += 1) { 73 | Promise$1.resolve(iterable[i]).then(resolve, reject); 74 | } 75 | }); 76 | }; 77 | 78 | var p = Promise$1.prototype; 79 | 80 | p.resolve = function resolve(x) { 81 | var promise = this; 82 | 83 | if (promise.state === PENDING) { 84 | if (x === promise) { 85 | throw new TypeError('Promise settled with itself.'); 86 | } 87 | 88 | var called = false; 89 | 90 | try { 91 | var then = x && x['then']; 92 | 93 | if (x !== null && typeof x === 'object' && typeof then === 'function') { 94 | then.call(x, function (x) { 95 | if (!called) { 96 | promise.resolve(x); 97 | } 98 | 99 | called = true; 100 | }, function (r) { 101 | if (!called) { 102 | promise.reject(r); 103 | } 104 | 105 | called = true; 106 | }); 107 | return; 108 | } 109 | } catch (e) { 110 | if (!called) { 111 | promise.reject(e); 112 | } 113 | 114 | return; 115 | } 116 | 117 | promise.state = RESOLVED; 118 | promise.value = x; 119 | promise.notify(); 120 | } 121 | }; 122 | 123 | p.reject = function reject(reason) { 124 | var promise = this; 125 | 126 | if (promise.state === PENDING) { 127 | if (reason === promise) { 128 | throw new TypeError('Promise settled with itself.'); 129 | } 130 | 131 | promise.state = REJECTED; 132 | promise.value = reason; 133 | promise.notify(); 134 | } 135 | }; 136 | 137 | p.notify = function notify() { 138 | var promise = this; 139 | nextTick(function () { 140 | if (promise.state !== PENDING) { 141 | while (promise.deferred.length) { 142 | var deferred = promise.deferred.shift(), 143 | onResolved = deferred[0], 144 | onRejected = deferred[1], 145 | resolve = deferred[2], 146 | reject = deferred[3]; 147 | 148 | try { 149 | if (promise.state === RESOLVED) { 150 | if (typeof onResolved === 'function') { 151 | resolve(onResolved.call(undefined, promise.value)); 152 | } else { 153 | resolve(promise.value); 154 | } 155 | } else if (promise.state === REJECTED) { 156 | if (typeof onRejected === 'function') { 157 | resolve(onRejected.call(undefined, promise.value)); 158 | } else { 159 | reject(promise.value); 160 | } 161 | } 162 | } catch (e) { 163 | reject(e); 164 | } 165 | } 166 | } 167 | }); 168 | }; 169 | 170 | p.then = function then(onResolved, onRejected) { 171 | var promise = this; 172 | return new Promise$1(function (resolve, reject) { 173 | promise.deferred.push([onResolved, onRejected, resolve, reject]); 174 | promise.notify(); 175 | }); 176 | }; 177 | 178 | p["catch"] = function (onRejected) { 179 | return this.then(undefined, onRejected); 180 | }; 181 | 182 | /** 183 | * Promise adapter. 184 | */ 185 | 186 | if (typeof Promise === 'undefined') { 187 | window.Promise = Promise$1; 188 | } 189 | 190 | function PromiseObj(executor, context) { 191 | if (executor instanceof Promise) { 192 | this.promise = executor; 193 | } else { 194 | this.promise = new Promise(executor.bind(context)); 195 | } 196 | 197 | this.context = context; 198 | } 199 | 200 | PromiseObj.all = function (iterable, context) { 201 | return new PromiseObj(Promise.all(iterable), context); 202 | }; 203 | 204 | PromiseObj.resolve = function (value, context) { 205 | return new PromiseObj(Promise.resolve(value), context); 206 | }; 207 | 208 | PromiseObj.reject = function (reason, context) { 209 | return new PromiseObj(Promise.reject(reason), context); 210 | }; 211 | 212 | PromiseObj.race = function (iterable, context) { 213 | return new PromiseObj(Promise.race(iterable), context); 214 | }; 215 | 216 | var p$1 = PromiseObj.prototype; 217 | 218 | p$1.bind = function (context) { 219 | this.context = context; 220 | return this; 221 | }; 222 | 223 | p$1.then = function (fulfilled, rejected) { 224 | if (fulfilled && fulfilled.bind && this.context) { 225 | fulfilled = fulfilled.bind(this.context); 226 | } 227 | 228 | if (rejected && rejected.bind && this.context) { 229 | rejected = rejected.bind(this.context); 230 | } 231 | 232 | return new PromiseObj(this.promise.then(fulfilled, rejected), this.context); 233 | }; 234 | 235 | p$1["catch"] = function (rejected) { 236 | if (rejected && rejected.bind && this.context) { 237 | rejected = rejected.bind(this.context); 238 | } 239 | 240 | return new PromiseObj(this.promise["catch"](rejected), this.context); 241 | }; 242 | 243 | p$1["finally"] = function (callback) { 244 | return this.then(function (value) { 245 | callback.call(this); 246 | return value; 247 | }, function (reason) { 248 | callback.call(this); 249 | return Promise.reject(reason); 250 | }); 251 | }; 252 | 253 | /** 254 | * Utility functions. 255 | */ 256 | var _ref = {}, 257 | hasOwnProperty = _ref.hasOwnProperty, 258 | slice = [].slice, 259 | debug = false, 260 | ntick; 261 | var inBrowser = typeof window !== 'undefined'; 262 | function Util (_ref2) { 263 | var config = _ref2.config, 264 | nextTick = _ref2.nextTick; 265 | ntick = nextTick; 266 | debug = config.debug || !config.silent; 267 | } 268 | function warn(msg) { 269 | if (typeof console !== 'undefined' && debug) { 270 | console.warn('[VueResource warn]: ' + msg); 271 | } 272 | } 273 | function error(msg) { 274 | if (typeof console !== 'undefined') { 275 | console.error(msg); 276 | } 277 | } 278 | function nextTick(cb, ctx) { 279 | return ntick(cb, ctx); 280 | } 281 | function trim(str) { 282 | return str ? str.replace(/^\s*|\s*$/g, '') : ''; 283 | } 284 | function trimEnd(str, chars) { 285 | if (str && chars === undefined) { 286 | return str.replace(/\s+$/, ''); 287 | } 288 | 289 | if (!str || !chars) { 290 | return str; 291 | } 292 | 293 | return str.replace(new RegExp("[" + chars + "]+$"), ''); 294 | } 295 | function toLower(str) { 296 | return str ? str.toLowerCase() : ''; 297 | } 298 | function toUpper(str) { 299 | return str ? str.toUpperCase() : ''; 300 | } 301 | var isArray = Array.isArray; 302 | function isString(val) { 303 | return typeof val === 'string'; 304 | } 305 | function isFunction(val) { 306 | return typeof val === 'function'; 307 | } 308 | function isObject(obj) { 309 | return obj !== null && typeof obj === 'object'; 310 | } 311 | function isPlainObject(obj) { 312 | return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; 313 | } 314 | function isBlob(obj) { 315 | return typeof Blob !== 'undefined' && obj instanceof Blob; 316 | } 317 | function isFormData(obj) { 318 | return typeof FormData !== 'undefined' && obj instanceof FormData; 319 | } 320 | function when(value, fulfilled, rejected) { 321 | var promise = PromiseObj.resolve(value); 322 | 323 | if (arguments.length < 2) { 324 | return promise; 325 | } 326 | 327 | return promise.then(fulfilled, rejected); 328 | } 329 | function options(fn, obj, opts) { 330 | opts = opts || {}; 331 | 332 | if (isFunction(opts)) { 333 | opts = opts.call(obj); 334 | } 335 | 336 | return merge(fn.bind({ 337 | $vm: obj, 338 | $options: opts 339 | }), fn, { 340 | $options: opts 341 | }); 342 | } 343 | function each(obj, iterator) { 344 | var i, key; 345 | 346 | if (isArray(obj)) { 347 | for (i = 0; i < obj.length; i++) { 348 | iterator.call(obj[i], obj[i], i); 349 | } 350 | } else if (isObject(obj)) { 351 | for (key in obj) { 352 | if (hasOwnProperty.call(obj, key)) { 353 | iterator.call(obj[key], obj[key], key); 354 | } 355 | } 356 | } 357 | 358 | return obj; 359 | } 360 | var assign = Object.assign || _assign; 361 | function merge(target) { 362 | var args = slice.call(arguments, 1); 363 | args.forEach(function (source) { 364 | _merge(target, source, true); 365 | }); 366 | return target; 367 | } 368 | function defaults(target) { 369 | var args = slice.call(arguments, 1); 370 | args.forEach(function (source) { 371 | for (var key in source) { 372 | if (target[key] === undefined) { 373 | target[key] = source[key]; 374 | } 375 | } 376 | }); 377 | return target; 378 | } 379 | 380 | function _assign(target) { 381 | var args = slice.call(arguments, 1); 382 | args.forEach(function (source) { 383 | _merge(target, source); 384 | }); 385 | return target; 386 | } 387 | 388 | function _merge(target, source, deep) { 389 | for (var key in source) { 390 | if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { 391 | if (isPlainObject(source[key]) && !isPlainObject(target[key])) { 392 | target[key] = {}; 393 | } 394 | 395 | if (isArray(source[key]) && !isArray(target[key])) { 396 | target[key] = []; 397 | } 398 | 399 | _merge(target[key], source[key], deep); 400 | } else if (source[key] !== undefined) { 401 | target[key] = source[key]; 402 | } 403 | } 404 | } 405 | 406 | /** 407 | * Root Prefix Transform. 408 | */ 409 | function root (options$$1, next) { 410 | var url = next(options$$1); 411 | 412 | if (isString(options$$1.root) && !/^(https?:)?\//.test(url)) { 413 | url = trimEnd(options$$1.root, '/') + '/' + url; 414 | } 415 | 416 | return url; 417 | } 418 | 419 | /** 420 | * Query Parameter Transform. 421 | */ 422 | function query (options$$1, next) { 423 | var urlParams = Object.keys(Url.options.params), 424 | query = {}, 425 | url = next(options$$1); 426 | each(options$$1.params, function (value, key) { 427 | if (urlParams.indexOf(key) === -1) { 428 | query[key] = value; 429 | } 430 | }); 431 | query = Url.params(query); 432 | 433 | if (query) { 434 | url += (url.indexOf('?') == -1 ? '?' : '&') + query; 435 | } 436 | 437 | return url; 438 | } 439 | 440 | /** 441 | * URL Template v2.0.6 (https://github.com/bramstein/url-template) 442 | */ 443 | function expand(url, params, variables) { 444 | var tmpl = parse(url), 445 | expanded = tmpl.expand(params); 446 | 447 | if (variables) { 448 | variables.push.apply(variables, tmpl.vars); 449 | } 450 | 451 | return expanded; 452 | } 453 | function parse(template) { 454 | var operators = ['+', '#', '.', '/', ';', '?', '&'], 455 | variables = []; 456 | return { 457 | vars: variables, 458 | expand: function expand(context) { 459 | return template.replace(/\{([^{}]+)\}|([^{}]+)/g, function (_, expression, literal) { 460 | if (expression) { 461 | var operator = null, 462 | values = []; 463 | 464 | if (operators.indexOf(expression.charAt(0)) !== -1) { 465 | operator = expression.charAt(0); 466 | expression = expression.substr(1); 467 | } 468 | 469 | expression.split(/,/g).forEach(function (variable) { 470 | var tmp = /([^:*]*)(?::(\d+)|(\*))?/.exec(variable); 471 | values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); 472 | variables.push(tmp[1]); 473 | }); 474 | 475 | if (operator && operator !== '+') { 476 | var separator = ','; 477 | 478 | if (operator === '?') { 479 | separator = '&'; 480 | } else if (operator !== '#') { 481 | separator = operator; 482 | } 483 | 484 | return (values.length !== 0 ? operator : '') + values.join(separator); 485 | } else { 486 | return values.join(','); 487 | } 488 | } else { 489 | return encodeReserved(literal); 490 | } 491 | }); 492 | } 493 | }; 494 | } 495 | 496 | function getValues(context, operator, key, modifier) { 497 | var value = context[key], 498 | result = []; 499 | 500 | if (isDefined(value) && value !== '') { 501 | if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { 502 | value = value.toString(); 503 | 504 | if (modifier && modifier !== '*') { 505 | value = value.substring(0, parseInt(modifier, 10)); 506 | } 507 | 508 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 509 | } else { 510 | if (modifier === '*') { 511 | if (Array.isArray(value)) { 512 | value.filter(isDefined).forEach(function (value) { 513 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 514 | }); 515 | } else { 516 | Object.keys(value).forEach(function (k) { 517 | if (isDefined(value[k])) { 518 | result.push(encodeValue(operator, value[k], k)); 519 | } 520 | }); 521 | } 522 | } else { 523 | var tmp = []; 524 | 525 | if (Array.isArray(value)) { 526 | value.filter(isDefined).forEach(function (value) { 527 | tmp.push(encodeValue(operator, value)); 528 | }); 529 | } else { 530 | Object.keys(value).forEach(function (k) { 531 | if (isDefined(value[k])) { 532 | tmp.push(encodeURIComponent(k)); 533 | tmp.push(encodeValue(operator, value[k].toString())); 534 | } 535 | }); 536 | } 537 | 538 | if (isKeyOperator(operator)) { 539 | result.push(encodeURIComponent(key) + '=' + tmp.join(',')); 540 | } else if (tmp.length !== 0) { 541 | result.push(tmp.join(',')); 542 | } 543 | } 544 | } 545 | } else { 546 | if (operator === ';') { 547 | result.push(encodeURIComponent(key)); 548 | } else if (value === '' && (operator === '&' || operator === '?')) { 549 | result.push(encodeURIComponent(key) + '='); 550 | } else if (value === '') { 551 | result.push(''); 552 | } 553 | } 554 | 555 | return result; 556 | } 557 | 558 | function isDefined(value) { 559 | return value !== undefined && value !== null; 560 | } 561 | 562 | function isKeyOperator(operator) { 563 | return operator === ';' || operator === '&' || operator === '?'; 564 | } 565 | 566 | function encodeValue(operator, value, key) { 567 | value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); 568 | 569 | if (key) { 570 | return encodeURIComponent(key) + '=' + value; 571 | } else { 572 | return value; 573 | } 574 | } 575 | 576 | function encodeReserved(str) { 577 | return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { 578 | if (!/%[0-9A-Fa-f]/.test(part)) { 579 | part = encodeURI(part); 580 | } 581 | 582 | return part; 583 | }).join(''); 584 | } 585 | 586 | /** 587 | * URL Template (RFC 6570) Transform. 588 | */ 589 | function template (options) { 590 | var variables = [], 591 | url = expand(options.url, options.params, variables); 592 | variables.forEach(function (key) { 593 | delete options.params[key]; 594 | }); 595 | return url; 596 | } 597 | 598 | /** 599 | * Service for URL templating. 600 | */ 601 | function Url(url, params) { 602 | var self = this || {}, 603 | options$$1 = url, 604 | transform; 605 | 606 | if (isString(url)) { 607 | options$$1 = { 608 | url: url, 609 | params: params 610 | }; 611 | } 612 | 613 | options$$1 = merge({}, Url.options, self.$options, options$$1); 614 | Url.transforms.forEach(function (handler) { 615 | if (isString(handler)) { 616 | handler = Url.transform[handler]; 617 | } 618 | 619 | if (isFunction(handler)) { 620 | transform = factory(handler, transform, self.$vm); 621 | } 622 | }); 623 | return transform(options$$1); 624 | } 625 | /** 626 | * Url options. 627 | */ 628 | 629 | Url.options = { 630 | url: '', 631 | root: null, 632 | params: {} 633 | }; 634 | /** 635 | * Url transforms. 636 | */ 637 | 638 | Url.transform = { 639 | template: template, 640 | query: query, 641 | root: root 642 | }; 643 | Url.transforms = ['template', 'query', 'root']; 644 | /** 645 | * Encodes a Url parameter string. 646 | * 647 | * @param {Object} obj 648 | */ 649 | 650 | Url.params = function (obj) { 651 | var params = [], 652 | escape = encodeURIComponent; 653 | 654 | params.add = function (key, value) { 655 | if (isFunction(value)) { 656 | value = value(); 657 | } 658 | 659 | if (value === null) { 660 | value = ''; 661 | } 662 | 663 | this.push(escape(key) + '=' + escape(value)); 664 | }; 665 | 666 | serialize(params, obj); 667 | return params.join('&').replace(/%20/g, '+'); 668 | }; 669 | /** 670 | * Parse a URL and return its components. 671 | * 672 | * @param {String} url 673 | */ 674 | 675 | 676 | Url.parse = function (url) { 677 | var el = document.createElement('a'); 678 | 679 | if (document.documentMode) { 680 | el.href = url; 681 | url = el.href; 682 | } 683 | 684 | el.href = url; 685 | return { 686 | href: el.href, 687 | protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', 688 | port: el.port, 689 | host: el.host, 690 | hostname: el.hostname, 691 | pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, 692 | search: el.search ? el.search.replace(/^\?/, '') : '', 693 | hash: el.hash ? el.hash.replace(/^#/, '') : '' 694 | }; 695 | }; 696 | 697 | function factory(handler, next, vm) { 698 | return function (options$$1) { 699 | return handler.call(vm, options$$1, next); 700 | }; 701 | } 702 | 703 | function serialize(params, obj, scope) { 704 | var array = isArray(obj), 705 | plain = isPlainObject(obj), 706 | hash; 707 | each(obj, function (value, key) { 708 | hash = isObject(value) || isArray(value); 709 | 710 | if (scope) { 711 | key = scope + '[' + (plain || hash ? key : '') + ']'; 712 | } 713 | 714 | if (!scope && array) { 715 | params.add(value.name, value.value); 716 | } else if (hash) { 717 | serialize(params, value, key); 718 | } else { 719 | params.add(key, value); 720 | } 721 | }); 722 | } 723 | 724 | /** 725 | * XDomain client (Internet Explorer). 726 | */ 727 | function xdrClient (request) { 728 | return new PromiseObj(function (resolve) { 729 | var xdr = new XDomainRequest(), 730 | handler = function handler(_ref) { 731 | var type = _ref.type; 732 | var status = 0; 733 | 734 | if (type === 'load') { 735 | status = 200; 736 | } else if (type === 'error') { 737 | status = 500; 738 | } 739 | 740 | resolve(request.respondWith(xdr.responseText, { 741 | status: status 742 | })); 743 | }; 744 | 745 | request.abort = function () { 746 | return xdr.abort(); 747 | }; 748 | 749 | xdr.open(request.method, request.getUrl()); 750 | 751 | if (request.timeout) { 752 | xdr.timeout = request.timeout; 753 | } 754 | 755 | xdr.onload = handler; 756 | xdr.onabort = handler; 757 | xdr.onerror = handler; 758 | xdr.ontimeout = handler; 759 | 760 | xdr.onprogress = function () {}; 761 | 762 | xdr.send(request.getBody()); 763 | }); 764 | } 765 | 766 | /** 767 | * CORS Interceptor. 768 | */ 769 | var SUPPORTS_CORS = inBrowser && 'withCredentials' in new XMLHttpRequest(); 770 | function cors (request) { 771 | if (inBrowser) { 772 | var orgUrl = Url.parse(location.href); 773 | var reqUrl = Url.parse(request.getUrl()); 774 | 775 | if (reqUrl.protocol !== orgUrl.protocol || reqUrl.host !== orgUrl.host) { 776 | request.crossOrigin = true; 777 | request.emulateHTTP = false; 778 | 779 | if (!SUPPORTS_CORS) { 780 | request.client = xdrClient; 781 | } 782 | } 783 | } 784 | } 785 | 786 | /** 787 | * Form data Interceptor. 788 | */ 789 | function form (request) { 790 | if (isFormData(request.body)) { 791 | request.headers["delete"]('Content-Type'); 792 | } else if (isObject(request.body) && request.emulateJSON) { 793 | request.body = Url.params(request.body); 794 | request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); 795 | } 796 | } 797 | 798 | /** 799 | * JSON Interceptor. 800 | */ 801 | function json (request) { 802 | var type = request.headers.get('Content-Type') || ''; 803 | 804 | if (isObject(request.body) && type.indexOf('application/json') === 0) { 805 | request.body = JSON.stringify(request.body); 806 | } 807 | 808 | return function (response) { 809 | return response.bodyText ? when(response.text(), function (text) { 810 | var type = response.headers.get('Content-Type') || ''; 811 | 812 | if (type.indexOf('application/json') === 0 || isJson(text)) { 813 | try { 814 | response.body = JSON.parse(text); 815 | } catch (e) { 816 | response.body = null; 817 | } 818 | } else { 819 | response.body = text; 820 | } 821 | 822 | return response; 823 | }) : response; 824 | }; 825 | } 826 | 827 | function isJson(str) { 828 | var start = str.match(/^\s*(\[|\{)/); 829 | var end = { 830 | '[': /]\s*$/, 831 | '{': /}\s*$/ 832 | }; 833 | return start && end[start[1]].test(str); 834 | } 835 | 836 | /** 837 | * JSONP client (Browser). 838 | */ 839 | function jsonpClient (request) { 840 | return new PromiseObj(function (resolve) { 841 | var name = request.jsonp || 'callback', 842 | callback = request.jsonpCallback || '_jsonp' + Math.random().toString(36).substr(2), 843 | body = null, 844 | handler, 845 | script; 846 | 847 | handler = function handler(_ref) { 848 | var type = _ref.type; 849 | var status = 0; 850 | 851 | if (type === 'load' && body !== null) { 852 | status = 200; 853 | } else if (type === 'error') { 854 | status = 500; 855 | } 856 | 857 | if (status && window[callback]) { 858 | delete window[callback]; 859 | document.body.removeChild(script); 860 | } 861 | 862 | resolve(request.respondWith(body, { 863 | status: status 864 | })); 865 | }; 866 | 867 | window[callback] = function (result) { 868 | body = JSON.stringify(result); 869 | }; 870 | 871 | request.abort = function () { 872 | handler({ 873 | type: 'abort' 874 | }); 875 | }; 876 | 877 | request.params[name] = callback; 878 | 879 | if (request.timeout) { 880 | setTimeout(request.abort, request.timeout); 881 | } 882 | 883 | script = document.createElement('script'); 884 | script.src = request.getUrl(); 885 | script.type = 'text/javascript'; 886 | script.async = true; 887 | script.onload = handler; 888 | script.onerror = handler; 889 | document.body.appendChild(script); 890 | }); 891 | } 892 | 893 | /** 894 | * JSONP Interceptor. 895 | */ 896 | function jsonp (request) { 897 | if (request.method == 'JSONP') { 898 | request.client = jsonpClient; 899 | } 900 | } 901 | 902 | /** 903 | * Before Interceptor. 904 | */ 905 | function before (request) { 906 | if (isFunction(request.before)) { 907 | request.before.call(this, request); 908 | } 909 | } 910 | 911 | /** 912 | * HTTP method override Interceptor. 913 | */ 914 | function method (request) { 915 | if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { 916 | request.headers.set('X-HTTP-Method-Override', request.method); 917 | request.method = 'POST'; 918 | } 919 | } 920 | 921 | /** 922 | * Header Interceptor. 923 | */ 924 | function header (request) { 925 | var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[toLower(request.method)]); 926 | each(headers, function (value, name) { 927 | if (!request.headers.has(name)) { 928 | request.headers.set(name, value); 929 | } 930 | }); 931 | } 932 | 933 | /** 934 | * XMLHttp client (Browser). 935 | */ 936 | function xhrClient (request) { 937 | return new PromiseObj(function (resolve) { 938 | var xhr = new XMLHttpRequest(), 939 | handler = function handler(event) { 940 | var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { 941 | status: xhr.status === 1223 ? 204 : xhr.status, 942 | // IE9 status bug 943 | statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) 944 | }); 945 | each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { 946 | response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); 947 | }); 948 | resolve(response); 949 | }; 950 | 951 | request.abort = function () { 952 | return xhr.abort(); 953 | }; 954 | 955 | xhr.open(request.method, request.getUrl(), true); 956 | 957 | if (request.timeout) { 958 | xhr.timeout = request.timeout; 959 | } 960 | 961 | if (request.responseType && 'responseType' in xhr) { 962 | xhr.responseType = request.responseType; 963 | } 964 | 965 | if (request.withCredentials || request.credentials) { 966 | xhr.withCredentials = true; 967 | } 968 | 969 | if (!request.crossOrigin) { 970 | request.headers.set('X-Requested-With', 'XMLHttpRequest'); 971 | } // deprecated use downloadProgress 972 | 973 | 974 | if (isFunction(request.progress) && request.method === 'GET') { 975 | xhr.addEventListener('progress', request.progress); 976 | } 977 | 978 | if (isFunction(request.downloadProgress)) { 979 | xhr.addEventListener('progress', request.downloadProgress); 980 | } // deprecated use uploadProgress 981 | 982 | 983 | if (isFunction(request.progress) && /^(POST|PUT)$/i.test(request.method)) { 984 | xhr.upload.addEventListener('progress', request.progress); 985 | } 986 | 987 | if (isFunction(request.uploadProgress) && xhr.upload) { 988 | xhr.upload.addEventListener('progress', request.uploadProgress); 989 | } 990 | 991 | request.headers.forEach(function (value, name) { 992 | xhr.setRequestHeader(name, value); 993 | }); 994 | xhr.onload = handler; 995 | xhr.onabort = handler; 996 | xhr.onerror = handler; 997 | xhr.ontimeout = handler; 998 | xhr.send(request.getBody()); 999 | }); 1000 | } 1001 | 1002 | /** 1003 | * Http client (Node). 1004 | */ 1005 | function nodeClient (request) { 1006 | var client = require('got'); 1007 | 1008 | return new PromiseObj(function (resolve) { 1009 | var url = request.getUrl(); 1010 | var body = request.getBody(); 1011 | var method = request.method; 1012 | var headers = {}, 1013 | handler; 1014 | request.headers.forEach(function (value, name) { 1015 | headers[name] = value; 1016 | }); 1017 | client(url, { 1018 | body: body, 1019 | method: method, 1020 | headers: headers 1021 | }).then(handler = function handler(resp) { 1022 | var response = request.respondWith(resp.body, { 1023 | status: resp.statusCode, 1024 | statusText: trim(resp.statusMessage) 1025 | }); 1026 | each(resp.headers, function (value, name) { 1027 | response.headers.set(name, value); 1028 | }); 1029 | resolve(response); 1030 | }, function (error$$1) { 1031 | return handler(error$$1.response); 1032 | }); 1033 | }); 1034 | } 1035 | 1036 | /** 1037 | * Base client. 1038 | */ 1039 | function Client (context) { 1040 | var reqHandlers = [sendRequest], 1041 | resHandlers = []; 1042 | 1043 | if (!isObject(context)) { 1044 | context = null; 1045 | } 1046 | 1047 | function Client(request) { 1048 | while (reqHandlers.length) { 1049 | var handler = reqHandlers.pop(); 1050 | 1051 | if (isFunction(handler)) { 1052 | var _ret = function () { 1053 | var response = void 0, 1054 | next = void 0; 1055 | response = handler.call(context, request, function (val) { 1056 | return next = val; 1057 | }) || next; 1058 | 1059 | if (isObject(response)) { 1060 | return { 1061 | v: new PromiseObj(function (resolve, reject) { 1062 | resHandlers.forEach(function (handler) { 1063 | response = when(response, function (response) { 1064 | return handler.call(context, response) || response; 1065 | }, reject); 1066 | }); 1067 | when(response, resolve, reject); 1068 | }, context) 1069 | }; 1070 | } 1071 | 1072 | if (isFunction(response)) { 1073 | resHandlers.unshift(response); 1074 | } 1075 | }(); 1076 | 1077 | if (typeof _ret === "object") return _ret.v; 1078 | } else { 1079 | warn("Invalid interceptor of type " + typeof handler + ", must be a function"); 1080 | } 1081 | } 1082 | } 1083 | 1084 | Client.use = function (handler) { 1085 | reqHandlers.push(handler); 1086 | }; 1087 | 1088 | return Client; 1089 | } 1090 | 1091 | function sendRequest(request) { 1092 | var client = request.client || (inBrowser ? xhrClient : nodeClient); 1093 | return client(request); 1094 | } 1095 | 1096 | /** 1097 | * HTTP Headers. 1098 | */ 1099 | 1100 | var Headers = /*#__PURE__*/function () { 1101 | function Headers(headers) { 1102 | var _this = this; 1103 | 1104 | this.map = {}; 1105 | each(headers, function (value, name) { 1106 | return _this.append(name, value); 1107 | }); 1108 | } 1109 | 1110 | var _proto = Headers.prototype; 1111 | 1112 | _proto.has = function has(name) { 1113 | return getName(this.map, name) !== null; 1114 | }; 1115 | 1116 | _proto.get = function get(name) { 1117 | var list = this.map[getName(this.map, name)]; 1118 | return list ? list.join() : null; 1119 | }; 1120 | 1121 | _proto.getAll = function getAll(name) { 1122 | return this.map[getName(this.map, name)] || []; 1123 | }; 1124 | 1125 | _proto.set = function set(name, value) { 1126 | this.map[normalizeName(getName(this.map, name) || name)] = [trim(value)]; 1127 | }; 1128 | 1129 | _proto.append = function append(name, value) { 1130 | var list = this.map[getName(this.map, name)]; 1131 | 1132 | if (list) { 1133 | list.push(trim(value)); 1134 | } else { 1135 | this.set(name, value); 1136 | } 1137 | }; 1138 | 1139 | _proto["delete"] = function _delete(name) { 1140 | delete this.map[getName(this.map, name)]; 1141 | }; 1142 | 1143 | _proto.deleteAll = function deleteAll() { 1144 | this.map = {}; 1145 | }; 1146 | 1147 | _proto.forEach = function forEach(callback, thisArg) { 1148 | var _this2 = this; 1149 | 1150 | each(this.map, function (list, name) { 1151 | each(list, function (value) { 1152 | return callback.call(thisArg, value, name, _this2); 1153 | }); 1154 | }); 1155 | }; 1156 | 1157 | return Headers; 1158 | }(); 1159 | 1160 | function getName(map, name) { 1161 | return Object.keys(map).reduce(function (prev, curr) { 1162 | return toLower(name) === toLower(curr) ? curr : prev; 1163 | }, null); 1164 | } 1165 | 1166 | function normalizeName(name) { 1167 | if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) { 1168 | throw new TypeError('Invalid character in header field name'); 1169 | } 1170 | 1171 | return trim(name); 1172 | } 1173 | 1174 | /** 1175 | * HTTP Response. 1176 | */ 1177 | 1178 | var Response = /*#__PURE__*/function () { 1179 | function Response(body, _ref) { 1180 | var url = _ref.url, 1181 | headers = _ref.headers, 1182 | status = _ref.status, 1183 | statusText = _ref.statusText; 1184 | this.url = url; 1185 | this.ok = status >= 200 && status < 300; 1186 | this.status = status || 0; 1187 | this.statusText = statusText || ''; 1188 | this.headers = new Headers(headers); 1189 | this.body = body; 1190 | 1191 | if (isString(body)) { 1192 | this.bodyText = body; 1193 | } else if (isBlob(body)) { 1194 | this.bodyBlob = body; 1195 | 1196 | if (isBlobText(body)) { 1197 | this.bodyText = blobText(body); 1198 | } 1199 | } 1200 | } 1201 | 1202 | var _proto = Response.prototype; 1203 | 1204 | _proto.blob = function blob() { 1205 | return when(this.bodyBlob); 1206 | }; 1207 | 1208 | _proto.text = function text() { 1209 | return when(this.bodyText); 1210 | }; 1211 | 1212 | _proto.json = function json() { 1213 | return when(this.text(), function (text) { 1214 | return JSON.parse(text); 1215 | }); 1216 | }; 1217 | 1218 | return Response; 1219 | }(); 1220 | Object.defineProperty(Response.prototype, 'data', { 1221 | get: function get() { 1222 | return this.body; 1223 | }, 1224 | set: function set(body) { 1225 | this.body = body; 1226 | } 1227 | }); 1228 | 1229 | function blobText(body) { 1230 | return new PromiseObj(function (resolve) { 1231 | var reader = new FileReader(); 1232 | reader.readAsText(body); 1233 | 1234 | reader.onload = function () { 1235 | resolve(reader.result); 1236 | }; 1237 | }); 1238 | } 1239 | 1240 | function isBlobText(body) { 1241 | return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; 1242 | } 1243 | 1244 | /** 1245 | * HTTP Request. 1246 | */ 1247 | 1248 | var Request = /*#__PURE__*/function () { 1249 | function Request(options$$1) { 1250 | this.body = null; 1251 | this.params = {}; 1252 | assign(this, options$$1, { 1253 | method: toUpper(options$$1.method || 'GET') 1254 | }); 1255 | 1256 | if (!(this.headers instanceof Headers)) { 1257 | this.headers = new Headers(this.headers); 1258 | } 1259 | } 1260 | 1261 | var _proto = Request.prototype; 1262 | 1263 | _proto.getUrl = function getUrl() { 1264 | return Url(this); 1265 | }; 1266 | 1267 | _proto.getBody = function getBody() { 1268 | return this.body; 1269 | }; 1270 | 1271 | _proto.respondWith = function respondWith(body, options$$1) { 1272 | return new Response(body, assign(options$$1 || {}, { 1273 | url: this.getUrl() 1274 | })); 1275 | }; 1276 | 1277 | return Request; 1278 | }(); 1279 | 1280 | /** 1281 | * Service for sending network requests. 1282 | */ 1283 | var COMMON_HEADERS = { 1284 | 'Accept': 'application/json, text/plain, */*' 1285 | }; 1286 | var JSON_CONTENT_TYPE = { 1287 | 'Content-Type': 'application/json;charset=utf-8' 1288 | }; 1289 | function Http(options$$1) { 1290 | var self = this || {}, 1291 | client = Client(self.$vm); 1292 | defaults(options$$1 || {}, self.$options, Http.options); 1293 | Http.interceptors.forEach(function (handler) { 1294 | if (isString(handler)) { 1295 | handler = Http.interceptor[handler]; 1296 | } 1297 | 1298 | if (isFunction(handler)) { 1299 | client.use(handler); 1300 | } 1301 | }); 1302 | return client(new Request(options$$1)).then(function (response) { 1303 | return response.ok ? response : PromiseObj.reject(response); 1304 | }, function (response) { 1305 | if (response instanceof Error) { 1306 | error(response); 1307 | } 1308 | 1309 | return PromiseObj.reject(response); 1310 | }); 1311 | } 1312 | Http.options = {}; 1313 | Http.headers = { 1314 | put: JSON_CONTENT_TYPE, 1315 | post: JSON_CONTENT_TYPE, 1316 | patch: JSON_CONTENT_TYPE, 1317 | "delete": JSON_CONTENT_TYPE, 1318 | common: COMMON_HEADERS, 1319 | custom: {} 1320 | }; 1321 | Http.interceptor = { 1322 | before: before, 1323 | method: method, 1324 | jsonp: jsonp, 1325 | json: json, 1326 | form: form, 1327 | header: header, 1328 | cors: cors 1329 | }; 1330 | Http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors']; 1331 | ['get', 'delete', 'head', 'jsonp'].forEach(function (method$$1) { 1332 | Http[method$$1] = function (url, options$$1) { 1333 | return this(assign(options$$1 || {}, { 1334 | url: url, 1335 | method: method$$1 1336 | })); 1337 | }; 1338 | }); 1339 | ['post', 'put', 'patch'].forEach(function (method$$1) { 1340 | Http[method$$1] = function (url, body, options$$1) { 1341 | return this(assign(options$$1 || {}, { 1342 | url: url, 1343 | method: method$$1, 1344 | body: body 1345 | })); 1346 | }; 1347 | }); 1348 | 1349 | /** 1350 | * Service for interacting with RESTful services. 1351 | */ 1352 | function Resource(url, params, actions, options$$1) { 1353 | var self = this || {}, 1354 | resource = {}; 1355 | actions = assign({}, Resource.actions, actions); 1356 | each(actions, function (action, name) { 1357 | action = merge({ 1358 | url: url, 1359 | params: assign({}, params) 1360 | }, options$$1, action); 1361 | 1362 | resource[name] = function () { 1363 | return (self.$http || Http)(opts(action, arguments)); 1364 | }; 1365 | }); 1366 | return resource; 1367 | } 1368 | 1369 | function opts(action, args) { 1370 | var options$$1 = assign({}, action), 1371 | params = {}, 1372 | body; 1373 | 1374 | switch (args.length) { 1375 | case 2: 1376 | params = args[0]; 1377 | body = args[1]; 1378 | break; 1379 | 1380 | case 1: 1381 | if (/^(POST|PUT|PATCH)$/i.test(options$$1.method)) { 1382 | body = args[0]; 1383 | } else { 1384 | params = args[0]; 1385 | } 1386 | 1387 | break; 1388 | 1389 | case 0: 1390 | break; 1391 | 1392 | default: 1393 | throw 'Expected up to 2 arguments [params, body], got ' + args.length + ' arguments'; 1394 | } 1395 | 1396 | options$$1.body = body; 1397 | options$$1.params = assign({}, options$$1.params, params); 1398 | return options$$1; 1399 | } 1400 | 1401 | Resource.actions = { 1402 | get: { 1403 | method: 'GET' 1404 | }, 1405 | save: { 1406 | method: 'POST' 1407 | }, 1408 | query: { 1409 | method: 'GET' 1410 | }, 1411 | update: { 1412 | method: 'PUT' 1413 | }, 1414 | remove: { 1415 | method: 'DELETE' 1416 | }, 1417 | "delete": { 1418 | method: 'DELETE' 1419 | } 1420 | }; 1421 | 1422 | /** 1423 | * Install plugin. 1424 | */ 1425 | 1426 | function plugin(Vue) { 1427 | if (plugin.installed) { 1428 | return; 1429 | } 1430 | 1431 | Util(Vue); 1432 | Vue.url = Url; 1433 | Vue.http = Http; 1434 | Vue.resource = Resource; 1435 | Vue.Promise = PromiseObj; 1436 | Object.defineProperties(Vue.prototype, { 1437 | $url: { 1438 | get: function get() { 1439 | return options(Vue.url, this, this.$options.url); 1440 | } 1441 | }, 1442 | $http: { 1443 | get: function get() { 1444 | return options(Vue.http, this, this.$options.http); 1445 | } 1446 | }, 1447 | $resource: { 1448 | get: function get() { 1449 | return Vue.resource.bind(this); 1450 | } 1451 | }, 1452 | $promise: { 1453 | get: function get() { 1454 | var _this = this; 1455 | 1456 | return function (executor) { 1457 | return new Vue.Promise(executor, _this); 1458 | }; 1459 | } 1460 | } 1461 | }); 1462 | } 1463 | 1464 | if (typeof window !== 'undefined' && window.Vue && !window.Vue.resource) { 1465 | window.Vue.use(plugin); 1466 | } 1467 | 1468 | module.exports = plugin; 1469 | -------------------------------------------------------------------------------- /dist/vue-resource.esm.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-resource v1.5.3 3 | * https://github.com/pagekit/vue-resource 4 | * Released under the MIT License. 5 | */ 6 | 7 | /** 8 | * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) 9 | */ 10 | var RESOLVED = 0; 11 | var REJECTED = 1; 12 | var PENDING = 2; 13 | function Promise$1(executor) { 14 | this.state = PENDING; 15 | this.value = undefined; 16 | this.deferred = []; 17 | var promise = this; 18 | 19 | try { 20 | executor(function (x) { 21 | promise.resolve(x); 22 | }, function (r) { 23 | promise.reject(r); 24 | }); 25 | } catch (e) { 26 | promise.reject(e); 27 | } 28 | } 29 | 30 | Promise$1.reject = function (r) { 31 | return new Promise$1(function (resolve, reject) { 32 | reject(r); 33 | }); 34 | }; 35 | 36 | Promise$1.resolve = function (x) { 37 | return new Promise$1(function (resolve, reject) { 38 | resolve(x); 39 | }); 40 | }; 41 | 42 | Promise$1.all = function all(iterable) { 43 | return new Promise$1(function (resolve, reject) { 44 | var count = 0, 45 | result = []; 46 | 47 | if (iterable.length === 0) { 48 | resolve(result); 49 | } 50 | 51 | function resolver(i) { 52 | return function (x) { 53 | result[i] = x; 54 | count += 1; 55 | 56 | if (count === iterable.length) { 57 | resolve(result); 58 | } 59 | }; 60 | } 61 | 62 | for (var i = 0; i < iterable.length; i += 1) { 63 | Promise$1.resolve(iterable[i]).then(resolver(i), reject); 64 | } 65 | }); 66 | }; 67 | 68 | Promise$1.race = function race(iterable) { 69 | return new Promise$1(function (resolve, reject) { 70 | for (var i = 0; i < iterable.length; i += 1) { 71 | Promise$1.resolve(iterable[i]).then(resolve, reject); 72 | } 73 | }); 74 | }; 75 | 76 | var p = Promise$1.prototype; 77 | 78 | p.resolve = function resolve(x) { 79 | var promise = this; 80 | 81 | if (promise.state === PENDING) { 82 | if (x === promise) { 83 | throw new TypeError('Promise settled with itself.'); 84 | } 85 | 86 | var called = false; 87 | 88 | try { 89 | var then = x && x['then']; 90 | 91 | if (x !== null && typeof x === 'object' && typeof then === 'function') { 92 | then.call(x, function (x) { 93 | if (!called) { 94 | promise.resolve(x); 95 | } 96 | 97 | called = true; 98 | }, function (r) { 99 | if (!called) { 100 | promise.reject(r); 101 | } 102 | 103 | called = true; 104 | }); 105 | return; 106 | } 107 | } catch (e) { 108 | if (!called) { 109 | promise.reject(e); 110 | } 111 | 112 | return; 113 | } 114 | 115 | promise.state = RESOLVED; 116 | promise.value = x; 117 | promise.notify(); 118 | } 119 | }; 120 | 121 | p.reject = function reject(reason) { 122 | var promise = this; 123 | 124 | if (promise.state === PENDING) { 125 | if (reason === promise) { 126 | throw new TypeError('Promise settled with itself.'); 127 | } 128 | 129 | promise.state = REJECTED; 130 | promise.value = reason; 131 | promise.notify(); 132 | } 133 | }; 134 | 135 | p.notify = function notify() { 136 | var promise = this; 137 | nextTick(function () { 138 | if (promise.state !== PENDING) { 139 | while (promise.deferred.length) { 140 | var deferred = promise.deferred.shift(), 141 | onResolved = deferred[0], 142 | onRejected = deferred[1], 143 | resolve = deferred[2], 144 | reject = deferred[3]; 145 | 146 | try { 147 | if (promise.state === RESOLVED) { 148 | if (typeof onResolved === 'function') { 149 | resolve(onResolved.call(undefined, promise.value)); 150 | } else { 151 | resolve(promise.value); 152 | } 153 | } else if (promise.state === REJECTED) { 154 | if (typeof onRejected === 'function') { 155 | resolve(onRejected.call(undefined, promise.value)); 156 | } else { 157 | reject(promise.value); 158 | } 159 | } 160 | } catch (e) { 161 | reject(e); 162 | } 163 | } 164 | } 165 | }); 166 | }; 167 | 168 | p.then = function then(onResolved, onRejected) { 169 | var promise = this; 170 | return new Promise$1(function (resolve, reject) { 171 | promise.deferred.push([onResolved, onRejected, resolve, reject]); 172 | promise.notify(); 173 | }); 174 | }; 175 | 176 | p["catch"] = function (onRejected) { 177 | return this.then(undefined, onRejected); 178 | }; 179 | 180 | /** 181 | * Promise adapter. 182 | */ 183 | 184 | if (typeof Promise === 'undefined') { 185 | window.Promise = Promise$1; 186 | } 187 | 188 | function PromiseObj(executor, context) { 189 | if (executor instanceof Promise) { 190 | this.promise = executor; 191 | } else { 192 | this.promise = new Promise(executor.bind(context)); 193 | } 194 | 195 | this.context = context; 196 | } 197 | 198 | PromiseObj.all = function (iterable, context) { 199 | return new PromiseObj(Promise.all(iterable), context); 200 | }; 201 | 202 | PromiseObj.resolve = function (value, context) { 203 | return new PromiseObj(Promise.resolve(value), context); 204 | }; 205 | 206 | PromiseObj.reject = function (reason, context) { 207 | return new PromiseObj(Promise.reject(reason), context); 208 | }; 209 | 210 | PromiseObj.race = function (iterable, context) { 211 | return new PromiseObj(Promise.race(iterable), context); 212 | }; 213 | 214 | var p$1 = PromiseObj.prototype; 215 | 216 | p$1.bind = function (context) { 217 | this.context = context; 218 | return this; 219 | }; 220 | 221 | p$1.then = function (fulfilled, rejected) { 222 | if (fulfilled && fulfilled.bind && this.context) { 223 | fulfilled = fulfilled.bind(this.context); 224 | } 225 | 226 | if (rejected && rejected.bind && this.context) { 227 | rejected = rejected.bind(this.context); 228 | } 229 | 230 | return new PromiseObj(this.promise.then(fulfilled, rejected), this.context); 231 | }; 232 | 233 | p$1["catch"] = function (rejected) { 234 | if (rejected && rejected.bind && this.context) { 235 | rejected = rejected.bind(this.context); 236 | } 237 | 238 | return new PromiseObj(this.promise["catch"](rejected), this.context); 239 | }; 240 | 241 | p$1["finally"] = function (callback) { 242 | return this.then(function (value) { 243 | callback.call(this); 244 | return value; 245 | }, function (reason) { 246 | callback.call(this); 247 | return Promise.reject(reason); 248 | }); 249 | }; 250 | 251 | /** 252 | * Utility functions. 253 | */ 254 | var _ref = {}, 255 | hasOwnProperty = _ref.hasOwnProperty, 256 | slice = [].slice, 257 | debug = false, 258 | ntick; 259 | var inBrowser = typeof window !== 'undefined'; 260 | function Util (_ref2) { 261 | var config = _ref2.config, 262 | nextTick = _ref2.nextTick; 263 | ntick = nextTick; 264 | debug = config.debug || !config.silent; 265 | } 266 | function warn(msg) { 267 | if (typeof console !== 'undefined' && debug) { 268 | console.warn('[VueResource warn]: ' + msg); 269 | } 270 | } 271 | function error(msg) { 272 | if (typeof console !== 'undefined') { 273 | console.error(msg); 274 | } 275 | } 276 | function nextTick(cb, ctx) { 277 | return ntick(cb, ctx); 278 | } 279 | function trim(str) { 280 | return str ? str.replace(/^\s*|\s*$/g, '') : ''; 281 | } 282 | function trimEnd(str, chars) { 283 | if (str && chars === undefined) { 284 | return str.replace(/\s+$/, ''); 285 | } 286 | 287 | if (!str || !chars) { 288 | return str; 289 | } 290 | 291 | return str.replace(new RegExp("[" + chars + "]+$"), ''); 292 | } 293 | function toLower(str) { 294 | return str ? str.toLowerCase() : ''; 295 | } 296 | function toUpper(str) { 297 | return str ? str.toUpperCase() : ''; 298 | } 299 | var isArray = Array.isArray; 300 | function isString(val) { 301 | return typeof val === 'string'; 302 | } 303 | function isFunction(val) { 304 | return typeof val === 'function'; 305 | } 306 | function isObject(obj) { 307 | return obj !== null && typeof obj === 'object'; 308 | } 309 | function isPlainObject(obj) { 310 | return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; 311 | } 312 | function isBlob(obj) { 313 | return typeof Blob !== 'undefined' && obj instanceof Blob; 314 | } 315 | function isFormData(obj) { 316 | return typeof FormData !== 'undefined' && obj instanceof FormData; 317 | } 318 | function when(value, fulfilled, rejected) { 319 | var promise = PromiseObj.resolve(value); 320 | 321 | if (arguments.length < 2) { 322 | return promise; 323 | } 324 | 325 | return promise.then(fulfilled, rejected); 326 | } 327 | function options(fn, obj, opts) { 328 | opts = opts || {}; 329 | 330 | if (isFunction(opts)) { 331 | opts = opts.call(obj); 332 | } 333 | 334 | return merge(fn.bind({ 335 | $vm: obj, 336 | $options: opts 337 | }), fn, { 338 | $options: opts 339 | }); 340 | } 341 | function each(obj, iterator) { 342 | var i, key; 343 | 344 | if (isArray(obj)) { 345 | for (i = 0; i < obj.length; i++) { 346 | iterator.call(obj[i], obj[i], i); 347 | } 348 | } else if (isObject(obj)) { 349 | for (key in obj) { 350 | if (hasOwnProperty.call(obj, key)) { 351 | iterator.call(obj[key], obj[key], key); 352 | } 353 | } 354 | } 355 | 356 | return obj; 357 | } 358 | var assign = Object.assign || _assign; 359 | function merge(target) { 360 | var args = slice.call(arguments, 1); 361 | args.forEach(function (source) { 362 | _merge(target, source, true); 363 | }); 364 | return target; 365 | } 366 | function defaults(target) { 367 | var args = slice.call(arguments, 1); 368 | args.forEach(function (source) { 369 | for (var key in source) { 370 | if (target[key] === undefined) { 371 | target[key] = source[key]; 372 | } 373 | } 374 | }); 375 | return target; 376 | } 377 | 378 | function _assign(target) { 379 | var args = slice.call(arguments, 1); 380 | args.forEach(function (source) { 381 | _merge(target, source); 382 | }); 383 | return target; 384 | } 385 | 386 | function _merge(target, source, deep) { 387 | for (var key in source) { 388 | if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { 389 | if (isPlainObject(source[key]) && !isPlainObject(target[key])) { 390 | target[key] = {}; 391 | } 392 | 393 | if (isArray(source[key]) && !isArray(target[key])) { 394 | target[key] = []; 395 | } 396 | 397 | _merge(target[key], source[key], deep); 398 | } else if (source[key] !== undefined) { 399 | target[key] = source[key]; 400 | } 401 | } 402 | } 403 | 404 | /** 405 | * Root Prefix Transform. 406 | */ 407 | function root (options$$1, next) { 408 | var url = next(options$$1); 409 | 410 | if (isString(options$$1.root) && !/^(https?:)?\//.test(url)) { 411 | url = trimEnd(options$$1.root, '/') + '/' + url; 412 | } 413 | 414 | return url; 415 | } 416 | 417 | /** 418 | * Query Parameter Transform. 419 | */ 420 | function query (options$$1, next) { 421 | var urlParams = Object.keys(Url.options.params), 422 | query = {}, 423 | url = next(options$$1); 424 | each(options$$1.params, function (value, key) { 425 | if (urlParams.indexOf(key) === -1) { 426 | query[key] = value; 427 | } 428 | }); 429 | query = Url.params(query); 430 | 431 | if (query) { 432 | url += (url.indexOf('?') == -1 ? '?' : '&') + query; 433 | } 434 | 435 | return url; 436 | } 437 | 438 | /** 439 | * URL Template v2.0.6 (https://github.com/bramstein/url-template) 440 | */ 441 | function expand(url, params, variables) { 442 | var tmpl = parse(url), 443 | expanded = tmpl.expand(params); 444 | 445 | if (variables) { 446 | variables.push.apply(variables, tmpl.vars); 447 | } 448 | 449 | return expanded; 450 | } 451 | function parse(template) { 452 | var operators = ['+', '#', '.', '/', ';', '?', '&'], 453 | variables = []; 454 | return { 455 | vars: variables, 456 | expand: function expand(context) { 457 | return template.replace(/\{([^{}]+)\}|([^{}]+)/g, function (_, expression, literal) { 458 | if (expression) { 459 | var operator = null, 460 | values = []; 461 | 462 | if (operators.indexOf(expression.charAt(0)) !== -1) { 463 | operator = expression.charAt(0); 464 | expression = expression.substr(1); 465 | } 466 | 467 | expression.split(/,/g).forEach(function (variable) { 468 | var tmp = /([^:*]*)(?::(\d+)|(\*))?/.exec(variable); 469 | values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); 470 | variables.push(tmp[1]); 471 | }); 472 | 473 | if (operator && operator !== '+') { 474 | var separator = ','; 475 | 476 | if (operator === '?') { 477 | separator = '&'; 478 | } else if (operator !== '#') { 479 | separator = operator; 480 | } 481 | 482 | return (values.length !== 0 ? operator : '') + values.join(separator); 483 | } else { 484 | return values.join(','); 485 | } 486 | } else { 487 | return encodeReserved(literal); 488 | } 489 | }); 490 | } 491 | }; 492 | } 493 | 494 | function getValues(context, operator, key, modifier) { 495 | var value = context[key], 496 | result = []; 497 | 498 | if (isDefined(value) && value !== '') { 499 | if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { 500 | value = value.toString(); 501 | 502 | if (modifier && modifier !== '*') { 503 | value = value.substring(0, parseInt(modifier, 10)); 504 | } 505 | 506 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 507 | } else { 508 | if (modifier === '*') { 509 | if (Array.isArray(value)) { 510 | value.filter(isDefined).forEach(function (value) { 511 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 512 | }); 513 | } else { 514 | Object.keys(value).forEach(function (k) { 515 | if (isDefined(value[k])) { 516 | result.push(encodeValue(operator, value[k], k)); 517 | } 518 | }); 519 | } 520 | } else { 521 | var tmp = []; 522 | 523 | if (Array.isArray(value)) { 524 | value.filter(isDefined).forEach(function (value) { 525 | tmp.push(encodeValue(operator, value)); 526 | }); 527 | } else { 528 | Object.keys(value).forEach(function (k) { 529 | if (isDefined(value[k])) { 530 | tmp.push(encodeURIComponent(k)); 531 | tmp.push(encodeValue(operator, value[k].toString())); 532 | } 533 | }); 534 | } 535 | 536 | if (isKeyOperator(operator)) { 537 | result.push(encodeURIComponent(key) + '=' + tmp.join(',')); 538 | } else if (tmp.length !== 0) { 539 | result.push(tmp.join(',')); 540 | } 541 | } 542 | } 543 | } else { 544 | if (operator === ';') { 545 | result.push(encodeURIComponent(key)); 546 | } else if (value === '' && (operator === '&' || operator === '?')) { 547 | result.push(encodeURIComponent(key) + '='); 548 | } else if (value === '') { 549 | result.push(''); 550 | } 551 | } 552 | 553 | return result; 554 | } 555 | 556 | function isDefined(value) { 557 | return value !== undefined && value !== null; 558 | } 559 | 560 | function isKeyOperator(operator) { 561 | return operator === ';' || operator === '&' || operator === '?'; 562 | } 563 | 564 | function encodeValue(operator, value, key) { 565 | value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); 566 | 567 | if (key) { 568 | return encodeURIComponent(key) + '=' + value; 569 | } else { 570 | return value; 571 | } 572 | } 573 | 574 | function encodeReserved(str) { 575 | return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { 576 | if (!/%[0-9A-Fa-f]/.test(part)) { 577 | part = encodeURI(part); 578 | } 579 | 580 | return part; 581 | }).join(''); 582 | } 583 | 584 | /** 585 | * URL Template (RFC 6570) Transform. 586 | */ 587 | function template (options) { 588 | var variables = [], 589 | url = expand(options.url, options.params, variables); 590 | variables.forEach(function (key) { 591 | delete options.params[key]; 592 | }); 593 | return url; 594 | } 595 | 596 | /** 597 | * Service for URL templating. 598 | */ 599 | function Url(url, params) { 600 | var self = this || {}, 601 | options$$1 = url, 602 | transform; 603 | 604 | if (isString(url)) { 605 | options$$1 = { 606 | url: url, 607 | params: params 608 | }; 609 | } 610 | 611 | options$$1 = merge({}, Url.options, self.$options, options$$1); 612 | Url.transforms.forEach(function (handler) { 613 | if (isString(handler)) { 614 | handler = Url.transform[handler]; 615 | } 616 | 617 | if (isFunction(handler)) { 618 | transform = factory(handler, transform, self.$vm); 619 | } 620 | }); 621 | return transform(options$$1); 622 | } 623 | /** 624 | * Url options. 625 | */ 626 | 627 | Url.options = { 628 | url: '', 629 | root: null, 630 | params: {} 631 | }; 632 | /** 633 | * Url transforms. 634 | */ 635 | 636 | Url.transform = { 637 | template: template, 638 | query: query, 639 | root: root 640 | }; 641 | Url.transforms = ['template', 'query', 'root']; 642 | /** 643 | * Encodes a Url parameter string. 644 | * 645 | * @param {Object} obj 646 | */ 647 | 648 | Url.params = function (obj) { 649 | var params = [], 650 | escape = encodeURIComponent; 651 | 652 | params.add = function (key, value) { 653 | if (isFunction(value)) { 654 | value = value(); 655 | } 656 | 657 | if (value === null) { 658 | value = ''; 659 | } 660 | 661 | this.push(escape(key) + '=' + escape(value)); 662 | }; 663 | 664 | serialize(params, obj); 665 | return params.join('&').replace(/%20/g, '+'); 666 | }; 667 | /** 668 | * Parse a URL and return its components. 669 | * 670 | * @param {String} url 671 | */ 672 | 673 | 674 | Url.parse = function (url) { 675 | var el = document.createElement('a'); 676 | 677 | if (document.documentMode) { 678 | el.href = url; 679 | url = el.href; 680 | } 681 | 682 | el.href = url; 683 | return { 684 | href: el.href, 685 | protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', 686 | port: el.port, 687 | host: el.host, 688 | hostname: el.hostname, 689 | pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, 690 | search: el.search ? el.search.replace(/^\?/, '') : '', 691 | hash: el.hash ? el.hash.replace(/^#/, '') : '' 692 | }; 693 | }; 694 | 695 | function factory(handler, next, vm) { 696 | return function (options$$1) { 697 | return handler.call(vm, options$$1, next); 698 | }; 699 | } 700 | 701 | function serialize(params, obj, scope) { 702 | var array = isArray(obj), 703 | plain = isPlainObject(obj), 704 | hash; 705 | each(obj, function (value, key) { 706 | hash = isObject(value) || isArray(value); 707 | 708 | if (scope) { 709 | key = scope + '[' + (plain || hash ? key : '') + ']'; 710 | } 711 | 712 | if (!scope && array) { 713 | params.add(value.name, value.value); 714 | } else if (hash) { 715 | serialize(params, value, key); 716 | } else { 717 | params.add(key, value); 718 | } 719 | }); 720 | } 721 | 722 | /** 723 | * XDomain client (Internet Explorer). 724 | */ 725 | function xdrClient (request) { 726 | return new PromiseObj(function (resolve) { 727 | var xdr = new XDomainRequest(), 728 | handler = function handler(_ref) { 729 | var type = _ref.type; 730 | var status = 0; 731 | 732 | if (type === 'load') { 733 | status = 200; 734 | } else if (type === 'error') { 735 | status = 500; 736 | } 737 | 738 | resolve(request.respondWith(xdr.responseText, { 739 | status: status 740 | })); 741 | }; 742 | 743 | request.abort = function () { 744 | return xdr.abort(); 745 | }; 746 | 747 | xdr.open(request.method, request.getUrl()); 748 | 749 | if (request.timeout) { 750 | xdr.timeout = request.timeout; 751 | } 752 | 753 | xdr.onload = handler; 754 | xdr.onabort = handler; 755 | xdr.onerror = handler; 756 | xdr.ontimeout = handler; 757 | 758 | xdr.onprogress = function () {}; 759 | 760 | xdr.send(request.getBody()); 761 | }); 762 | } 763 | 764 | /** 765 | * CORS Interceptor. 766 | */ 767 | var SUPPORTS_CORS = inBrowser && 'withCredentials' in new XMLHttpRequest(); 768 | function cors (request) { 769 | if (inBrowser) { 770 | var orgUrl = Url.parse(location.href); 771 | var reqUrl = Url.parse(request.getUrl()); 772 | 773 | if (reqUrl.protocol !== orgUrl.protocol || reqUrl.host !== orgUrl.host) { 774 | request.crossOrigin = true; 775 | request.emulateHTTP = false; 776 | 777 | if (!SUPPORTS_CORS) { 778 | request.client = xdrClient; 779 | } 780 | } 781 | } 782 | } 783 | 784 | /** 785 | * Form data Interceptor. 786 | */ 787 | function form (request) { 788 | if (isFormData(request.body)) { 789 | request.headers["delete"]('Content-Type'); 790 | } else if (isObject(request.body) && request.emulateJSON) { 791 | request.body = Url.params(request.body); 792 | request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); 793 | } 794 | } 795 | 796 | /** 797 | * JSON Interceptor. 798 | */ 799 | function json (request) { 800 | var type = request.headers.get('Content-Type') || ''; 801 | 802 | if (isObject(request.body) && type.indexOf('application/json') === 0) { 803 | request.body = JSON.stringify(request.body); 804 | } 805 | 806 | return function (response) { 807 | return response.bodyText ? when(response.text(), function (text) { 808 | var type = response.headers.get('Content-Type') || ''; 809 | 810 | if (type.indexOf('application/json') === 0 || isJson(text)) { 811 | try { 812 | response.body = JSON.parse(text); 813 | } catch (e) { 814 | response.body = null; 815 | } 816 | } else { 817 | response.body = text; 818 | } 819 | 820 | return response; 821 | }) : response; 822 | }; 823 | } 824 | 825 | function isJson(str) { 826 | var start = str.match(/^\s*(\[|\{)/); 827 | var end = { 828 | '[': /]\s*$/, 829 | '{': /}\s*$/ 830 | }; 831 | return start && end[start[1]].test(str); 832 | } 833 | 834 | /** 835 | * JSONP client (Browser). 836 | */ 837 | function jsonpClient (request) { 838 | return new PromiseObj(function (resolve) { 839 | var name = request.jsonp || 'callback', 840 | callback = request.jsonpCallback || '_jsonp' + Math.random().toString(36).substr(2), 841 | body = null, 842 | handler, 843 | script; 844 | 845 | handler = function handler(_ref) { 846 | var type = _ref.type; 847 | var status = 0; 848 | 849 | if (type === 'load' && body !== null) { 850 | status = 200; 851 | } else if (type === 'error') { 852 | status = 500; 853 | } 854 | 855 | if (status && window[callback]) { 856 | delete window[callback]; 857 | document.body.removeChild(script); 858 | } 859 | 860 | resolve(request.respondWith(body, { 861 | status: status 862 | })); 863 | }; 864 | 865 | window[callback] = function (result) { 866 | body = JSON.stringify(result); 867 | }; 868 | 869 | request.abort = function () { 870 | handler({ 871 | type: 'abort' 872 | }); 873 | }; 874 | 875 | request.params[name] = callback; 876 | 877 | if (request.timeout) { 878 | setTimeout(request.abort, request.timeout); 879 | } 880 | 881 | script = document.createElement('script'); 882 | script.src = request.getUrl(); 883 | script.type = 'text/javascript'; 884 | script.async = true; 885 | script.onload = handler; 886 | script.onerror = handler; 887 | document.body.appendChild(script); 888 | }); 889 | } 890 | 891 | /** 892 | * JSONP Interceptor. 893 | */ 894 | function jsonp (request) { 895 | if (request.method == 'JSONP') { 896 | request.client = jsonpClient; 897 | } 898 | } 899 | 900 | /** 901 | * Before Interceptor. 902 | */ 903 | function before (request) { 904 | if (isFunction(request.before)) { 905 | request.before.call(this, request); 906 | } 907 | } 908 | 909 | /** 910 | * HTTP method override Interceptor. 911 | */ 912 | function method (request) { 913 | if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { 914 | request.headers.set('X-HTTP-Method-Override', request.method); 915 | request.method = 'POST'; 916 | } 917 | } 918 | 919 | /** 920 | * Header Interceptor. 921 | */ 922 | function header (request) { 923 | var headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[toLower(request.method)]); 924 | each(headers, function (value, name) { 925 | if (!request.headers.has(name)) { 926 | request.headers.set(name, value); 927 | } 928 | }); 929 | } 930 | 931 | /** 932 | * XMLHttp client (Browser). 933 | */ 934 | function xhrClient (request) { 935 | return new PromiseObj(function (resolve) { 936 | var xhr = new XMLHttpRequest(), 937 | handler = function handler(event) { 938 | var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { 939 | status: xhr.status === 1223 ? 204 : xhr.status, 940 | // IE9 status bug 941 | statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) 942 | }); 943 | each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { 944 | response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); 945 | }); 946 | resolve(response); 947 | }; 948 | 949 | request.abort = function () { 950 | return xhr.abort(); 951 | }; 952 | 953 | xhr.open(request.method, request.getUrl(), true); 954 | 955 | if (request.timeout) { 956 | xhr.timeout = request.timeout; 957 | } 958 | 959 | if (request.responseType && 'responseType' in xhr) { 960 | xhr.responseType = request.responseType; 961 | } 962 | 963 | if (request.withCredentials || request.credentials) { 964 | xhr.withCredentials = true; 965 | } 966 | 967 | if (!request.crossOrigin) { 968 | request.headers.set('X-Requested-With', 'XMLHttpRequest'); 969 | } // deprecated use downloadProgress 970 | 971 | 972 | if (isFunction(request.progress) && request.method === 'GET') { 973 | xhr.addEventListener('progress', request.progress); 974 | } 975 | 976 | if (isFunction(request.downloadProgress)) { 977 | xhr.addEventListener('progress', request.downloadProgress); 978 | } // deprecated use uploadProgress 979 | 980 | 981 | if (isFunction(request.progress) && /^(POST|PUT)$/i.test(request.method)) { 982 | xhr.upload.addEventListener('progress', request.progress); 983 | } 984 | 985 | if (isFunction(request.uploadProgress) && xhr.upload) { 986 | xhr.upload.addEventListener('progress', request.uploadProgress); 987 | } 988 | 989 | request.headers.forEach(function (value, name) { 990 | xhr.setRequestHeader(name, value); 991 | }); 992 | xhr.onload = handler; 993 | xhr.onabort = handler; 994 | xhr.onerror = handler; 995 | xhr.ontimeout = handler; 996 | xhr.send(request.getBody()); 997 | }); 998 | } 999 | 1000 | /** 1001 | * Http client (Node). 1002 | */ 1003 | function nodeClient (request) { 1004 | var client = require('got'); 1005 | 1006 | return new PromiseObj(function (resolve) { 1007 | var url = request.getUrl(); 1008 | var body = request.getBody(); 1009 | var method = request.method; 1010 | var headers = {}, 1011 | handler; 1012 | request.headers.forEach(function (value, name) { 1013 | headers[name] = value; 1014 | }); 1015 | client(url, { 1016 | body: body, 1017 | method: method, 1018 | headers: headers 1019 | }).then(handler = function handler(resp) { 1020 | var response = request.respondWith(resp.body, { 1021 | status: resp.statusCode, 1022 | statusText: trim(resp.statusMessage) 1023 | }); 1024 | each(resp.headers, function (value, name) { 1025 | response.headers.set(name, value); 1026 | }); 1027 | resolve(response); 1028 | }, function (error$$1) { 1029 | return handler(error$$1.response); 1030 | }); 1031 | }); 1032 | } 1033 | 1034 | /** 1035 | * Base client. 1036 | */ 1037 | function Client (context) { 1038 | var reqHandlers = [sendRequest], 1039 | resHandlers = []; 1040 | 1041 | if (!isObject(context)) { 1042 | context = null; 1043 | } 1044 | 1045 | function Client(request) { 1046 | while (reqHandlers.length) { 1047 | var handler = reqHandlers.pop(); 1048 | 1049 | if (isFunction(handler)) { 1050 | var _ret = function () { 1051 | var response = void 0, 1052 | next = void 0; 1053 | response = handler.call(context, request, function (val) { 1054 | return next = val; 1055 | }) || next; 1056 | 1057 | if (isObject(response)) { 1058 | return { 1059 | v: new PromiseObj(function (resolve, reject) { 1060 | resHandlers.forEach(function (handler) { 1061 | response = when(response, function (response) { 1062 | return handler.call(context, response) || response; 1063 | }, reject); 1064 | }); 1065 | when(response, resolve, reject); 1066 | }, context) 1067 | }; 1068 | } 1069 | 1070 | if (isFunction(response)) { 1071 | resHandlers.unshift(response); 1072 | } 1073 | }(); 1074 | 1075 | if (typeof _ret === "object") return _ret.v; 1076 | } else { 1077 | warn("Invalid interceptor of type " + typeof handler + ", must be a function"); 1078 | } 1079 | } 1080 | } 1081 | 1082 | Client.use = function (handler) { 1083 | reqHandlers.push(handler); 1084 | }; 1085 | 1086 | return Client; 1087 | } 1088 | 1089 | function sendRequest(request) { 1090 | var client = request.client || (inBrowser ? xhrClient : nodeClient); 1091 | return client(request); 1092 | } 1093 | 1094 | /** 1095 | * HTTP Headers. 1096 | */ 1097 | 1098 | var Headers = /*#__PURE__*/function () { 1099 | function Headers(headers) { 1100 | var _this = this; 1101 | 1102 | this.map = {}; 1103 | each(headers, function (value, name) { 1104 | return _this.append(name, value); 1105 | }); 1106 | } 1107 | 1108 | var _proto = Headers.prototype; 1109 | 1110 | _proto.has = function has(name) { 1111 | return getName(this.map, name) !== null; 1112 | }; 1113 | 1114 | _proto.get = function get(name) { 1115 | var list = this.map[getName(this.map, name)]; 1116 | return list ? list.join() : null; 1117 | }; 1118 | 1119 | _proto.getAll = function getAll(name) { 1120 | return this.map[getName(this.map, name)] || []; 1121 | }; 1122 | 1123 | _proto.set = function set(name, value) { 1124 | this.map[normalizeName(getName(this.map, name) || name)] = [trim(value)]; 1125 | }; 1126 | 1127 | _proto.append = function append(name, value) { 1128 | var list = this.map[getName(this.map, name)]; 1129 | 1130 | if (list) { 1131 | list.push(trim(value)); 1132 | } else { 1133 | this.set(name, value); 1134 | } 1135 | }; 1136 | 1137 | _proto["delete"] = function _delete(name) { 1138 | delete this.map[getName(this.map, name)]; 1139 | }; 1140 | 1141 | _proto.deleteAll = function deleteAll() { 1142 | this.map = {}; 1143 | }; 1144 | 1145 | _proto.forEach = function forEach(callback, thisArg) { 1146 | var _this2 = this; 1147 | 1148 | each(this.map, function (list, name) { 1149 | each(list, function (value) { 1150 | return callback.call(thisArg, value, name, _this2); 1151 | }); 1152 | }); 1153 | }; 1154 | 1155 | return Headers; 1156 | }(); 1157 | 1158 | function getName(map, name) { 1159 | return Object.keys(map).reduce(function (prev, curr) { 1160 | return toLower(name) === toLower(curr) ? curr : prev; 1161 | }, null); 1162 | } 1163 | 1164 | function normalizeName(name) { 1165 | if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) { 1166 | throw new TypeError('Invalid character in header field name'); 1167 | } 1168 | 1169 | return trim(name); 1170 | } 1171 | 1172 | /** 1173 | * HTTP Response. 1174 | */ 1175 | 1176 | var Response = /*#__PURE__*/function () { 1177 | function Response(body, _ref) { 1178 | var url = _ref.url, 1179 | headers = _ref.headers, 1180 | status = _ref.status, 1181 | statusText = _ref.statusText; 1182 | this.url = url; 1183 | this.ok = status >= 200 && status < 300; 1184 | this.status = status || 0; 1185 | this.statusText = statusText || ''; 1186 | this.headers = new Headers(headers); 1187 | this.body = body; 1188 | 1189 | if (isString(body)) { 1190 | this.bodyText = body; 1191 | } else if (isBlob(body)) { 1192 | this.bodyBlob = body; 1193 | 1194 | if (isBlobText(body)) { 1195 | this.bodyText = blobText(body); 1196 | } 1197 | } 1198 | } 1199 | 1200 | var _proto = Response.prototype; 1201 | 1202 | _proto.blob = function blob() { 1203 | return when(this.bodyBlob); 1204 | }; 1205 | 1206 | _proto.text = function text() { 1207 | return when(this.bodyText); 1208 | }; 1209 | 1210 | _proto.json = function json() { 1211 | return when(this.text(), function (text) { 1212 | return JSON.parse(text); 1213 | }); 1214 | }; 1215 | 1216 | return Response; 1217 | }(); 1218 | Object.defineProperty(Response.prototype, 'data', { 1219 | get: function get() { 1220 | return this.body; 1221 | }, 1222 | set: function set(body) { 1223 | this.body = body; 1224 | } 1225 | }); 1226 | 1227 | function blobText(body) { 1228 | return new PromiseObj(function (resolve) { 1229 | var reader = new FileReader(); 1230 | reader.readAsText(body); 1231 | 1232 | reader.onload = function () { 1233 | resolve(reader.result); 1234 | }; 1235 | }); 1236 | } 1237 | 1238 | function isBlobText(body) { 1239 | return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; 1240 | } 1241 | 1242 | /** 1243 | * HTTP Request. 1244 | */ 1245 | 1246 | var Request = /*#__PURE__*/function () { 1247 | function Request(options$$1) { 1248 | this.body = null; 1249 | this.params = {}; 1250 | assign(this, options$$1, { 1251 | method: toUpper(options$$1.method || 'GET') 1252 | }); 1253 | 1254 | if (!(this.headers instanceof Headers)) { 1255 | this.headers = new Headers(this.headers); 1256 | } 1257 | } 1258 | 1259 | var _proto = Request.prototype; 1260 | 1261 | _proto.getUrl = function getUrl() { 1262 | return Url(this); 1263 | }; 1264 | 1265 | _proto.getBody = function getBody() { 1266 | return this.body; 1267 | }; 1268 | 1269 | _proto.respondWith = function respondWith(body, options$$1) { 1270 | return new Response(body, assign(options$$1 || {}, { 1271 | url: this.getUrl() 1272 | })); 1273 | }; 1274 | 1275 | return Request; 1276 | }(); 1277 | 1278 | /** 1279 | * Service for sending network requests. 1280 | */ 1281 | var COMMON_HEADERS = { 1282 | 'Accept': 'application/json, text/plain, */*' 1283 | }; 1284 | var JSON_CONTENT_TYPE = { 1285 | 'Content-Type': 'application/json;charset=utf-8' 1286 | }; 1287 | function Http(options$$1) { 1288 | var self = this || {}, 1289 | client = Client(self.$vm); 1290 | defaults(options$$1 || {}, self.$options, Http.options); 1291 | Http.interceptors.forEach(function (handler) { 1292 | if (isString(handler)) { 1293 | handler = Http.interceptor[handler]; 1294 | } 1295 | 1296 | if (isFunction(handler)) { 1297 | client.use(handler); 1298 | } 1299 | }); 1300 | return client(new Request(options$$1)).then(function (response) { 1301 | return response.ok ? response : PromiseObj.reject(response); 1302 | }, function (response) { 1303 | if (response instanceof Error) { 1304 | error(response); 1305 | } 1306 | 1307 | return PromiseObj.reject(response); 1308 | }); 1309 | } 1310 | Http.options = {}; 1311 | Http.headers = { 1312 | put: JSON_CONTENT_TYPE, 1313 | post: JSON_CONTENT_TYPE, 1314 | patch: JSON_CONTENT_TYPE, 1315 | "delete": JSON_CONTENT_TYPE, 1316 | common: COMMON_HEADERS, 1317 | custom: {} 1318 | }; 1319 | Http.interceptor = { 1320 | before: before, 1321 | method: method, 1322 | jsonp: jsonp, 1323 | json: json, 1324 | form: form, 1325 | header: header, 1326 | cors: cors 1327 | }; 1328 | Http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors']; 1329 | ['get', 'delete', 'head', 'jsonp'].forEach(function (method$$1) { 1330 | Http[method$$1] = function (url, options$$1) { 1331 | return this(assign(options$$1 || {}, { 1332 | url: url, 1333 | method: method$$1 1334 | })); 1335 | }; 1336 | }); 1337 | ['post', 'put', 'patch'].forEach(function (method$$1) { 1338 | Http[method$$1] = function (url, body, options$$1) { 1339 | return this(assign(options$$1 || {}, { 1340 | url: url, 1341 | method: method$$1, 1342 | body: body 1343 | })); 1344 | }; 1345 | }); 1346 | 1347 | /** 1348 | * Service for interacting with RESTful services. 1349 | */ 1350 | function Resource(url, params, actions, options$$1) { 1351 | var self = this || {}, 1352 | resource = {}; 1353 | actions = assign({}, Resource.actions, actions); 1354 | each(actions, function (action, name) { 1355 | action = merge({ 1356 | url: url, 1357 | params: assign({}, params) 1358 | }, options$$1, action); 1359 | 1360 | resource[name] = function () { 1361 | return (self.$http || Http)(opts(action, arguments)); 1362 | }; 1363 | }); 1364 | return resource; 1365 | } 1366 | 1367 | function opts(action, args) { 1368 | var options$$1 = assign({}, action), 1369 | params = {}, 1370 | body; 1371 | 1372 | switch (args.length) { 1373 | case 2: 1374 | params = args[0]; 1375 | body = args[1]; 1376 | break; 1377 | 1378 | case 1: 1379 | if (/^(POST|PUT|PATCH)$/i.test(options$$1.method)) { 1380 | body = args[0]; 1381 | } else { 1382 | params = args[0]; 1383 | } 1384 | 1385 | break; 1386 | 1387 | case 0: 1388 | break; 1389 | 1390 | default: 1391 | throw 'Expected up to 2 arguments [params, body], got ' + args.length + ' arguments'; 1392 | } 1393 | 1394 | options$$1.body = body; 1395 | options$$1.params = assign({}, options$$1.params, params); 1396 | return options$$1; 1397 | } 1398 | 1399 | Resource.actions = { 1400 | get: { 1401 | method: 'GET' 1402 | }, 1403 | save: { 1404 | method: 'POST' 1405 | }, 1406 | query: { 1407 | method: 'GET' 1408 | }, 1409 | update: { 1410 | method: 'PUT' 1411 | }, 1412 | remove: { 1413 | method: 'DELETE' 1414 | }, 1415 | "delete": { 1416 | method: 'DELETE' 1417 | } 1418 | }; 1419 | 1420 | /** 1421 | * Install plugin. 1422 | */ 1423 | 1424 | function plugin(Vue) { 1425 | if (plugin.installed) { 1426 | return; 1427 | } 1428 | 1429 | Util(Vue); 1430 | Vue.url = Url; 1431 | Vue.http = Http; 1432 | Vue.resource = Resource; 1433 | Vue.Promise = PromiseObj; 1434 | Object.defineProperties(Vue.prototype, { 1435 | $url: { 1436 | get: function get() { 1437 | return options(Vue.url, this, this.$options.url); 1438 | } 1439 | }, 1440 | $http: { 1441 | get: function get() { 1442 | return options(Vue.http, this, this.$options.http); 1443 | } 1444 | }, 1445 | $resource: { 1446 | get: function get() { 1447 | return Vue.resource.bind(this); 1448 | } 1449 | }, 1450 | $promise: { 1451 | get: function get() { 1452 | var _this = this; 1453 | 1454 | return function (executor) { 1455 | return new Vue.Promise(executor, _this); 1456 | }; 1457 | } 1458 | } 1459 | }); 1460 | } 1461 | 1462 | if (typeof window !== 'undefined' && window.Vue && !window.Vue.resource) { 1463 | window.Vue.use(plugin); 1464 | } 1465 | 1466 | export default plugin; 1467 | export { Url, Http, Resource }; 1468 | -------------------------------------------------------------------------------- /dist/vue-resource.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-resource v1.5.3 3 | * https://github.com/pagekit/vue-resource 4 | * Released under the MIT License. 5 | */ 6 | 7 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueResource=e()}(this,function(){"use strict";function s(t){this.state=2,this.value=void 0,this.deferred=[];var e=this;try{t(function(t){e.resolve(t)},function(t){e.reject(t)})}catch(t){e.reject(t)}}s.reject=function(n){return new s(function(t,e){e(n)})},s.resolve=function(n){return new s(function(t,e){t(n)})},s.all=function(i){return new s(function(n,t){var o=0,r=[];0===i.length&&n(r);for(var e=0;e { 13 | // success callback 14 | }, response => { 15 | // error callback 16 | }); 17 | } 18 | ``` 19 | 20 | ## Methods 21 | 22 | Shortcut methods are available for all request types. These methods work globally or in a Vue instance. 23 | 24 | ```js 25 | // global Vue object 26 | Vue.http.get('/someUrl', [config]).then(successCallback, errorCallback); 27 | Vue.http.post('/someUrl', [body], [config]).then(successCallback, errorCallback); 28 | 29 | // in a Vue instance 30 | this.$http.get('/someUrl', [config]).then(successCallback, errorCallback); 31 | this.$http.post('/someUrl', [body], [config]).then(successCallback, errorCallback); 32 | ``` 33 | List of shortcut methods: 34 | 35 | * `get(url, [config])` 36 | * `head(url, [config])` 37 | * `delete(url, [config])` 38 | * `jsonp(url, [config])` 39 | * `post(url, [body], [config])` 40 | * `put(url, [body], [config])` 41 | * `patch(url, [body], [config])` 42 | 43 | ## Config 44 | 45 | Parameter | Type | Description 46 | --------- | ---- | ----------- 47 | url | `string` | URL to which the request is sent 48 | body | `Object`, `FormData`, `string` | Data to be sent as the request body 49 | headers | `Object` | Headers object to be sent as HTTP request headers 50 | params | `Object` | Parameters object to be sent as URL parameters 51 | method | `string` | HTTP method (e.g. GET, POST, ...) 52 | responseType | `string` | Type of the response body (e.g. text, blob, json, ...) 53 | timeout | `number` | Request timeout in milliseconds (`0` means no timeout) 54 | credentials | `boolean` | Indicates whether or not cross-site Access-Control requests should be made using credentials 55 | emulateHTTP | `boolean` | Send PUT, PATCH and DELETE requests with a HTTP POST and set the `X-HTTP-Method-Override` header 56 | emulateJSON | `boolean` | Send request body as `application/x-www-form-urlencoded` content type 57 | before | `function(request)` | Callback function to modify the request object before it is sent 58 | uploadProgress | `function(event)` | Callback function to handle the [ProgressEvent](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent) of uploads 59 | downloadProgress | `function(event)` | Callback function to handle the [ProgressEvent](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent) of downloads 60 | 61 | ## Response 62 | 63 | A request resolves to a response object with the following properties and methods: 64 | 65 | Property | Type | Description 66 | -------- | ---- | ----------- 67 | url | `string` | Response URL origin 68 | body | `Object`, `Blob`, `string` | Response body 69 | headers | `Header` | Response Headers object 70 | ok | `boolean` | HTTP status code between 200 and 299 71 | status | `number` | HTTP status code of the response 72 | statusText | `string` | HTTP status text of the response 73 | **Method** | **Type** | **Description** 74 | text() | `Promise` | Resolves the body as string 75 | json() | `Promise` | Resolves the body as parsed JSON object 76 | blob() | `Promise` | Resolves the body as Blob object 77 | 78 | ## Example 79 | 80 | ```js 81 | { 82 | // POST /someUrl 83 | this.$http.post('/someUrl', {foo: 'bar'}).then(response => { 84 | 85 | // get status 86 | response.status; 87 | 88 | // get status text 89 | response.statusText; 90 | 91 | // get 'Expires' header 92 | response.headers.get('Expires'); 93 | 94 | // get body data 95 | this.someData = response.body; 96 | 97 | }, response => { 98 | // error callback 99 | }); 100 | } 101 | ``` 102 | 103 | Send a get request with URL query parameters and a custom headers. 104 | 105 | ```js 106 | { 107 | // GET /someUrl?foo=bar 108 | this.$http.get('/someUrl', {params: {foo: 'bar'}, headers: {'X-Custom': '...'}}).then(response => { 109 | // success callback 110 | }, response => { 111 | // error callback 112 | }); 113 | } 114 | ``` 115 | 116 | Fetch an image and use the blob() method to extract the image body content from the response. 117 | 118 | ```js 119 | { 120 | // GET /image.jpg 121 | this.$http.get('/image.jpg', {responseType: 'blob'}).then(response => { 122 | 123 | // resolve to Blob 124 | return response.blob(); 125 | 126 | }).then(blob => { 127 | // use image Blob 128 | }); 129 | } 130 | ``` 131 | 132 | ## Interceptors 133 | 134 | Interceptors can be defined globally and are used for pre- and postprocessing of a request. If a request is sent using `this.$http` or `this.$resource` the current Vue instance is available as `this` in a interceptor callback. 135 | 136 | ### Request processing 137 | ```js 138 | Vue.http.interceptors.push(function(request) { 139 | 140 | // modify method 141 | request.method = 'POST'; 142 | 143 | // modify headers 144 | request.headers.set('X-CSRF-TOKEN', 'TOKEN'); 145 | request.headers.set('Authorization', 'Bearer TOKEN'); 146 | 147 | }); 148 | ``` 149 | 150 | ### Request and Response processing 151 | ```js 152 | Vue.http.interceptors.push(function(request) { 153 | 154 | // modify request 155 | request.method = 'POST'; 156 | 157 | // return response callback 158 | return function(response) { 159 | 160 | // modify response 161 | response.body = '...'; 162 | 163 | }; 164 | }); 165 | ``` 166 | 167 | ### Return a Response and stop processing 168 | ```js 169 | Vue.http.interceptors.push(function(request) { 170 | 171 | // modify request ... 172 | 173 | // stop and return response 174 | return request.respondWith(body, { 175 | status: 404, 176 | statusText: 'Not found' 177 | }); 178 | }); 179 | ``` 180 | 181 | ### Overriding default interceptors 182 | 183 | All default interceptors callbacks can be overriden to change their behavior. All interceptors are exposed through the `Vue.http.interceptor` object with their names `before`, `method`, `jsonp`, `json`, `form`, `header` and `cors`. 184 | 185 | ```js 186 | Vue.http.interceptor.before = function(request) { 187 | 188 | // override before interceptor 189 | 190 | }; 191 | -------------------------------------------------------------------------------- /docs/recipes.md: -------------------------------------------------------------------------------- 1 | # Code Recipes 2 | 3 | The Recipes provide code examples to common use-cases. If you want to share your recipe feel free to send a [pull request](https://github.com/pagekit/vue-resource/pulls). 4 | 5 | ## Forms 6 | 7 | Sending forms using [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData). 8 | 9 | ```js 10 | { 11 | var formData = new FormData(); 12 | 13 | // append string 14 | formData.append('foo', 'bar'); 15 | 16 | // append Blob/File object 17 | formData.append('pic', fileInput, 'mypic.jpg'); 18 | 19 | // POST /someUrl 20 | this.$http.post('/someUrl', formData).then(response => { 21 | // success callback 22 | }, response => { 23 | // error callback 24 | }); 25 | } 26 | ``` 27 | 28 | ## Abort a request 29 | 30 | Abort a previous request when a new request is about to be sent. For example when typing in a autocomplete input. 31 | 32 | ```js 33 | { 34 | // GET /someUrl 35 | this.$http.get('/someUrl', { 36 | 37 | // use before callback 38 | before(request) { 39 | 40 | // abort previous request, if exists 41 | if (this.previousRequest) { 42 | this.previousRequest.abort(); 43 | } 44 | 45 | // set previous request on Vue instance 46 | this.previousRequest = request; 47 | } 48 | 49 | }).then(response => { 50 | // success callback 51 | }, response => { 52 | // error callback 53 | }); 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/resource.md: -------------------------------------------------------------------------------- 1 | # Resource 2 | 3 | The resource service can be used globally `Vue.resource` or in a Vue instance `this.$resource`. 4 | 5 | ## Methods 6 | 7 | * `resource(url, [params], [actions], [options])` 8 | 9 | ## Default Actions 10 | 11 | ```js 12 | get: {method: 'GET'}, 13 | save: {method: 'POST'}, 14 | query: {method: 'GET'}, 15 | update: {method: 'PUT'}, 16 | remove: {method: 'DELETE'}, 17 | delete: {method: 'DELETE'} 18 | ``` 19 | 20 | ## Example 21 | 22 | ```js 23 | { 24 | var resource = this.$resource('someItem{/id}'); 25 | 26 | // GET someItem/1 27 | resource.get({id: 1}).then(response => { 28 | this.item = response.body; 29 | }); 30 | 31 | // POST someItem/1 32 | resource.save({id: 1}, {item: this.item}).then(response => { 33 | // success callback 34 | }, response => { 35 | // error callback 36 | }); 37 | 38 | // DELETE someItem/1 39 | resource.delete({id: 1}).then(response => { 40 | // success callback 41 | }, response => { 42 | // error callback 43 | }); 44 | } 45 | ``` 46 | 47 | ## Custom Actions 48 | 49 | ```js 50 | { 51 | var customActions = { 52 | foo: {method: 'GET', url: 'someItem/foo{/id}'}, 53 | bar: {method: 'POST', url: 'someItem/bar{/id}'} 54 | } 55 | 56 | var resource = this.$resource('someItem{/id}', {}, customActions); 57 | 58 | // GET someItem/foo/1 59 | resource.foo({id: 1}).then(response => { 60 | this.item = response.body; 61 | }); 62 | 63 | // POST someItem/bar/1 64 | resource.bar({id: 1}, {item: this.item}).then(response => { 65 | // success callback 66 | }, response => { 67 | // error callback 68 | }); 69 | } 70 | ``` 71 | 72 | **Note:** When passing only one single object (for POST, PUT and PATCH custom actions), it will defaults to body param. If you need set url params you will have to pass an empty object as second argument. 73 | 74 | ```js 75 | { 76 | var resource = this.$resource('someItem{/id}', {}, { 77 | baz: {method: 'POST', url: 'someItem/baz{/id}'} 78 | }); 79 | 80 | // POST someItem/baz 81 | resource.baz({id: 1}).then(response => { 82 | // success callback 83 | }, response => { 84 | // error callback 85 | }); 86 | 87 | // POST someItem/baz/1 88 | resource.baz({id: 1}, {}).then(response => { 89 | // success callback 90 | }, response => { 91 | // error callback 92 | }); 93 | ``` 94 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-resource", 3 | "version": "1.5.3", 4 | "main": "dist/vue-resource.common.js", 5 | "module": "dist/vue-resource.esm.js", 6 | "unpkg": "dist/vue-resource.min.js", 7 | "jsdelivr": "dist/vue-resource.min.js", 8 | "typings": "types/index.d.ts", 9 | "description": "The HTTP client for Vue.js", 10 | "homepage": "https://github.com/pagekit/vue-resource", 11 | "license": "MIT", 12 | "keywords": [ 13 | "vue", 14 | "xhr", 15 | "http", 16 | "ajax" 17 | ], 18 | "bugs": { 19 | "url": "https://github.com/pagekit/vue-resource/issues" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/pagekit/vue-resource.git" 24 | }, 25 | "scripts": { 26 | "up": "yarn upgrade-interactive --latest", 27 | "test": "jest --env=node", 28 | "karma": "karma start test/karma.conf.js --single-run", 29 | "build": "node build/build.js", 30 | "release": "node build/release.js", 31 | "webpack": "webpack --config test/webpack.config.js" 32 | }, 33 | "browser": { 34 | "got": false 35 | }, 36 | "dependencies": { 37 | "got": ">=8.0 <12.0" 38 | }, 39 | "devDependencies": { 40 | "@babel/core": "^7.2.2", 41 | "@babel/preset-env": "^7.2.0", 42 | "babel-loader": "^8.0.4", 43 | "eslint": "^5.11.1", 44 | "generate-release": "^1.1.1", 45 | "jasmine": "^3.3.1", 46 | "jasmine-core": "^3.3.0", 47 | "jest": "^23.6.0", 48 | "karma": "^3.1.4", 49 | "karma-chrome-launcher": "^2.2.0", 50 | "karma-firefox-launcher": "^1.1.0", 51 | "karma-jasmine": "^2.0.1", 52 | "karma-safari-launcher": "^1.0.0", 53 | "karma-webpack": "^3.0.5", 54 | "replace-in-file": "^3.4.2", 55 | "rollup": "^0.66.0", 56 | "rollup-plugin-babel": "^4.1.0", 57 | "rollup-plugin-replace": "^2.1.0", 58 | "uglify-js": "^3.4.9", 59 | "vue": "^2.5.21", 60 | "webpack": "^4.28.3", 61 | "webpack-cli": "^3.1.2" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/http/client/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base client. 3 | */ 4 | 5 | import Promise from '../../promise'; 6 | import xhrClient from './xhr'; 7 | import nodeClient from './node'; 8 | import {warn, when, isObject, isFunction, inBrowser} from '../../util'; 9 | 10 | export default function (context) { 11 | 12 | const reqHandlers = [sendRequest], resHandlers = []; 13 | 14 | if (!isObject(context)) { 15 | context = null; 16 | } 17 | 18 | function Client(request) { 19 | while (reqHandlers.length) { 20 | 21 | const handler = reqHandlers.pop(); 22 | 23 | if (isFunction(handler)) { 24 | 25 | let response, next; 26 | 27 | response = handler.call(context, request, val => next = val) || next; 28 | 29 | if (isObject(response)) { 30 | return new Promise((resolve, reject) => { 31 | 32 | resHandlers.forEach(handler => { 33 | response = when(response, response => { 34 | return handler.call(context, response) || response; 35 | }, reject); 36 | }); 37 | 38 | when(response, resolve, reject); 39 | 40 | }, context); 41 | } 42 | 43 | if (isFunction(response)) { 44 | resHandlers.unshift(response); 45 | } 46 | 47 | } else { 48 | warn(`Invalid interceptor of type ${typeof handler}, must be a function`); 49 | } 50 | } 51 | } 52 | 53 | Client.use = handler => { 54 | reqHandlers.push(handler); 55 | }; 56 | 57 | return Client; 58 | } 59 | 60 | function sendRequest(request) { 61 | 62 | const client = request.client || (inBrowser ? xhrClient : nodeClient); 63 | 64 | return client(request); 65 | } 66 | -------------------------------------------------------------------------------- /src/http/client/jsonp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSONP client (Browser). 3 | */ 4 | 5 | import Promise from '../../promise'; 6 | 7 | export default function (request) { 8 | return new Promise(resolve => { 9 | 10 | var name = request.jsonp || 'callback', callback = request.jsonpCallback || '_jsonp' + Math.random().toString(36).substr(2), body = null, handler, script; 11 | 12 | handler = ({type}) => { 13 | 14 | var status = 0; 15 | 16 | if (type === 'load' && body !== null) { 17 | status = 200; 18 | } else if (type === 'error') { 19 | status = 500; 20 | } 21 | 22 | if (status && window[callback]) { 23 | delete window[callback]; 24 | document.body.removeChild(script); 25 | } 26 | 27 | resolve(request.respondWith(body, {status})); 28 | }; 29 | 30 | window[callback] = result => { 31 | body = JSON.stringify(result); 32 | }; 33 | 34 | request.abort = () => { 35 | handler({type: 'abort'}); 36 | }; 37 | 38 | request.params[name] = callback; 39 | 40 | if (request.timeout) { 41 | setTimeout(request.abort, request.timeout); 42 | } 43 | 44 | script = document.createElement('script'); 45 | script.src = request.getUrl(); 46 | script.type = 'text/javascript'; 47 | script.async = true; 48 | script.onload = handler; 49 | script.onerror = handler; 50 | 51 | document.body.appendChild(script); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /src/http/client/node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Http client (Node). 3 | */ 4 | 5 | import Promise from '../../promise'; 6 | import {each, trim} from '../../util'; 7 | 8 | export default function (request) { 9 | 10 | const client = require('got'); 11 | 12 | return new Promise(resolve => { 13 | 14 | var url = request.getUrl(); 15 | var body = request.getBody(); 16 | var method = request.method; 17 | var headers = {}, handler; 18 | 19 | request.headers.forEach((value, name) => { 20 | headers[name] = value; 21 | }); 22 | 23 | client(url, {body, method, headers}).then(handler = (resp) => { 24 | 25 | var response = request.respondWith(resp.body, { 26 | status: resp.statusCode, 27 | statusText: trim(resp.statusMessage) 28 | }); 29 | 30 | each(resp.headers, (value, name) => { 31 | response.headers.set(name, value); 32 | }); 33 | 34 | resolve(response); 35 | 36 | }, error => handler(error.response)); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/http/client/xdr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * XDomain client (Internet Explorer). 3 | */ 4 | 5 | import Promise from '../../promise'; 6 | 7 | export default function (request) { 8 | return new Promise(resolve => { 9 | 10 | var xdr = new XDomainRequest(), handler = ({type}) => { 11 | 12 | var status = 0; 13 | 14 | if (type === 'load') { 15 | status = 200; 16 | } else if (type === 'error') { 17 | status = 500; 18 | } 19 | 20 | resolve(request.respondWith(xdr.responseText, {status})); 21 | }; 22 | 23 | request.abort = () => xdr.abort(); 24 | 25 | xdr.open(request.method, request.getUrl()); 26 | 27 | if (request.timeout) { 28 | xdr.timeout = request.timeout; 29 | } 30 | 31 | xdr.onload = handler; 32 | xdr.onabort = handler; 33 | xdr.onerror = handler; 34 | xdr.ontimeout = handler; 35 | xdr.onprogress = () => {}; 36 | xdr.send(request.getBody()); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/http/client/xhr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * XMLHttp client (Browser). 3 | */ 4 | 5 | import Promise from '../../promise'; 6 | import {each, trim, isFunction} from '../../util'; 7 | 8 | export default function (request) { 9 | return new Promise(resolve => { 10 | 11 | var xhr = new XMLHttpRequest(), handler = (event) => { 12 | 13 | var response = request.respondWith( 14 | 'response' in xhr ? xhr.response : xhr.responseText, { 15 | status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug 16 | statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) 17 | }); 18 | 19 | each(trim(xhr.getAllResponseHeaders()).split('\n'), row => { 20 | response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); 21 | }); 22 | 23 | resolve(response); 24 | }; 25 | 26 | request.abort = () => xhr.abort(); 27 | 28 | xhr.open(request.method, request.getUrl(), true); 29 | 30 | if (request.timeout) { 31 | xhr.timeout = request.timeout; 32 | } 33 | 34 | if (request.responseType && 'responseType' in xhr) { 35 | xhr.responseType = request.responseType; 36 | } 37 | 38 | if (request.withCredentials || request.credentials) { 39 | xhr.withCredentials = true; 40 | } 41 | 42 | if (!request.crossOrigin) { 43 | request.headers.set('X-Requested-With', 'XMLHttpRequest'); 44 | } 45 | 46 | // deprecated use downloadProgress 47 | if (isFunction(request.progress) && request.method === 'GET') { 48 | xhr.addEventListener('progress', request.progress); 49 | } 50 | 51 | if (isFunction(request.downloadProgress)) { 52 | xhr.addEventListener('progress', request.downloadProgress); 53 | } 54 | 55 | // deprecated use uploadProgress 56 | if (isFunction(request.progress) && /^(POST|PUT)$/i.test(request.method)) { 57 | xhr.upload.addEventListener('progress', request.progress); 58 | } 59 | 60 | if (isFunction(request.uploadProgress) && xhr.upload) { 61 | xhr.upload.addEventListener('progress', request.uploadProgress); 62 | } 63 | 64 | request.headers.forEach((value, name) => { 65 | xhr.setRequestHeader(name, value); 66 | }); 67 | 68 | xhr.onload = handler; 69 | xhr.onabort = handler; 70 | xhr.onerror = handler; 71 | xhr.ontimeout = handler; 72 | xhr.send(request.getBody()); 73 | }); 74 | } 75 | -------------------------------------------------------------------------------- /src/http/headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTTP Headers. 3 | */ 4 | 5 | import {each, trim, toLower} from '../util'; 6 | 7 | export default class Headers { 8 | 9 | constructor(headers) { 10 | 11 | this.map = {}; 12 | 13 | each(headers, (value, name) => this.append(name, value)); 14 | } 15 | 16 | has(name) { 17 | return getName(this.map, name) !== null; 18 | } 19 | 20 | get(name) { 21 | 22 | var list = this.map[getName(this.map, name)]; 23 | 24 | return list ? list.join() : null; 25 | } 26 | 27 | getAll(name) { 28 | return this.map[getName(this.map, name)] || []; 29 | } 30 | 31 | set(name, value) { 32 | this.map[normalizeName(getName(this.map, name) || name)] = [trim(value)]; 33 | } 34 | 35 | append(name, value) { 36 | 37 | var list = this.map[getName(this.map, name)]; 38 | 39 | if (list) { 40 | list.push(trim(value)); 41 | } else { 42 | this.set(name, value); 43 | } 44 | } 45 | 46 | delete(name) { 47 | delete this.map[getName(this.map, name)]; 48 | } 49 | 50 | deleteAll() { 51 | this.map = {}; 52 | } 53 | 54 | forEach(callback, thisArg) { 55 | each(this.map, (list, name) => { 56 | each(list, value => callback.call(thisArg, value, name, this)); 57 | }); 58 | } 59 | 60 | } 61 | 62 | function getName(map, name) { 63 | return Object.keys(map).reduce((prev, curr) => { 64 | return toLower(name) === toLower(curr) ? curr : prev; 65 | }, null); 66 | } 67 | 68 | function normalizeName(name) { 69 | 70 | if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) { 71 | throw new TypeError('Invalid character in header field name'); 72 | } 73 | 74 | return trim(name); 75 | } 76 | -------------------------------------------------------------------------------- /src/http/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service for sending network requests. 3 | */ 4 | 5 | const COMMON_HEADERS = {'Accept': 'application/json, text/plain, */*'}; 6 | const JSON_CONTENT_TYPE = {'Content-Type': 'application/json;charset=utf-8'}; 7 | 8 | import cors from './interceptor/cors'; 9 | import form from './interceptor/form'; 10 | import json from './interceptor/json'; 11 | import jsonp from './interceptor/jsonp'; 12 | import before from './interceptor/before'; 13 | import method from './interceptor/method'; 14 | import header from './interceptor/header'; 15 | import Client from './client/index'; 16 | import Request from './request'; 17 | import Promise from '../promise'; 18 | import {assign, defaults, error, isString, isFunction} from '../util'; 19 | 20 | export default function Http(options) { 21 | 22 | var self = this || {}, client = Client(self.$vm); 23 | 24 | defaults(options || {}, self.$options, Http.options); 25 | 26 | Http.interceptors.forEach(handler => { 27 | 28 | if (isString(handler)) { 29 | handler = Http.interceptor[handler]; 30 | } 31 | 32 | if (isFunction(handler)) { 33 | client.use(handler); 34 | } 35 | 36 | }); 37 | 38 | return client(new Request(options)).then(response => { 39 | 40 | return response.ok ? response : Promise.reject(response); 41 | 42 | }, response => { 43 | 44 | if (response instanceof Error) { 45 | error(response); 46 | } 47 | 48 | return Promise.reject(response); 49 | }); 50 | } 51 | 52 | Http.options = {}; 53 | 54 | Http.headers = { 55 | put: JSON_CONTENT_TYPE, 56 | post: JSON_CONTENT_TYPE, 57 | patch: JSON_CONTENT_TYPE, 58 | delete: JSON_CONTENT_TYPE, 59 | common: COMMON_HEADERS, 60 | custom: {} 61 | }; 62 | 63 | Http.interceptor = {before, method, jsonp, json, form, header, cors}; 64 | Http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors']; 65 | 66 | ['get', 'delete', 'head', 'jsonp'].forEach(method => { 67 | 68 | Http[method] = function (url, options) { 69 | return this(assign(options || {}, {url, method})); 70 | }; 71 | 72 | }); 73 | 74 | ['post', 'put', 'patch'].forEach(method => { 75 | 76 | Http[method] = function (url, body, options) { 77 | return this(assign(options || {}, {url, method, body})); 78 | }; 79 | 80 | }); 81 | -------------------------------------------------------------------------------- /src/http/interceptor/before.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Before Interceptor. 3 | */ 4 | 5 | import {isFunction} from '../../util'; 6 | 7 | export default function (request) { 8 | 9 | if (isFunction(request.before)) { 10 | request.before.call(this, request); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/http/interceptor/cors.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CORS Interceptor. 3 | */ 4 | 5 | import Url from '../../url/index'; 6 | import xdrClient from '../client/xdr'; 7 | import {inBrowser} from '../../util'; 8 | 9 | const SUPPORTS_CORS = inBrowser && 'withCredentials' in new XMLHttpRequest(); 10 | 11 | export default function (request) { 12 | 13 | if (inBrowser) { 14 | 15 | const orgUrl = Url.parse(location.href); 16 | const reqUrl = Url.parse(request.getUrl()); 17 | 18 | if (reqUrl.protocol !== orgUrl.protocol || reqUrl.host !== orgUrl.host) { 19 | 20 | request.crossOrigin = true; 21 | request.emulateHTTP = false; 22 | 23 | if (!SUPPORTS_CORS) { 24 | request.client = xdrClient; 25 | } 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/http/interceptor/form.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Form data Interceptor. 3 | */ 4 | 5 | import Url from '../../url/index'; 6 | import {isObject, isFormData} from '../../util'; 7 | 8 | export default function (request) { 9 | 10 | if (isFormData(request.body)) { 11 | request.headers.delete('Content-Type'); 12 | } else if (isObject(request.body) && request.emulateJSON) { 13 | request.body = Url.params(request.body); 14 | request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/http/interceptor/header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Header Interceptor. 3 | */ 4 | 5 | import Http from '../index'; 6 | import {assign, each, toLower} from '../../util'; 7 | 8 | export default function (request) { 9 | 10 | const headers = assign({}, Http.headers.common, 11 | !request.crossOrigin ? Http.headers.custom : {}, 12 | Http.headers[toLower(request.method)] 13 | ); 14 | 15 | each(headers, (value, name) => { 16 | if (!request.headers.has(name)) { 17 | request.headers.set(name, value); 18 | } 19 | }); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/http/interceptor/json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSON Interceptor. 3 | */ 4 | 5 | import {when, isObject} from '../../util'; 6 | 7 | export default function (request) { 8 | 9 | const type = request.headers.get('Content-Type') || ''; 10 | 11 | if (isObject(request.body) && type.indexOf('application/json') === 0) { 12 | request.body = JSON.stringify(request.body); 13 | } 14 | 15 | return response => { 16 | 17 | return response.bodyText ? when(response.text(), text => { 18 | 19 | const type = response.headers.get('Content-Type') || ''; 20 | 21 | if (type.indexOf('application/json') === 0 || isJson(text)) { 22 | 23 | try { 24 | response.body = JSON.parse(text); 25 | } catch (e) { 26 | response.body = null; 27 | } 28 | 29 | } else { 30 | response.body = text; 31 | } 32 | 33 | return response; 34 | 35 | }) : response; 36 | 37 | }; 38 | } 39 | 40 | function isJson(str) { 41 | 42 | const start = str.match(/^\s*(\[|\{)/); 43 | const end = {'[': /]\s*$/, '{': /}\s*$/}; 44 | 45 | return start && end[start[1]].test(str); 46 | } 47 | -------------------------------------------------------------------------------- /src/http/interceptor/jsonp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSONP Interceptor. 3 | */ 4 | 5 | import jsonpClient from '../client/jsonp'; 6 | 7 | export default function (request) { 8 | 9 | if (request.method == 'JSONP') { 10 | request.client = jsonpClient; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/http/interceptor/method.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTTP method override Interceptor. 3 | */ 4 | 5 | export default function (request) { 6 | 7 | if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { 8 | request.headers.set('X-HTTP-Method-Override', request.method); 9 | request.method = 'POST'; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/http/request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTTP Request. 3 | */ 4 | 5 | import Url from '../url/index'; 6 | import Headers from './headers'; 7 | import Response from './response'; 8 | import {assign, toUpper} from '../util'; 9 | 10 | export default class Request { 11 | 12 | constructor(options) { 13 | 14 | this.body = null; 15 | this.params = {}; 16 | 17 | assign(this, options, { 18 | method: toUpper(options.method || 'GET') 19 | }); 20 | 21 | if (!(this.headers instanceof Headers)) { 22 | this.headers = new Headers(this.headers); 23 | } 24 | } 25 | 26 | getUrl() { 27 | return Url(this); 28 | } 29 | 30 | getBody() { 31 | return this.body; 32 | } 33 | 34 | respondWith(body, options) { 35 | return new Response(body, assign(options || {}, {url: this.getUrl()})); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/http/response.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTTP Response. 3 | */ 4 | 5 | import Headers from './headers'; 6 | import Promise from '../promise'; 7 | import {when, isBlob, isString} from '../util'; 8 | 9 | export default class Response { 10 | 11 | constructor(body, {url, headers, status, statusText}) { 12 | 13 | this.url = url; 14 | this.ok = status >= 200 && status < 300; 15 | this.status = status || 0; 16 | this.statusText = statusText || ''; 17 | this.headers = new Headers(headers); 18 | this.body = body; 19 | 20 | if (isString(body)) { 21 | 22 | this.bodyText = body; 23 | 24 | } else if (isBlob(body)) { 25 | 26 | this.bodyBlob = body; 27 | 28 | if (isBlobText(body)) { 29 | this.bodyText = blobText(body); 30 | } 31 | } 32 | } 33 | 34 | blob() { 35 | return when(this.bodyBlob); 36 | } 37 | 38 | text() { 39 | return when(this.bodyText); 40 | } 41 | 42 | json() { 43 | return when(this.text(), text => JSON.parse(text)); 44 | } 45 | 46 | } 47 | 48 | Object.defineProperty(Response.prototype, 'data', { 49 | 50 | get() { 51 | return this.body; 52 | }, 53 | 54 | set(body) { 55 | this.body = body; 56 | } 57 | 58 | }); 59 | 60 | function blobText(body) { 61 | return new Promise((resolve) => { 62 | 63 | var reader = new FileReader(); 64 | 65 | reader.readAsText(body); 66 | reader.onload = () => { 67 | resolve(reader.result); 68 | }; 69 | 70 | }); 71 | } 72 | 73 | function isBlobText(body) { 74 | return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; 75 | } 76 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Install plugin. 3 | */ 4 | 5 | import Url from './url/index'; 6 | import Http from './http/index'; 7 | import Promise from './promise'; 8 | import Resource from './resource'; 9 | import Util, {options} from './util'; 10 | 11 | function plugin(Vue) { 12 | 13 | if (plugin.installed) { 14 | return; 15 | } 16 | 17 | Util(Vue); 18 | 19 | Vue.url = Url; 20 | Vue.http = Http; 21 | Vue.resource = Resource; 22 | Vue.Promise = Promise; 23 | 24 | Object.defineProperties(Vue.prototype, { 25 | 26 | $url: { 27 | get() { 28 | return options(Vue.url, this, this.$options.url); 29 | } 30 | }, 31 | 32 | $http: { 33 | get() { 34 | return options(Vue.http, this, this.$options.http); 35 | } 36 | }, 37 | 38 | $resource: { 39 | get() { 40 | return Vue.resource.bind(this); 41 | } 42 | }, 43 | 44 | $promise: { 45 | get() { 46 | return (executor) => new Vue.Promise(executor, this); 47 | } 48 | } 49 | 50 | }); 51 | } 52 | 53 | if (typeof window !== 'undefined' && window.Vue && !window.Vue.resource) { 54 | window.Vue.use(plugin); 55 | } 56 | 57 | export default plugin; 58 | -------------------------------------------------------------------------------- /src/lib/promise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) 3 | */ 4 | 5 | const RESOLVED = 0; 6 | const REJECTED = 1; 7 | const PENDING = 2; 8 | 9 | import {nextTick} from '../util'; 10 | 11 | export default function Promise(executor) { 12 | 13 | this.state = PENDING; 14 | this.value = undefined; 15 | this.deferred = []; 16 | 17 | var promise = this; 18 | 19 | try { 20 | executor(function (x) { 21 | promise.resolve(x); 22 | }, function (r) { 23 | promise.reject(r); 24 | }); 25 | } catch (e) { 26 | promise.reject(e); 27 | } 28 | } 29 | 30 | Promise.reject = function (r) { 31 | return new Promise(function (resolve, reject) { 32 | reject(r); 33 | }); 34 | }; 35 | 36 | Promise.resolve = function (x) { 37 | return new Promise(function (resolve, reject) { 38 | resolve(x); 39 | }); 40 | }; 41 | 42 | Promise.all = function all(iterable) { 43 | return new Promise(function (resolve, reject) { 44 | var count = 0, result = []; 45 | 46 | if (iterable.length === 0) { 47 | resolve(result); 48 | } 49 | 50 | function resolver(i) { 51 | return function (x) { 52 | result[i] = x; 53 | count += 1; 54 | 55 | if (count === iterable.length) { 56 | resolve(result); 57 | } 58 | }; 59 | } 60 | 61 | for (var i = 0; i < iterable.length; i += 1) { 62 | Promise.resolve(iterable[i]).then(resolver(i), reject); 63 | } 64 | }); 65 | }; 66 | 67 | Promise.race = function race(iterable) { 68 | return new Promise(function (resolve, reject) { 69 | for (var i = 0; i < iterable.length; i += 1) { 70 | Promise.resolve(iterable[i]).then(resolve, reject); 71 | } 72 | }); 73 | }; 74 | 75 | var p = Promise.prototype; 76 | 77 | p.resolve = function resolve(x) { 78 | var promise = this; 79 | 80 | if (promise.state === PENDING) { 81 | if (x === promise) { 82 | throw new TypeError('Promise settled with itself.'); 83 | } 84 | 85 | var called = false; 86 | 87 | try { 88 | var then = x && x['then']; 89 | 90 | if (x !== null && typeof x === 'object' && typeof then === 'function') { 91 | then.call(x, function (x) { 92 | if (!called) { 93 | promise.resolve(x); 94 | } 95 | called = true; 96 | 97 | }, function (r) { 98 | if (!called) { 99 | promise.reject(r); 100 | } 101 | called = true; 102 | }); 103 | return; 104 | } 105 | } catch (e) { 106 | if (!called) { 107 | promise.reject(e); 108 | } 109 | return; 110 | } 111 | 112 | promise.state = RESOLVED; 113 | promise.value = x; 114 | promise.notify(); 115 | } 116 | }; 117 | 118 | p.reject = function reject(reason) { 119 | var promise = this; 120 | 121 | if (promise.state === PENDING) { 122 | if (reason === promise) { 123 | throw new TypeError('Promise settled with itself.'); 124 | } 125 | 126 | promise.state = REJECTED; 127 | promise.value = reason; 128 | promise.notify(); 129 | } 130 | }; 131 | 132 | p.notify = function notify() { 133 | var promise = this; 134 | 135 | nextTick(function () { 136 | if (promise.state !== PENDING) { 137 | while (promise.deferred.length) { 138 | var deferred = promise.deferred.shift(), 139 | onResolved = deferred[0], 140 | onRejected = deferred[1], 141 | resolve = deferred[2], 142 | reject = deferred[3]; 143 | 144 | try { 145 | if (promise.state === RESOLVED) { 146 | if (typeof onResolved === 'function') { 147 | resolve(onResolved.call(undefined, promise.value)); 148 | } else { 149 | resolve(promise.value); 150 | } 151 | } else if (promise.state === REJECTED) { 152 | if (typeof onRejected === 'function') { 153 | resolve(onRejected.call(undefined, promise.value)); 154 | } else { 155 | reject(promise.value); 156 | } 157 | } 158 | } catch (e) { 159 | reject(e); 160 | } 161 | } 162 | } 163 | }); 164 | }; 165 | 166 | p.then = function then(onResolved, onRejected) { 167 | var promise = this; 168 | 169 | return new Promise(function (resolve, reject) { 170 | promise.deferred.push([onResolved, onRejected, resolve, reject]); 171 | promise.notify(); 172 | }); 173 | }; 174 | 175 | p.catch = function (onRejected) { 176 | return this.then(undefined, onRejected); 177 | }; 178 | -------------------------------------------------------------------------------- /src/lib/url-template.js: -------------------------------------------------------------------------------- 1 | /** 2 | * URL Template v2.0.6 (https://github.com/bramstein/url-template) 3 | */ 4 | 5 | export function expand(url, params, variables) { 6 | 7 | var tmpl = parse(url), expanded = tmpl.expand(params); 8 | 9 | if (variables) { 10 | variables.push.apply(variables, tmpl.vars); 11 | } 12 | 13 | return expanded; 14 | } 15 | 16 | export function parse(template) { 17 | 18 | var operators = ['+', '#', '.', '/', ';', '?', '&'], variables = []; 19 | 20 | return { 21 | vars: variables, 22 | expand(context) { 23 | return template.replace(/\{([^{}]+)\}|([^{}]+)/g, (_, expression, literal) => { 24 | if (expression) { 25 | 26 | var operator = null, values = []; 27 | 28 | if (operators.indexOf(expression.charAt(0)) !== -1) { 29 | operator = expression.charAt(0); 30 | expression = expression.substr(1); 31 | } 32 | 33 | expression.split(/,/g).forEach((variable) => { 34 | var tmp = /([^:*]*)(?::(\d+)|(\*))?/.exec(variable); 35 | values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); 36 | variables.push(tmp[1]); 37 | }); 38 | 39 | if (operator && operator !== '+') { 40 | 41 | var separator = ','; 42 | 43 | if (operator === '?') { 44 | separator = '&'; 45 | } else if (operator !== '#') { 46 | separator = operator; 47 | } 48 | 49 | return (values.length !== 0 ? operator : '') + values.join(separator); 50 | } else { 51 | return values.join(','); 52 | } 53 | 54 | } else { 55 | return encodeReserved(literal); 56 | } 57 | }); 58 | } 59 | }; 60 | } 61 | 62 | function getValues(context, operator, key, modifier) { 63 | 64 | var value = context[key], result = []; 65 | 66 | if (isDefined(value) && value !== '') { 67 | if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { 68 | value = value.toString(); 69 | 70 | if (modifier && modifier !== '*') { 71 | value = value.substring(0, parseInt(modifier, 10)); 72 | } 73 | 74 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 75 | } else { 76 | if (modifier === '*') { 77 | if (Array.isArray(value)) { 78 | value.filter(isDefined).forEach((value) => { 79 | result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); 80 | }); 81 | } else { 82 | Object.keys(value).forEach((k) => { 83 | if (isDefined(value[k])) { 84 | result.push(encodeValue(operator, value[k], k)); 85 | } 86 | }); 87 | } 88 | } else { 89 | var tmp = []; 90 | 91 | if (Array.isArray(value)) { 92 | value.filter(isDefined).forEach((value) => { 93 | tmp.push(encodeValue(operator, value)); 94 | }); 95 | } else { 96 | Object.keys(value).forEach((k) => { 97 | if (isDefined(value[k])) { 98 | tmp.push(encodeURIComponent(k)); 99 | tmp.push(encodeValue(operator, value[k].toString())); 100 | } 101 | }); 102 | } 103 | 104 | if (isKeyOperator(operator)) { 105 | result.push(encodeURIComponent(key) + '=' + tmp.join(',')); 106 | } else if (tmp.length !== 0) { 107 | result.push(tmp.join(',')); 108 | } 109 | } 110 | } 111 | } else { 112 | if (operator === ';') { 113 | result.push(encodeURIComponent(key)); 114 | } else if (value === '' && (operator === '&' || operator === '?')) { 115 | result.push(encodeURIComponent(key) + '='); 116 | } else if (value === '') { 117 | result.push(''); 118 | } 119 | } 120 | 121 | return result; 122 | } 123 | 124 | function isDefined(value) { 125 | return value !== undefined && value !== null; 126 | } 127 | 128 | function isKeyOperator(operator) { 129 | return operator === ';' || operator === '&' || operator === '?'; 130 | } 131 | 132 | function encodeValue(operator, value, key) { 133 | 134 | value = (operator === '+' || operator === '#') ? encodeReserved(value) : encodeURIComponent(value); 135 | 136 | if (key) { 137 | return encodeURIComponent(key) + '=' + value; 138 | } else { 139 | return value; 140 | } 141 | } 142 | 143 | function encodeReserved(str) { 144 | return str.split(/(%[0-9A-Fa-f]{2})/g).map((part) => { 145 | if (!/%[0-9A-Fa-f]/.test(part)) { 146 | part = encodeURI(part); 147 | } 148 | return part; 149 | }).join(''); 150 | } 151 | -------------------------------------------------------------------------------- /src/promise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Promise adapter. 3 | */ 4 | 5 | import PromiseLib from './lib/promise'; 6 | 7 | if (typeof Promise === 'undefined') { 8 | window.Promise = PromiseLib; 9 | } 10 | 11 | export default function PromiseObj(executor, context) { 12 | 13 | if (executor instanceof Promise) { 14 | this.promise = executor; 15 | } else { 16 | this.promise = new Promise(executor.bind(context)); 17 | } 18 | 19 | this.context = context; 20 | } 21 | 22 | PromiseObj.all = function (iterable, context) { 23 | return new PromiseObj(Promise.all(iterable), context); 24 | }; 25 | 26 | PromiseObj.resolve = function (value, context) { 27 | return new PromiseObj(Promise.resolve(value), context); 28 | }; 29 | 30 | PromiseObj.reject = function (reason, context) { 31 | return new PromiseObj(Promise.reject(reason), context); 32 | }; 33 | 34 | PromiseObj.race = function (iterable, context) { 35 | return new PromiseObj(Promise.race(iterable), context); 36 | }; 37 | 38 | var p = PromiseObj.prototype; 39 | 40 | p.bind = function (context) { 41 | this.context = context; 42 | return this; 43 | }; 44 | 45 | p.then = function (fulfilled, rejected) { 46 | 47 | if (fulfilled && fulfilled.bind && this.context) { 48 | fulfilled = fulfilled.bind(this.context); 49 | } 50 | 51 | if (rejected && rejected.bind && this.context) { 52 | rejected = rejected.bind(this.context); 53 | } 54 | 55 | return new PromiseObj(this.promise.then(fulfilled, rejected), this.context); 56 | }; 57 | 58 | p.catch = function (rejected) { 59 | 60 | if (rejected && rejected.bind && this.context) { 61 | rejected = rejected.bind(this.context); 62 | } 63 | 64 | return new PromiseObj(this.promise.catch(rejected), this.context); 65 | }; 66 | 67 | p.finally = function (callback) { 68 | 69 | return this.then(function (value) { 70 | callback.call(this); 71 | return value; 72 | }, function (reason) { 73 | callback.call(this); 74 | return Promise.reject(reason); 75 | } 76 | ); 77 | }; 78 | -------------------------------------------------------------------------------- /src/resource.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service for interacting with RESTful services. 3 | */ 4 | 5 | import Http from './http/index'; 6 | import {assign, each, merge} from './util'; 7 | 8 | export default function Resource(url, params, actions, options) { 9 | 10 | var self = this || {}, resource = {}; 11 | 12 | actions = assign({}, 13 | Resource.actions, 14 | actions 15 | ); 16 | 17 | each(actions, (action, name) => { 18 | 19 | action = merge({url, params: assign({}, params)}, options, action); 20 | 21 | resource[name] = function () { 22 | return (self.$http || Http)(opts(action, arguments)); 23 | }; 24 | }); 25 | 26 | return resource; 27 | } 28 | 29 | function opts(action, args) { 30 | 31 | var options = assign({}, action), params = {}, body; 32 | 33 | switch (args.length) { 34 | 35 | case 2: 36 | 37 | params = args[0]; 38 | body = args[1]; 39 | 40 | break; 41 | 42 | case 1: 43 | 44 | if (/^(POST|PUT|PATCH)$/i.test(options.method)) { 45 | body = args[0]; 46 | } else { 47 | params = args[0]; 48 | } 49 | 50 | break; 51 | 52 | case 0: 53 | 54 | break; 55 | 56 | default: 57 | 58 | throw 'Expected up to 2 arguments [params, body], got ' + args.length + ' arguments'; 59 | } 60 | 61 | options.body = body; 62 | options.params = assign({}, options.params, params); 63 | 64 | return options; 65 | } 66 | 67 | Resource.actions = { 68 | 69 | get: {method: 'GET'}, 70 | save: {method: 'POST'}, 71 | query: {method: 'GET'}, 72 | update: {method: 'PUT'}, 73 | remove: {method: 'DELETE'}, 74 | delete: {method: 'DELETE'} 75 | 76 | }; 77 | -------------------------------------------------------------------------------- /src/url/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service for URL templating. 3 | */ 4 | 5 | import root from './root'; 6 | import query from './query'; 7 | import template from './template'; 8 | import {each, merge, isArray, isFunction, isObject, isPlainObject, isString} from '../util'; 9 | 10 | export default function Url(url, params) { 11 | 12 | var self = this || {}, options = url, transform; 13 | 14 | if (isString(url)) { 15 | options = {url, params}; 16 | } 17 | 18 | options = merge({}, Url.options, self.$options, options); 19 | 20 | Url.transforms.forEach(handler => { 21 | 22 | if (isString(handler)) { 23 | handler = Url.transform[handler]; 24 | } 25 | 26 | if (isFunction(handler)) { 27 | transform = factory(handler, transform, self.$vm); 28 | } 29 | 30 | }); 31 | 32 | return transform(options); 33 | } 34 | 35 | /** 36 | * Url options. 37 | */ 38 | 39 | Url.options = { 40 | url: '', 41 | root: null, 42 | params: {} 43 | }; 44 | 45 | /** 46 | * Url transforms. 47 | */ 48 | 49 | Url.transform = {template, query, root}; 50 | Url.transforms = ['template', 'query', 'root']; 51 | 52 | /** 53 | * Encodes a Url parameter string. 54 | * 55 | * @param {Object} obj 56 | */ 57 | 58 | Url.params = function (obj) { 59 | 60 | var params = [], escape = encodeURIComponent; 61 | 62 | params.add = function (key, value) { 63 | 64 | if (isFunction(value)) { 65 | value = value(); 66 | } 67 | 68 | if (value === null) { 69 | value = ''; 70 | } 71 | 72 | this.push(escape(key) + '=' + escape(value)); 73 | }; 74 | 75 | serialize(params, obj); 76 | 77 | return params.join('&').replace(/%20/g, '+'); 78 | }; 79 | 80 | /** 81 | * Parse a URL and return its components. 82 | * 83 | * @param {String} url 84 | */ 85 | 86 | Url.parse = function (url) { 87 | 88 | var el = document.createElement('a'); 89 | 90 | if (document.documentMode) { 91 | el.href = url; 92 | url = el.href; 93 | } 94 | 95 | el.href = url; 96 | 97 | return { 98 | href: el.href, 99 | protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', 100 | port: el.port, 101 | host: el.host, 102 | hostname: el.hostname, 103 | pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, 104 | search: el.search ? el.search.replace(/^\?/, '') : '', 105 | hash: el.hash ? el.hash.replace(/^#/, '') : '' 106 | }; 107 | }; 108 | 109 | function factory(handler, next, vm) { 110 | return options => { 111 | return handler.call(vm, options, next); 112 | }; 113 | } 114 | 115 | function serialize(params, obj, scope) { 116 | 117 | var array = isArray(obj), plain = isPlainObject(obj), hash; 118 | 119 | each(obj, (value, key) => { 120 | 121 | hash = isObject(value) || isArray(value); 122 | 123 | if (scope) { 124 | key = scope + '[' + (plain || hash ? key : '') + ']'; 125 | } 126 | 127 | if (!scope && array) { 128 | params.add(value.name, value.value); 129 | } else if (hash) { 130 | serialize(params, value, key); 131 | } else { 132 | params.add(key, value); 133 | } 134 | }); 135 | } 136 | -------------------------------------------------------------------------------- /src/url/query.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Query Parameter Transform. 3 | */ 4 | 5 | import Url from './index'; 6 | import {each} from '../util'; 7 | 8 | export default function (options, next) { 9 | 10 | var urlParams = Object.keys(Url.options.params), query = {}, url = next(options); 11 | 12 | each(options.params, (value, key) => { 13 | if (urlParams.indexOf(key) === -1) { 14 | query[key] = value; 15 | } 16 | }); 17 | 18 | query = Url.params(query); 19 | 20 | if (query) { 21 | url += (url.indexOf('?') == -1 ? '?' : '&') + query; 22 | } 23 | 24 | return url; 25 | } 26 | -------------------------------------------------------------------------------- /src/url/root.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Root Prefix Transform. 3 | */ 4 | 5 | import {isString, trimEnd} from '../util'; 6 | 7 | export default function (options, next) { 8 | 9 | var url = next(options); 10 | 11 | if (isString(options.root) && !/^(https?:)?\//.test(url)) { 12 | url = trimEnd(options.root, '/') + '/' + url; 13 | } 14 | 15 | return url; 16 | } 17 | -------------------------------------------------------------------------------- /src/url/template.js: -------------------------------------------------------------------------------- 1 | /** 2 | * URL Template (RFC 6570) Transform. 3 | */ 4 | 5 | import {expand} from '../lib/url-template'; 6 | 7 | export default function (options) { 8 | 9 | var variables = [], url = expand(options.url, options.params, variables); 10 | 11 | variables.forEach((key) => { 12 | delete options.params[key]; 13 | }); 14 | 15 | return url; 16 | } 17 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility functions. 3 | */ 4 | 5 | import Promise from './promise'; 6 | 7 | var {hasOwnProperty} = {}, {slice} = [], debug = false, ntick; 8 | 9 | export const inBrowser = typeof window !== 'undefined'; 10 | 11 | export default function ({config, nextTick}) { 12 | ntick = nextTick; 13 | debug = config.debug || !config.silent; 14 | } 15 | 16 | export function warn(msg) { 17 | if (typeof console !== 'undefined' && debug) { 18 | console.warn('[VueResource warn]: ' + msg); 19 | } 20 | } 21 | 22 | export function error(msg) { 23 | if (typeof console !== 'undefined') { 24 | console.error(msg); 25 | } 26 | } 27 | 28 | export function nextTick(cb, ctx) { 29 | return ntick(cb, ctx); 30 | } 31 | 32 | export function trim(str) { 33 | return str ? str.replace(/^\s*|\s*$/g, '') : ''; 34 | } 35 | 36 | export function trimEnd(str, chars) { 37 | 38 | if (str && chars === undefined) { 39 | return str.replace(/\s+$/, ''); 40 | } 41 | 42 | if (!str || !chars) { 43 | return str; 44 | } 45 | 46 | return str.replace(new RegExp(`[${chars}]+$`), ''); 47 | } 48 | 49 | export function toLower(str) { 50 | return str ? str.toLowerCase() : ''; 51 | } 52 | 53 | export function toUpper(str) { 54 | return str ? str.toUpperCase() : ''; 55 | } 56 | 57 | export const isArray = Array.isArray; 58 | 59 | export function isString(val) { 60 | return typeof val === 'string'; 61 | } 62 | 63 | export function isBoolean(val) { 64 | return val === true || val === false; 65 | } 66 | 67 | export function isFunction(val) { 68 | return typeof val === 'function'; 69 | } 70 | 71 | export function isObject(obj) { 72 | return obj !== null && typeof obj === 'object'; 73 | } 74 | 75 | export function isPlainObject(obj) { 76 | return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; 77 | } 78 | 79 | export function isBlob(obj) { 80 | return typeof Blob !== 'undefined' && obj instanceof Blob; 81 | } 82 | 83 | export function isFormData(obj) { 84 | return typeof FormData !== 'undefined' && obj instanceof FormData; 85 | } 86 | 87 | export function when(value, fulfilled, rejected) { 88 | 89 | var promise = Promise.resolve(value); 90 | 91 | if (arguments.length < 2) { 92 | return promise; 93 | } 94 | 95 | return promise.then(fulfilled, rejected); 96 | } 97 | 98 | export function options(fn, obj, opts) { 99 | 100 | opts = opts || {}; 101 | 102 | if (isFunction(opts)) { 103 | opts = opts.call(obj); 104 | } 105 | 106 | return merge(fn.bind({$vm: obj, $options: opts}), fn, {$options: opts}); 107 | } 108 | 109 | export function each(obj, iterator) { 110 | 111 | var i, key; 112 | 113 | if (isArray(obj)) { 114 | for (i = 0; i < obj.length; i++) { 115 | iterator.call(obj[i], obj[i], i); 116 | } 117 | } else if (isObject(obj)) { 118 | for (key in obj) { 119 | if (hasOwnProperty.call(obj, key)) { 120 | iterator.call(obj[key], obj[key], key); 121 | } 122 | } 123 | } 124 | 125 | return obj; 126 | } 127 | 128 | export const assign = Object.assign || _assign; 129 | 130 | export function merge(target) { 131 | 132 | var args = slice.call(arguments, 1); 133 | 134 | args.forEach(source => { 135 | _merge(target, source, true); 136 | }); 137 | 138 | return target; 139 | } 140 | 141 | export function defaults(target) { 142 | 143 | var args = slice.call(arguments, 1); 144 | 145 | args.forEach(source => { 146 | 147 | for (var key in source) { 148 | if (target[key] === undefined) { 149 | target[key] = source[key]; 150 | } 151 | } 152 | 153 | }); 154 | 155 | return target; 156 | } 157 | 158 | function _assign(target) { 159 | 160 | var args = slice.call(arguments, 1); 161 | 162 | args.forEach(source => { 163 | _merge(target, source); 164 | }); 165 | 166 | return target; 167 | } 168 | 169 | function _merge(target, source, deep) { 170 | for (var key in source) { 171 | if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { 172 | if (isPlainObject(source[key]) && !isPlainObject(target[key])) { 173 | target[key] = {}; 174 | } 175 | if (isArray(source[key]) && !isArray(target[key])) { 176 | target[key] = []; 177 | } 178 | _merge(target[key], source[key], deep); 179 | } else if (source[key] !== undefined) { 180 | target[key] = source[key]; 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /test/data/invalid.json: -------------------------------------------------------------------------------- 1 | invalid -------------------------------------------------------------------------------- /test/data/text.txt: -------------------------------------------------------------------------------- 1 | text -------------------------------------------------------------------------------- /test/data/valid.json: -------------------------------------------------------------------------------- 1 | {"foo": "bar"} -------------------------------------------------------------------------------- /test/http.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | describe('Vue.http', function () { 4 | 5 | it('get("data/text.txt")', done => { 6 | 7 | Vue.http.get('data/text.txt').then(res => { 8 | 9 | expect(res.ok).toBe(true); 10 | expect(res.status).toBe(200); 11 | expect(res.body).toBe('text'); 12 | expect(res.data).toBe(res.body); 13 | expect(res.headers.get('Content-Type')).toBe('text/plain'); 14 | 15 | done(); 16 | }); 17 | 18 | }); 19 | 20 | it('get("data/valid.json")', done => { 21 | 22 | Vue.http.get('data/valid.json').then(res => { 23 | 24 | expect(res.ok).toBe(true); 25 | expect(res.status).toBe(200); 26 | expect(typeof res.body).toBe('object'); 27 | expect(res.body.foo).toBe('bar'); 28 | 29 | done(); 30 | }); 31 | 32 | }); 33 | 34 | it('get("data/invalid.json")', done => { 35 | 36 | Vue.http.get('data/invalid.json').then(res => { 37 | 38 | expect(res.ok).toBe(true); 39 | expect(res.status).toBe(200); 40 | expect(res.body).toBeNull(); 41 | 42 | done(); 43 | }); 44 | 45 | }); 46 | 47 | it('get("github.com/avatar")', done => { 48 | 49 | Vue.http.get('https://avatars1.githubusercontent.com/u/6128107', {responseType: 'blob'}).then(res => { 50 | 51 | expect(res.ok).toBe(true); 52 | expect(res.status).toBe(200); 53 | expect(res.body instanceof Blob).toBe(true); 54 | expect(res.body.type).toBe('image/png'); 55 | 56 | done(); 57 | }); 58 | 59 | }); 60 | 61 | it('get("cors-api.appspot.com")', done => { 62 | 63 | Vue.http.get('http://server.cors-api.appspot.com/server?id=1&enable=true').then(res => { 64 | 65 | expect(res.ok).toBe(true); 66 | expect(res.status).toBe(200); 67 | expect(typeof res.body).toBe('object'); 68 | expect(res.body.shift().requestType).toBe('cors'); 69 | 70 | if (res.headers.get('Content-Type')) { 71 | expect(res.headers.get('Content-Type')).toBe('application/json'); 72 | } 73 | 74 | done(); 75 | }); 76 | 77 | }); 78 | 79 | it('jsonp("jsfiddle.net/jsonp")', done => { 80 | 81 | Vue.http.jsonp('http://jsfiddle.net/echo/jsonp/', {params: {foo: 'bar'}}).then(res => { 82 | 83 | expect(res.ok).toBe(true); 84 | expect(res.status).toBe(200); 85 | expect(typeof res.body).toBe('object'); 86 | expect(res.body.foo).toBe('bar'); 87 | 88 | done(); 89 | }); 90 | 91 | }); 92 | 93 | }); 94 | 95 | describe('this.$http', function () { 96 | 97 | it('get("data/valid.json")', done => { 98 | 99 | var vm = new Vue({ 100 | 101 | created() { 102 | 103 | this.$http.get('data/valid.json').then(res => { 104 | 105 | expect(this).toBe(vm); 106 | expect(res.ok).toBe(true); 107 | expect(res.status).toBe(200); 108 | expect(typeof res.body).toBe('object'); 109 | expect(res.body.foo).toBe('bar'); 110 | 111 | done(); 112 | 113 | }); 114 | 115 | } 116 | 117 | }); 118 | 119 | }); 120 | 121 | it('get("data/valid.json") with timeout', done => { 122 | 123 | var vm = new Vue({ 124 | 125 | created() { 126 | 127 | var random = Math.random().toString(36).substr(2); 128 | 129 | this.$http.get(`data/valid.json?${random}`, {timeout: 1}).then(res => { 130 | 131 | fail('Callback has been called'); 132 | 133 | }, res => { 134 | 135 | expect(res.ok).toBe(false); 136 | expect(res.status).toBe(0); 137 | 138 | done(); 139 | 140 | }); 141 | 142 | } 143 | 144 | }); 145 | 146 | }); 147 | 148 | it('get("data/valid.json") with abort()', done => { 149 | 150 | var vm = new Vue({ 151 | 152 | created() { 153 | 154 | var random = Math.random().toString(36).substr(2); 155 | 156 | this.$http.get(`data/valid.json?${random}`, { 157 | 158 | before(req) { 159 | setTimeout(() => { 160 | 161 | expect(typeof req.abort).toBe('function'); 162 | 163 | req.abort(); 164 | 165 | }, 0); 166 | } 167 | 168 | }).then(res => { 169 | fail('Callback has been called'); 170 | }, res => { 171 | done(); 172 | }); 173 | } 174 | 175 | }); 176 | 177 | }); 178 | 179 | it('get("data/notfound.json") using catch()', done => { 180 | 181 | var vm = new Vue({ 182 | 183 | created() { 184 | 185 | this.$http.get('data/notfound.json').catch(res => { 186 | 187 | expect(this).toBe(vm); 188 | expect(res.ok).toBe(false); 189 | expect(res.status).toBe(404); 190 | 191 | done(); 192 | }); 193 | 194 | } 195 | 196 | }); 197 | 198 | }); 199 | 200 | }); -------------------------------------------------------------------------------- /test/http.test.js: -------------------------------------------------------------------------------- 1 | var Vue = require('vue'); 2 | var VueResource = require('../dist/vue-resource.common.js'); 3 | 4 | Vue.use(VueResource); 5 | 6 | describe('Vue.http', function () { 7 | 8 | it('post("jsfiddle.net/html")', () => { 9 | 10 | return Vue.http.post('http://jsfiddle.net/echo/html/', {html: 'text'}, {emulateJSON: true}).then(res => { 11 | 12 | expect(res.ok).toBe(true); 13 | expect(res.status).toBe(200); 14 | expect(typeof res.body).toBe('string'); 15 | expect(res.body).toBe('text'); 16 | 17 | }); 18 | 19 | }); 20 | 21 | it('post("jsfiddle.net/json")', () => { 22 | 23 | return Vue.http.post('http://jsfiddle.net/echo/json/', {json: JSON.stringify({foo: 'bar'})}, {emulateJSON: true}).then(res => { 24 | 25 | expect(res.ok).toBe(true); 26 | expect(res.status).toBe(200); 27 | expect(typeof res.body).toBe('object'); 28 | expect(res.body.foo).toBe('bar'); 29 | 30 | }); 31 | 32 | }); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue Resource - Jasmine 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueResource from '../src/index'; 3 | 4 | Vue.use(VueResource); 5 | 6 | require('./url'); 7 | require('./http'); 8 | require('./resource'); 9 | require('./promise'); 10 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = config => { 2 | 3 | config.set({ 4 | 5 | basePath: __dirname, 6 | 7 | frameworks: ['jasmine'], 8 | 9 | browsers: ['Chrome', 'Safari', 'Firefox'], 10 | 11 | files: [ 12 | 'index.js', { 13 | pattern: 'data/*', 14 | included: false 15 | }, 16 | ], 17 | 18 | preprocessors: { 19 | 'index.js': ['webpack'] 20 | }, 21 | 22 | proxies: { 23 | '/data/': '/base/data/' 24 | }, 25 | 26 | webpack: { 27 | mode: 'development' 28 | }, 29 | 30 | }); 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /test/promise.js: -------------------------------------------------------------------------------- 1 | import Promise from '../src/promise'; 2 | 3 | describe('Vue.promise ' + (window.Promise !== undefined ? '(native)' : '(polyfill)'), function () { 4 | 5 | it('then fulfill', function (done) { 6 | 7 | Promise.resolve(1).then(function (value) { 8 | expect(value).toBe(1); 9 | done(); 10 | }); 11 | 12 | }); 13 | 14 | it('then reject', function (done) { 15 | 16 | Promise.reject(1).then(undefined, function (value) { 17 | expect(value).toBe(1); 18 | done(); 19 | }); 20 | 21 | }); 22 | 23 | it('catch', function (done) { 24 | 25 | Promise.reject(1).catch(function (value) { 26 | expect(value).toBe(1); 27 | done(); 28 | }); 29 | 30 | }); 31 | 32 | it('finally fulfill', function (done) { 33 | 34 | Promise.resolve(1).finally(function (arg) { 35 | expect(arg).toBe(undefined); 36 | }).then(function (arg) { 37 | expect(arg).toBe(1); 38 | done(); 39 | }); 40 | 41 | }); 42 | 43 | it('finally reject', function (done) { 44 | 45 | Promise.reject(1).finally(function (arg) { 46 | expect(arg).toBe(undefined); 47 | }).catch(function (arg) { 48 | expect(arg).toBe(1); 49 | done(); 50 | }); 51 | 52 | }); 53 | 54 | it('all', function (done) { 55 | 56 | Promise.all([ 57 | 58 | Promise.resolve(1), 59 | Promise.resolve(2) 60 | 61 | ]).then(function (values) { 62 | expect(values[0]).toBe(1); 63 | expect(values[1]).toBe(2); 64 | done(); 65 | }); 66 | 67 | }); 68 | 69 | it('duplicate', function (done) { 70 | 71 | Promise.all([ 72 | 73 | Promise.resolve(1).then(function (value) { 74 | expect(value).toBe(1); 75 | }), 76 | 77 | Promise.resolve(2).then(function (value) { 78 | expect(value).toBe(2); 79 | }) 80 | 81 | ]).then(done); 82 | 83 | }); 84 | 85 | it('context', function (done) { 86 | 87 | var context = {foo: 'bar'}; 88 | 89 | Promise.resolve().bind(context).then(function () { 90 | expect(this).toBe(context); 91 | done(); 92 | }); 93 | 94 | }); 95 | 96 | it('context chain fulfill', function (done) { 97 | 98 | var context = {foo: 'bar'}; 99 | 100 | Promise.resolve().bind(context).catch(undefined).finally(function () { 101 | expect(this).toBe(context); 102 | }).then(function () { 103 | expect(this).toBe(context); 104 | done(); 105 | }); 106 | 107 | }); 108 | 109 | it('context chain reject', function (done) { 110 | 111 | var context = {foo: 'bar'}; 112 | 113 | Promise.reject().bind(context).catch(function () { 114 | expect(this).toBe(context); 115 | return Promise.reject(); 116 | }).finally(function () { 117 | expect(this).toBe(context); 118 | }).catch(function () { 119 | expect(this).toBe(context); 120 | done(); 121 | }); 122 | 123 | }); 124 | 125 | }); 126 | -------------------------------------------------------------------------------- /test/resource.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | describe('this.$resource', function () { 4 | 5 | it('get({file: "valid.json"})', (done) => { 6 | 7 | var vm = new Vue({ 8 | 9 | created() { 10 | 11 | var resource = this.$resource('data{/file}'); 12 | 13 | resource.get({file: 'valid.json'}).then((res) => { 14 | 15 | expect(res.ok).toBe(true); 16 | expect(res.status).toBe(200); 17 | expect(res.data.foo).toBe('bar'); 18 | 19 | done(); 20 | }); 21 | 22 | } 23 | 24 | }); 25 | 26 | }); 27 | 28 | it('save({file: "valid.json"}, {foo: "bar"})', (done) => { 29 | 30 | var vm = new Vue({ 31 | 32 | created() { 33 | 34 | var resource = this.$resource('data{/file}'); 35 | 36 | resource.save({file: 'valid.json'}, {foo: 'bar'}).then((res) => { 37 | 38 | expect(res.ok).toBe(true); 39 | expect(res.status).toBe(200); 40 | expect(res.data.foo).toBe('bar'); 41 | 42 | done(); 43 | }); 44 | 45 | } 46 | 47 | }); 48 | 49 | }); 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /test/url.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | describe('Vue.url', function () { 4 | 5 | it('data{/id}', function () { 6 | 7 | expect(Vue.url('data{/id}')).toBe('data'); 8 | expect(Vue.url('data{/id}', {id: 1})).toBe('data/1'); 9 | 10 | }); 11 | 12 | it('data{/array}', function () { 13 | 14 | expect(Vue.url('data{?array}')).toBe('data'); 15 | expect(Vue.url('data{?array}', {array: [1,2,3]})).toBe('data?array=1,2,3'); 16 | 17 | }); 18 | 19 | it('{+path}data', function () { 20 | 21 | expect(Vue.url('{+path}data')).toBe('data'); 22 | expect(Vue.url('{+path}data', {path: 'path1/path2/'})).toBe('path1/path2/data'); 23 | 24 | }); 25 | 26 | it('{+base}data', function () { 27 | 28 | Vue.url.options.params.base = 'base/path/'; 29 | expect(Vue.url('{+base}data')).toBe('base/path/data'); 30 | 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | mode: 'development', 4 | 5 | entry: __dirname + '/index.js', 6 | 7 | output: { 8 | path: __dirname + '/', 9 | filename: 'specs.js' 10 | }, 11 | 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.js$/, 16 | exclude: /node_modules/, 17 | use: 'babel-loader' 18 | } 19 | ] 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as VueResource from './vue_resource'; 2 | export default VueResource -------------------------------------------------------------------------------- /types/vue.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extends interfaces in Vue.js 3 | */ 4 | 5 | import Vue from "vue"; 6 | import { HttpHeaders, HttpOptions, HttpResponse, $http, $resource } from "./vue_resource"; 7 | 8 | declare module "vue/types/options" { 9 | interface ComponentOptions { 10 | http?: (HttpOptions & { headers?: HttpHeaders } & { [key: string]: any }) 11 | } 12 | } 13 | 14 | declare module "vue/types/vue" { 15 | interface Vue { 16 | $http: { 17 | (options: HttpOptions): PromiseLike; 18 | get: $http; 19 | post: $http; 20 | put: $http; 21 | patch: $http; 22 | delete: $http; 23 | jsonp: $http; 24 | }; 25 | $resource: $resource; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /types/vue_resource.ts: -------------------------------------------------------------------------------- 1 | import _Vue from 'vue'; 2 | 3 | // augment typings of Vue.js 4 | import './vue'; 5 | 6 | export interface HttpHeaders { 7 | put?: { [key: string]: string }; 8 | post?: { [key: string]: string }; 9 | patch?: { [key: string]: string }; 10 | delete?: { [key: string]: string }; 11 | common?: { [key: string]: string }; 12 | custom?: { [key: string]: string }; 13 | [key: string]: any; 14 | } 15 | 16 | export interface HttpResponse { 17 | data: any; 18 | ok: boolean; 19 | status: number; 20 | statusText: string; 21 | headers: Function; 22 | text(): string; 23 | json(): any; 24 | blob(): Blob; 25 | } 26 | 27 | export interface HttpOptions { 28 | url?: string; 29 | method?: string; 30 | body?: any; 31 | params?: any; 32 | headers?: any; 33 | before?(request: any): any; 34 | progress?(event: any): any; 35 | credentials?: boolean; 36 | emulateHTTP?: boolean; 37 | emulateJSON?: boolean; 38 | } 39 | 40 | export interface $http { 41 | (url: string, data?: any, options?: HttpOptions): PromiseLike; 42 | (url: string, options?: HttpOptions): PromiseLike; 43 | } 44 | 45 | export interface HttpInterceptor { 46 | request?(request: HttpOptions): HttpOptions; 47 | response?(response: HttpResponse): HttpResponse; 48 | } 49 | 50 | export interface Http { 51 | options: HttpOptions & { root: string }; 52 | headers: HttpHeaders; 53 | interceptors: (HttpInterceptor | (() => HttpInterceptor))[]; 54 | get: $http; 55 | post: $http; 56 | put: $http; 57 | patch: $http; 58 | delete: $http; 59 | jsonp: $http; 60 | } 61 | 62 | export interface ResourceActions { 63 | get: { method: string }; 64 | save: { method: string }; 65 | query: { method: string }; 66 | update: { method: string }; 67 | remove: { method: string }; 68 | delete: { method: string }; 69 | } 70 | 71 | export interface ResourceMethod { 72 | (params: any, data?: any, success?: Function, error?: Function): PromiseLike; 73 | (params: any, success?: Function, error?: Function): PromiseLike; 74 | (success?: Function, error?: Function): PromiseLike; 75 | } 76 | 77 | export interface ResourceMethods { 78 | get: ResourceMethod; 79 | save: ResourceMethod; 80 | query: ResourceMethod; 81 | update: ResourceMethod; 82 | remove: ResourceMethod; 83 | delete: ResourceMethod; 84 | } 85 | 86 | export interface $resource { 87 | (url: string, params?: any, actions?: any, options?: HttpOptions): ResourceMethods; 88 | } 89 | 90 | export interface Resource extends $resource { 91 | actions: ResourceActions; 92 | } 93 | 94 | export declare function install(vue: typeof _Vue): void; 95 | --------------------------------------------------------------------------------