From a4754562007072d9668b3f70bbf3b6479726abb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honor=C3=A9=20HOUNWANOU?= Date: Tue, 13 Sep 2016 15:38:23 -0400 Subject: [PATCH 01/12] Fix wrong store state path (#311) Fix wrong store state path --- docs/en/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/tutorial.md b/docs/en/tutorial.md index 1e474a3f5..46c23727d 100644 --- a/docs/en/tutorial.md +++ b/docs/en/tutorial.md @@ -250,7 +250,7 @@ You might be wondering - why did we choose to use a getter instead of directly a 1. We may want to define getters with computed values (think totals, averages, etc.). 2. Many components in a larger app can use the same getter function. -3. If the value is moved from say `store.count` to `store.counter.value` you'd have to update one getter instead of dozens of components. +3. If the value is moved from say `store.state.count` to `store.state.counter.value` you'd have to update one getter instead of dozens of components. These are a few of the benefits of using getters. From cea198835a028b70d0693f347e21121b548135ef Mon Sep 17 00:00:00 2001 From: katashin Date: Wed, 14 Sep 2016 04:38:43 +0900 Subject: [PATCH 02/12] use state transformer in logger plugin (#309) --- src/plugins/logger.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/logger.js b/src/plugins/logger.js index 583620837..e1d27f7a0 100644 --- a/src/plugins/logger.js +++ b/src/plugins/logger.js @@ -28,9 +28,9 @@ export default function createLogger ({ console.log(message) } - console.log('%c prev state', 'color: #9E9E9E; font-weight: bold', prevState) + console.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState)) console.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation) - console.log('%c next state', 'color: #4CAF50; font-weight: bold', nextState) + console.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState)) try { console.groupEnd() From 2e62705d4bce4ebcb8eca23df8c7b849125fc565 Mon Sep 17 00:00:00 2001 From: katashin Date: Wed, 14 Sep 2016 04:39:18 +0900 Subject: [PATCH 03/12] Fix broken todomvc e2e test (#296) * fix broken todomvc e2e test * bump casperjs --- package.json | 2 +- test/e2e/todomvc.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 69199db01..cfb04836c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "babel-preset-es2015-rollup": "^1.1.1", "babel-preset-stage-2": "^6.1.18", "babel-runtime": "^6.0.0", - "casperjs": "^1.1.0-beta5", + "casperjs": "^1.1.3", "chai": "^3.4.1", "css-loader": "^0.23.1", "eslint": "^2.2.0", diff --git a/test/e2e/todomvc.js b/test/e2e/todomvc.js index c7085174c..811905d67 100644 --- a/test/e2e/todomvc.js +++ b/test/e2e/todomvc.js @@ -2,6 +2,7 @@ casper.test.begin('todomvc', 57, function (test) { casper .start('examples/todomvc/index.html') .then(function () { + this.viewport(1000, 1000) // for appearing destroy button by mouse hover test.assertNotVisible('.main', '.main should be hidden') test.assertNotVisible('.footer', '.footer should be hidden') test.assertElementCount('.filters .selected', 1, 'should have one filter selected') @@ -29,7 +30,7 @@ casper.test.begin('todomvc', 57, function (test) { test.assertVisible('.main', '.main should now be visible') test.assertVisible('.footer', '.footer should now be visible') test.assertNotVisible('.clear-completed', '.clear-completed should be hidden') - test.assertField({type: 'css', path: '.new-todo'}, '', 'new todo input should be reset') + test.assertField({ type: 'css', path: '.new-todo' }, '', 'new todo input should be reset') }) // add another item --------------------------------------------------- @@ -88,6 +89,9 @@ casper.test.begin('todomvc', 57, function (test) { // remove a completed item -------------------------------------------- + .then(function () { + this.mouse.move('.todo:nth-child(1)') + }) .thenClick('.todo:nth-child(1) .destroy', function () { test.assertElementCount('.todo', 4, 'should have 4 items now') test.assertElementCount('.todo.completed', 2, 'should have 2 item completed') @@ -96,6 +100,9 @@ casper.test.begin('todomvc', 57, function (test) { // remove a incompleted item ------------------------------------------ + .then(function () { + this.mouse.move('.todo:nth-child(2)') + }) .thenClick('.todo:nth-child(2) .destroy', function () { test.assertElementCount('.todo', 3, 'should have 3 items now') test.assertElementCount('.todo.completed', 2, 'should have 2 item completed') From 2b75d948d42d96e26901964195a0366cfdca4d50 Mon Sep 17 00:00:00 2001 From: Kamakura Masaya Date: Mon, 19 Sep 2016 01:51:49 +0900 Subject: [PATCH 04/12] update document ja tutorial (#320) --- docs/ja/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/tutorial.md b/docs/ja/tutorial.md index 73c70b5c4..58e545d4e 100644 --- a/docs/ja/tutorial.md +++ b/docs/ja/tutorial.md @@ -145,7 +145,7 @@ export default { アクションはコンポーネントから呼び出される関数です。アクション関数は対応するミューテーションをディスパッチすることで、ストアを更新することができます。アクションは更新をディスパッチする前に、その他のデータを読み込むために HTTP バックエンドと通信することも可能です。 -`incrementCounter` 関数を持つ、新しいファイル `vuex/action.js` を作成しましょう。 +`incrementCounter` 関数を持つ、新しいファイル `vuex/actions.js` を作成しましょう。 ```js // アクションは1番目の引数にストアを受け取ります。 From 757aa7ce51e7f27c487668064ab4bd4ff7bc03bf Mon Sep 17 00:00:00 2001 From: Kamakura Masaya Date: Mon, 19 Sep 2016 01:52:57 +0900 Subject: [PATCH 05/12] update docs/ja/state.md (#321) --- docs/ja/state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/state.md b/docs/ja/state.md index 2d3c1edc7..a72cf5d7e 100644 --- a/docs/ja/state.md +++ b/docs/ja/state.md @@ -67,7 +67,7 @@ count: function() { 特殊な `vuex` オプションブロックについて説明しておきましょう。これは、コンポーネントで利用されるストアの状態が何か記述する場所です。各プロパテイ名は、唯一の引数として、全体のステートツリーを受け取るゲッター関数を指定します。そして、状態の一部を選ぶか、状態から算出される値を返します。返された値は、算出プロパティのように、プロパティ名を使ってコンポーネントにセットされます。 - ほとんどの場合で、"ゲッター( getter )" 関数は、ES2015 のアロー関数を使って、完結に書くことができるでしょう: + ほとんどの場合で、"ゲッター( getter )" 関数は、ES2015 のアロー関数を使って、簡潔に書くことができるでしょう: ``` js vuex: { From ed0bae9eb4239f716de1cf006fcfc56063af90c8 Mon Sep 17 00:00:00 2001 From: sciooga Date: Thu, 22 Sep 2016 08:27:06 -0500 Subject: [PATCH 06/12] Api has chagned (#322) Actions not in Vuex.Store constructor options. --- docs/zh-cn/mutations.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/zh-cn/mutations.md b/docs/zh-cn/mutations.md index d29dbd11d..47df4df01 100644 --- a/docs/zh-cn/mutations.md +++ b/docs/zh-cn/mutations.md @@ -99,7 +99,6 @@ import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, - actions: { ... }, mutations: { // we can use the ES2015 computed property name feature // to use a constant as the function name From f8d2195efe4fd74878444033b35c26c331e70cd8 Mon Sep 17 00:00:00 2001 From: Obura Tongoi Date: Thu, 22 Sep 2016 06:31:06 -0700 Subject: [PATCH 07/12] Update actions.md (#288) Just a minor typographical error. Great work! --- docs/en/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/actions.md b/docs/en/actions.md index dc9efd402..3bb36bfb3 100644 --- a/docs/en/actions.md +++ b/docs/en/actions.md @@ -10,7 +10,7 @@ function increment (store) { store.dispatch('INCREMENT') } -// a action with additional arguments +// an action with additional arguments // with ES2015 argument destructuring function incrementBy ({ dispatch }, amount) { dispatch('INCREMENT', amount) From f44ab7f34fea1e2ba5869cdedfc96878254c702d Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 Sep 2016 06:32:58 -0700 Subject: [PATCH 08/12] Update testing.md (#267) --- docs/en/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/testing.md b/docs/en/testing.md index 318cbcc55..b4aae115d 100644 --- a/docs/en/testing.md +++ b/docs/en/testing.md @@ -164,4 +164,4 @@ mocha test-bundle.js #### Running in Browser with Karma + karma-webpack -Consult the setup in [vue-loader documentation](http://vuejs.github.io/vue-loader/workflow/testing.html). +Consult the setup in [vue-loader documentation](http://vue-loader.vuejs.org/en/workflow/testing.html). From 10be6af789ce1adcf2cb2bd529c30dd50054c022 Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Thu, 22 Sep 2016 15:35:59 +0200 Subject: [PATCH 09/12] Docs cleanup (#233) --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 80600b06f..91945b904 100644 --- a/src/index.js +++ b/src/index.js @@ -261,11 +261,11 @@ class Store { } /** - * Setup mutation check: if the vuex instance's state is mutated + * Setup mutation check: if the Vuex instance's state is mutated * outside of a mutation handler, we throw en error. This effectively - * enforces all mutations to the state to be trackable and hot-reloadble. + * enforces all mutations to the state to be trackable and hot-reloadable. * However, this comes at a run time cost since we are doing a deep - * watch on the entire state tree, so it is only enalbed with the + * watch on the entire state tree, so it is only enabled if the * strict option is set to true. */ From 3f25d3b15bbdcda3e9f78fec50476dd7a26d7439 Mon Sep 17 00:00:00 2001 From: katashin Date: Fri, 23 Sep 2016 08:00:48 +0900 Subject: [PATCH 10/12] Support circular structure for logger (#327) * support circular structure for logger * add deepCopy unit test --- package.json | 2 +- src/plugins/logger.js | 6 ++++-- src/util.js | 48 +++++++++++++++++++++++++++++++++++++++++++ test/unit/util.js | 42 +++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 test/unit/util.js diff --git a/package.json b/package.json index cfb04836c..594923d6f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "chat": "cd examples/chat && webpack-dev-server --inline --hot --config ../webpack.shared.config.js", "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", + "unit": "BABEL_ENV=development mocha test/unit/*.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 e2e", diff --git a/src/plugins/logger.js b/src/plugins/logger.js index e1d27f7a0..1bef55cc7 100644 --- a/src/plugins/logger.js +++ b/src/plugins/logger.js @@ -1,18 +1,20 @@ // Credits: borrowed code from fcomb/redux-logger +import { deepCopy } from '../util' + export default function createLogger ({ collapsed = true, transformer = state => state, mutationTransformer = mut => mut } = {}) { return store => { - let prevState = JSON.parse(JSON.stringify(store.state)) + let prevState = deepCopy(store.state) store.subscribe((mutation, state) => { if (typeof console === 'undefined') { return } - const nextState = JSON.parse(JSON.stringify(state)) + const nextState = deepCopy(state) const time = new Date() const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}` const formattedMutation = mutationTransformer(mutation) diff --git a/src/util.js b/src/util.js index fea7d5e46..c8729791a 100644 --- a/src/util.js +++ b/src/util.js @@ -25,6 +25,54 @@ export function mergeObjects (arr) { }, {}) } +/** + * Get the first item that pass the test + * by second argument function + * + * @param {Array} list + * @param {Function} f + * @return {*} + */ +function find (list, f) { + return list.filter(f)[0] +} + +/** + * Deep copy the given object considering circular structure. + * This function caches all nested objects and its copies. + * If it detects circular structure, use cached copy to avoid infinite loop. + * + * @param {*} obj + * @param {Array} cache + * @return {*} + */ +export function deepCopy (obj, cache = []) { + // just return if obj is immutable value + if (obj === null || typeof obj !== 'object') { + return obj + } + + // if obj is hit, it is in circular structure + const hit = find(cache, c => c.original === obj) + if (hit) { + return hit.copy + } + + const copy = Array.isArray(obj) ? [] : {} + // put the copy into cache at first + // because we want to refer it in recursive deepCopy + cache.push({ + original: obj, + copy + }) + + Object.keys(obj).forEach(key => { + copy[key] = deepCopy(obj[key], cache) + }) + + return copy +} + /** * Check whether the given value is Object or not * diff --git a/test/unit/util.js b/test/unit/util.js new file mode 100644 index 000000000..1ce62fea3 --- /dev/null +++ b/test/unit/util.js @@ -0,0 +1,42 @@ +import { expect } from 'chai' +import { deepCopy } from '../../src/util' + +describe('util', () => { + it('deepCopy: nornal structure', () => { + const original = { + a: 1, + b: 'string', + c: true, + d: null, + e: undefined + } + const copy = deepCopy(original) + + expect(copy).to.deep.equal(original) + }) + + it('deepCopy: nested structure', () => { + const original = { + a: { + b: 1, + c: [2, 3, { + d: 4 + }] + } + } + const copy = deepCopy(original) + + expect(copy).to.deep.equal(original) + }) + + it('deepCopy: circular structure', () => { + const original = { + a: 1 + } + original.circular = original + + const copy = deepCopy(original) + + expect(copy).to.deep.equal(original) + }) +}) From ae778eef11d393a255124333ef3edb84af194837 Mon Sep 17 00:00:00 2001 From: Niall O'Brien Date: Fri, 23 Sep 2016 00:07:25 +0100 Subject: [PATCH 11/12] Adds an additional example (#307) Adds an example that explains how to use Vuex in the context of building a realtime app with Feathers.js on the backend. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 230cd3c4d..9b8be7563 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [Documentation](http://vuejs.github.io/vuex/) - [Great introduction and explanation by @skyronic](http://skyronic.com/2016/01/03/vuex-basics-tutorial/) (using outdated 0.3.0 API, but still worth a read!) - [Vuex introduction video - James Browne from London Vue.js Meetup #1](https://www.youtube.com/watch?v=l1KHL-TX3qs) +- [Feathers.js example using Vue.js and Vuex on the client to maintain state](https://github.com/niallobrien/feathers-chat-example) by [Niall O'Brien](https://github.com/niallobrien) (Twitter: [@niall_obrien](https://twitter.com/niall_obrien)) ## Examples From 84a503e29387e975fde353b0e3703065ceb6884e Mon Sep 17 00:00:00 2001 From: Hiroaki Ninomiya Date: Tue, 21 Feb 2017 00:13:50 +0900 Subject: [PATCH 12/12] Fix indent (#644) --- docs/ja/state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/state.md b/docs/ja/state.md index a72cf5d7e..1dd58c789 100644 --- a/docs/ja/state.md +++ b/docs/ja/state.md @@ -13,7 +13,7 @@ Vuex は**単一ステートツリー (single state tree)**を使います。つ ``` js // Vue コンポーネントの定義 computed: { -count: function() { + count: function() { return store.state.count } }