Browse Source

Merge branch 'next'

Evan You 9 years ago
parent
commit
2f1035af76

+ 2 - 4
.eslintrc

@@ -1,6 +1,4 @@
 {
-  "extends": "standard",
-  "rules": {
-    "arrow-parens": [2, "as-needed"]
-  }
+  "root": true,
+  "extends": "vue"
 }

+ 0 - 2
build/bind.js

@@ -1,2 +0,0 @@
-// shim phantomjs for testing
-Function.prototype.bind = require('function-bind')

+ 47 - 43
dist/vuex.js

@@ -1,5 +1,5 @@
 /*!
- * Vuex v0.6.3
+ * Vuex v0.8.2
  * (c) 2016 Evan You
  * Released under the MIT License.
  */
@@ -9,20 +9,19 @@
   (global.Vuex = factory());
 }(this, function () { 'use strict';
 
-  var babelHelpers = {};
-  babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
     return typeof obj;
   } : function (obj) {
     return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj;
   };
 
-  babelHelpers.classCallCheck = function (instance, Constructor) {
+  var classCallCheck = function (instance, Constructor) {
     if (!(instance instanceof Constructor)) {
       throw new TypeError("Cannot call a class as a function");
     }
   };
 
-  babelHelpers.createClass = function () {
+  var createClass = function () {
     function defineProperties(target, props) {
       for (var i = 0; i < props.length; i++) {
         var descriptor = props[i];
@@ -40,7 +39,7 @@
     };
   }();
 
-  babelHelpers.toConsumableArray = function (arr) {
+  var toConsumableArray = function (arr) {
     if (Array.isArray(arr)) {
       for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
 
@@ -50,8 +49,6 @@
     }
   };
 
-  babelHelpers;
-
   /**
    * Merge an array of objects into one.
    *
@@ -89,7 +86,7 @@
   function deepClone(obj) {
     if (Array.isArray(obj)) {
       return obj.map(deepClone);
-    } else if (obj && (typeof obj === 'undefined' ? 'undefined' : babelHelpers.typeof(obj)) === 'object') {
+    } else if (obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object') {
       var cloned = {};
       var keys = Object.keys(obj);
       for (var i = 0, l = keys.length; i < l; i++) {
@@ -110,9 +107,8 @@
   var Watcher = void 0;
   function getWatcher(vm) {
     if (!Watcher) {
-      var unwatch = vm.$watch('__vuex__', function (a) {
-        return a;
-      });
+      var noop = function noop() {};
+      var unwatch = vm.$watch(noop, noop);
       Watcher = vm._watchers[0].constructor;
       unwatch();
     }
@@ -134,11 +130,8 @@
       if (!hook) return;
       hook.emit('vuex:init', store);
       hook.on('vuex:travel-to-state', function (targetState) {
-        var currentState = store._vm._data;
         store._dispatching = true;
-        Object.keys(targetState).forEach(function (key) {
-          currentState[key] = targetState[key];
-        });
+        store._vm.state = targetState;
         store._dispatching = false;
       });
     },
@@ -149,14 +142,24 @@
   };
 
   function override (Vue) {
-    // override init and inject vuex init procedure
-    var _init = Vue.prototype._init;
-    Vue.prototype._init = function () {
-      var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+    var version = Number(Vue.version.split('.')[0]);
 
-      options.init = options.init ? [vuexInit].concat(options.init) : vuexInit;
-      _init.call(this, options);
-    };
+    if (version >= 2) {
+      var usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1;
+      Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit });
+    } else {
+      (function () {
+        // override init and inject vuex init procedure
+        // for 1.x backwards compatibility.
+        var _init = Vue.prototype._init;
+        Vue.prototype._init = function () {
+          var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+          options.init = options.init ? [vuexInit].concat(options.init) : vuexInit;
+          _init.call(this, options);
+        };
+      })();
+    }
 
     /**
      * Vuex init hook, injected into each instances init hooks list.
@@ -179,8 +182,8 @@
           console.warn('[vuex] store not injected. make sure to ' + 'provide the store option in your root component.');
         }
         var state = vuex.state;
-        var getters = vuex.getters;
         var actions = vuex.actions;
+        var getters = vuex.getters;
         // handle deprecated state option
 
         if (state && !getters) {
@@ -254,8 +257,8 @@
       var vm = store._vm;
       var Watcher = getWatcher(vm);
       var Dep = getDep(vm);
-      var watcher = new Watcher(vm, function (state) {
-        return getter(state);
+      var watcher = new Watcher(vm, function (vm) {
+        return getter(vm.state);
       }, null, { lazy: true });
       var computedGetter = function computedGetter() {
         if (watcher.dirty) {
@@ -333,7 +336,7 @@
       var middlewares = _ref$middlewares === undefined ? [] : _ref$middlewares;
       var _ref$strict = _ref.strict;
       var strict = _ref$strict === undefined ? false : _ref$strict;
-      babelHelpers.classCallCheck(this, Store);
+      classCallCheck(this, Store);
 
       this._getterCacheId = 'vuex_store_' + uid++;
       this._dispatching = false;
@@ -357,7 +360,9 @@
       var silent = Vue.config.silent;
       Vue.config.silent = true;
       this._vm = new Vue({
-        data: state
+        data: {
+          state: state
+        }
       });
       Vue.config.silent = silent;
       this._setupModuleState(state, modules);
@@ -376,7 +381,7 @@
      * @return {Object}
      */
 
-    babelHelpers.createClass(Store, [{
+    createClass(Store, [{
       key: 'dispatch',
 
 
@@ -393,7 +398,7 @@
 
         var silent = false;
         // compatibility for object actions, e.g. FSA
-        if ((typeof type === 'undefined' ? 'undefined' : babelHelpers.typeof(type)) === 'object' && type.type && arguments.length === 1) {
+        if ((typeof type === 'undefined' ? 'undefined' : _typeof(type)) === 'object' && type.type && arguments.length === 1) {
           payload = [type.payload];
           if (type.silent) silent = true;
           type = type.type;
@@ -405,10 +410,10 @@
           // apply the mutation
           if (Array.isArray(mutation)) {
             mutation.forEach(function (m) {
-              return m.apply(undefined, [state].concat(babelHelpers.toConsumableArray(payload)));
+              return m.apply(undefined, [state].concat(toConsumableArray(payload)));
             });
           } else {
-            mutation.apply(undefined, [state].concat(babelHelpers.toConsumableArray(payload)));
+            mutation.apply(undefined, [state].concat(toConsumableArray(payload)));
           }
           this._dispatching = false;
           if (!silent) this._applyMiddlewares(type, payload);
@@ -422,18 +427,22 @@
        * Same API as Vue's $watch, except when watching a function,
        * the function gets the state as the first argument.
        *
-       * @param {String|Function} expOrFn
+       * @param {Function} fn
        * @param {Function} cb
        * @param {Object} [options]
        */
 
     }, {
       key: 'watch',
-      value: function watch(expOrFn, cb, options) {
+      value: function watch(fn, cb, options) {
         var _this2 = this;
 
+        if (typeof fn !== 'function') {
+          console.error('Vuex store.watch only accepts function.');
+          return;
+        }
         return this._vm.$watch(function () {
-          return typeof expOrFn === 'function' ? expOrFn(_this2.state) : _this2._vm.$get(expOrFn);
+          return fn(_this2.state);
         }, cb, options);
       }
 
@@ -523,7 +532,7 @@
 
         var Watcher = getWatcher(this._vm);
         /* eslint-disable no-new */
-        new Watcher(this._vm, '$data', function () {
+        new Watcher(this._vm, 'state', function () {
           if (!_this3._dispatching) {
             throw new Error('[vuex] Do not mutate vuex store state outside mutation handlers.');
           }
@@ -596,7 +605,7 @@
     }, {
       key: 'state',
       get: function get() {
-        return this._vm._data;
+        return this._vm.state;
       },
       set: function set(v) {
         throw new Error('[vuex] Vuex root state is read only.');
@@ -619,14 +628,9 @@
     install(window.Vue);
   }
 
-  function createLogger() {
-    console.warn('[vuex] Vuex.createLogger has been deprecated.' + 'Use `import createLogger from \'vuex/logger\' instead.');
-  }
-
   var index = {
     Store: Store,
-    install: install,
-    createLogger: createLogger
+    install: install
   };
 
   return index;

File diff suppressed because it is too large
+ 1 - 1
dist/vuex.min.js


+ 10 - 3
examples/chat/components/MessageSection.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="message-section">
     <h3 class="message-thread-heading">{{ thread.name }}</h3>
-    <ul class="message-list" v-el:list>
+    <ul class="message-list" ref="list">
       <message
-        v-for="message in messages | orderBy 'timestamp'"
+        v-for="message in sortedMessages"
         track-by="id"
         :message="message">
       </message>
@@ -28,10 +28,17 @@ export default {
       sendMessage
     }
   },
+  computed: {
+    sortedMessages () {
+      return this.messages
+        .slice()
+        .sort((a, b) => a.timestamp - b.timestamp)
+    }
+  },
   watch: {
     'thread.lastMessage': function () {
       this.$nextTick(() => {
-        const ul = this.$els.list
+        const ul = this.$refs.list
         ul.scrollTop = ul.scrollHeight
       })
     }

+ 1 - 1
examples/chat/index.html

@@ -6,7 +6,7 @@
     <link href="http://fonts.googleapis.com/css?family=Muli" rel="stylesheet" type="text/css">
   </head>
   <body>
-    <app></app>
+    <div id="app"></div>
     <script src="build.js"></script>
   </body>
 </html>

+ 2 - 2
examples/chat/main.js

@@ -11,9 +11,9 @@ Vue.filter('time', timestamp => {
 })
 
 new Vue({
-  el: 'body',
+  el: '#app',
   store,
-  components: { App }
+  render: h => h(App)
 })
 
 getAllMessages(store)

+ 1 - 1
examples/counter-hot/Counter.vue

@@ -18,7 +18,7 @@ import { recentHistory } from './vuex/getters'
 export default {
   vuex: {
     actions,
-    state: {
+    getters: {
       count: state => state.count,
       recentHistory
     }

+ 1 - 1
examples/counter-hot/index.html

@@ -5,7 +5,7 @@
     <title>vuex counter example</title>
   </head>
   <body>
-    <counter></counter>
+    <div id="app"></div>
     <script src="build.js"></script>
   </body>
 </html>

+ 2 - 2
examples/counter-hot/main.js

@@ -3,7 +3,7 @@ import store from './vuex/store'
 import Counter from './Counter.vue'
 
 new Vue({
-  el: 'body',
+  el: '#app',
   store,
-  components: { Counter }
+  render: h => h(Counter)
 })

+ 1 - 1
examples/counter/index.html

@@ -5,7 +5,7 @@
     <title>vuex counter example</title>
   </head>
   <body>
-    <counter></counter>
+    <div id="app"></div>
     <script src="build.js"></script>
   </body>
 </html>

+ 2 - 2
examples/counter/main.js

@@ -3,7 +3,7 @@ import Counter from './Counter.vue'
 import store from './store'
 
 new Vue({
-  el: 'body',
+  el: '#app',
   store,
-  components: { Counter }
+  render: h => h(Counter)
 })

+ 23 - 0
examples/shopping-cart/currency.js

@@ -0,0 +1,23 @@
+const digitsRE = /(\d{3})(?=\d)/g
+
+export function currency (value, currency, decimals) {
+  value = parseFloat(value)
+  if (!isFinite(value) || (!value && value !== 0)) return ''
+  currency = currency != null ? currency : '$'
+  decimals = decimals != null ? decimals : 2
+  var stringified = Math.abs(value).toFixed(decimals)
+  var _int = decimals
+    ? stringified.slice(0, -1 - decimals)
+    : stringified
+  var i = _int.length % 3
+  var head = i > 0
+    ? (_int.slice(0, i) + (_int.length > 3 ? ',' : ''))
+    : ''
+  var _float = decimals
+    ? stringified.slice(-1 - decimals)
+    : ''
+  var sign = value < 0 ? '-' : ''
+  return sign + currency + head +
+    _int.slice(i).replace(digitsRE, '$1,') +
+    _float
+}

+ 1 - 1
examples/shopping-cart/index.html

@@ -5,7 +5,7 @@
     <title>vuex shopping cart example</title>
   </head>
   <body>
-    <app></app>
+    <div id="app"></div>
     <script src="build.js"></script>
   </body>
 </html>

+ 5 - 2
examples/shopping-cart/main.js

@@ -2,9 +2,12 @@ import 'babel-polyfill'
 import Vue from 'vue'
 import App from './components/App.vue'
 import store from './vuex/store'
+import { currency } from './currency'
+
+Vue.filter('currency', currency)
 
 new Vue({
-  el: 'body',
+  el: '#app',
   store,
-  components: { App }
+  render: h => h(App)
 })

+ 7 - 3
examples/todomvc/components/App.vue

@@ -25,11 +25,11 @@
     <footer class="footer" v-show="todos.length">
       <span class="todo-count">
         <strong>{{ remaining }}</strong>
-        {{ remaining | pluralize 'item' }} left
+        {{ remaining | pluralize('item') }} left
       </span>
       <ul class="filters">
-        <li v-for="(key, val) in filters">
-          <a href="#/{{$key}}"
+        <li v-for="(val, key) in filters">
+          <a :href="'#/' + key"
             :class="{ selected: visibility === key }"
             @click="visibility = key">
             {{ key | capitalize }}
@@ -96,6 +96,10 @@ export default {
       }
       e.target.value = ''
     }
+  },
+  filters: {
+    pluralize: (n, w) => n === 1 ? w : (w + 's'),
+    capitalize: s => s.charAt(0).toUpperCase() + s.slice(1)
   }
 }
 </script>

+ 3 - 3
examples/todomvc/components/Todo.vue

@@ -40,10 +40,10 @@ export default {
     }
   },
   directives: {
-    focus (value) {
+    focus (el, { value }, { context }) {
       if (value) {
-        this.vm.$nextTick(() => {
-          this.el.focus()
+        context.$nextTick(() => {
+          el.focus()
         })
       }
     }

+ 1 - 1
examples/todomvc/index.html

@@ -5,7 +5,7 @@
     <title>vuex todomvc example</title>
   </head>
   <body>
-    <app></app>
+    <div id="app"></div>
     <script src="build.js"></script>
   </body>
 </html>

+ 2 - 2
examples/todomvc/main.js

@@ -4,6 +4,6 @@ import App from './components/App.vue'
 
 new Vue({
   store, // inject store to all children
-  el: 'body',
-  components: { App }
+  el: '#app',
+  render: h => h(App)
 })

+ 1 - 1
examples/todomvc/vuex/store.js

@@ -24,7 +24,7 @@ const mutations = {
   },
 
   DELETE_TODO (state, todo) {
-    state.todos.$remove(todo)
+    state.todos.splice(state.todos.indexOf(todo), 1)
   },
 
   TOGGLE_TODO (state, todo) {

+ 1 - 1
examples/webpack.build-all.config.js

@@ -8,7 +8,7 @@ var examples = [
 
 var entry = {}
 examples.forEach(function (name) {
-  entry[name] = ['./build/bind.js', './examples/' + name + '/main.js']
+  entry[name] = ['./examples/' + name + '/main.js']
 })
 
 module.exports = {

+ 8 - 12
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vuex",
-  "version": "0.6.3",
+  "version": "0.8.2",
   "description": "state management for Vue.js",
   "main": "dist/vuex.js",
   "files": [
@@ -17,8 +17,9 @@
     "build": "node build/build.js",
     "build-examples": "BABEL_ENV=development webpack --config examples/webpack.build-all.config.js",
     "unit": "BABEL_ENV=development mocha test/unit/test.js --compilers js:babel-core/register",
+    "pree2e": "npm run build-examples",
     "e2e": "casperjs test --concise ./test/e2e",
-    "test": "eslint src && npm run unit && npm run build-examples && npm run e2e",
+    "test": "eslint src && npm run unit && npm run e2e",
     "docs": "cd docs && gitbook serve",
     "deploy-docs": "cd docs && ./deploy.sh",
     "release": "bash build/release.sh"
@@ -46,22 +47,17 @@
     "chai": "^3.4.1",
     "css-loader": "^0.23.1",
     "eslint": "^2.2.0",
-    "eslint-config-standard": "^5.1.0",
-    "eslint-plugin-promise": "^1.0.8",
-    "eslint-plugin-standard": "^1.3.2",
-    "function-bind": "^1.1.0",
+    "eslint-config-vue": "^1.0.0",
     "mocha": "^2.3.4",
-    "rollup": "^0.25.4",
+    "phantomjs-prebuilt": "^2.1.7",
+    "rollup": "^0.32.0",
     "rollup-plugin-babel": "^2.4.0",
     "sinon": "^1.17.3",
     "sinon-chai": "^2.8.0",
     "todomvc-app-css": "^2.0.3",
     "uglify-js": "^2.6.2",
-    "vue": "^1.0.17",
-    "vue-hot-reload-api": "^1.2.1",
-    "vue-html-loader": "^1.0.0",
-    "vue-loader": "^8.2.0",
-    "vue-style-loader": "^1.0.0",
+    "vue": "^2.0.0-alpha.7",
+    "vue-loader": "^9.0.3",
     "webpack": "^1.12.8",
     "webpack-dev-server": "^1.12.1"
   }

+ 13 - 19
src/index.js

@@ -43,7 +43,9 @@ class Store {
     const silent = Vue.config.silent
     Vue.config.silent = true
     this._vm = new Vue({
-      data: state
+      data: {
+        state
+      }
     })
     Vue.config.silent = silent
     this._setupModuleState(state, modules)
@@ -63,7 +65,7 @@ class Store {
    */
 
   get state () {
-    return this._vm._data
+    return this._vm.state
   }
 
   set state (v) {
@@ -106,17 +108,17 @@ class Store {
    * Same API as Vue's $watch, except when watching a function,
    * the function gets the state as the first argument.
    *
-   * @param {String|Function} expOrFn
+   * @param {Function} fn
    * @param {Function} cb
    * @param {Object} [options]
    */
 
-  watch (expOrFn, cb, options) {
-    return this._vm.$watch(() => {
-      return typeof expOrFn === 'function'
-        ? expOrFn(this.state)
-        : this._vm.$get(expOrFn)
-    }, cb, options)
+  watch (fn, cb, options) {
+    if (typeof fn !== 'function') {
+      console.error('Vuex store.watch only accepts function.')
+      return
+    }
+    return this._vm.$watch(() => fn(this.state), cb, options)
   }
 
   /**
@@ -186,7 +188,7 @@ class Store {
   _setupMutationCheck () {
     const Watcher = getWatcher(this._vm)
     /* eslint-disable no-new */
-    new Watcher(this._vm, '$data', () => {
+    new Watcher(this._vm, 'state', () => {
       if (!this._dispatching) {
         throw new Error(
           '[vuex] Do not mutate vuex store state outside mutation handlers.'
@@ -270,15 +272,7 @@ if (typeof window !== 'undefined' && window.Vue) {
   install(window.Vue)
 }
 
-function createLogger () {
-  console.warn(
-    '[vuex] Vuex.createLogger has been deprecated.' +
-    'Use `import createLogger from \'vuex/logger\' instead.'
-  )
-}
-
 export default {
   Store,
-  install,
-  createLogger
+  install
 }

+ 1 - 4
src/middlewares/devtool.js

@@ -7,11 +7,8 @@ export default {
     if (!hook) return
     hook.emit('vuex:init', store)
     hook.on('vuex:travel-to-state', targetState => {
-      const currentState = store._vm._data
       store._dispatching = true
-      Object.keys(targetState).forEach(key => {
-        currentState[key] = targetState[key]
-      })
+      store._vm.state = targetState
       store._dispatching = false
     })
   },

+ 20 - 11
src/override.js

@@ -1,13 +1,21 @@
 import { getWatcher, getDep } from './util'
 
 export default function (Vue) {
-  // override init and inject vuex init procedure
-  const _init = Vue.prototype._init
-  Vue.prototype._init = function (options = {}) {
-    options.init = options.init
-      ? [vuexInit].concat(options.init)
-      : vuexInit
-    _init.call(this, options)
+  const version = Number(Vue.version.split('.')[0])
+
+  if (version >= 2) {
+    const usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1
+    Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit })
+  } else {
+    // override init and inject vuex init procedure
+    // for 1.x backwards compatibility.
+    const _init = Vue.prototype._init
+    Vue.prototype._init = function (options = {}) {
+      options.init = options.init
+        ? [vuexInit].concat(options.init)
+        : vuexInit
+      _init.call(this, options)
+    }
   }
 
   /**
@@ -31,7 +39,8 @@ export default function (Vue) {
           'provide the store option in your root component.'
         )
       }
-      let { state, getters, actions } = vuex
+      const { state, actions } = vuex
+      let { getters } = vuex
       // handle deprecated state option
       if (state && !getters) {
         console.warn(
@@ -43,14 +52,14 @@ export default function (Vue) {
       // getters
       if (getters) {
         options.computed = options.computed || {}
-        for (let key in getters) {
+        for (const key in getters) {
           defineVuexGetter(this, key, getters[key])
         }
       }
       // actions
       if (actions) {
         options.methods = options.methods || {}
-        for (let key in actions) {
+        for (const key in actions) {
           options.methods[key] = makeBoundAction(this.$store, actions[key], key)
         }
       }
@@ -109,7 +118,7 @@ export default function (Vue) {
     const Dep = getDep(vm)
     const watcher = new Watcher(
       vm,
-      state => getter(state),
+      vm => getter(vm.state),
       null,
       { lazy: true }
     )

+ 2 - 1
src/util.js

@@ -56,7 +56,8 @@ export function deepClone (obj) {
 let Watcher
 export function getWatcher (vm) {
   if (!Watcher) {
-    const unwatch = vm.$watch('__vuex__', a => a)
+    const noop = function () {}
+    const unwatch = vm.$watch(noop, noop)
     Watcher = vm._watchers[0].constructor
     unwatch()
   }

+ 1 - 5
test/unit/test.js

@@ -300,17 +300,13 @@ describe('Vuex', () => {
         [TEST]: state => state.a++
       }
     })
-    let watchedValueOne, watchedValueTwo
+    let watchedValueOne
     store.watch(({ a }) => a, val => {
       watchedValueOne = val
     })
-    store.watch('a', val => {
-      watchedValueTwo = val
-    })
     store.dispatch(TEST)
     Vue.nextTick(() => {
       expect(watchedValueOne).to.equal(2)
-      expect(watchedValueTwo).to.equal(2)
       done()
     })
   })

Some files were not shown because too many files changed in this diff