Skip to content

Commit 5ff35a4

Browse files
committed
Merge branch 'dev' of github.com:vuejs/vue into extend-inject
2 parents 1c4439e + 13bb643 commit 5ff35a4

File tree

13 files changed

+445
-306
lines changed

13 files changed

+445
-306
lines changed

.eslintrc

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
{
22
"root": true,
3-
"parser": "babel-eslint",
4-
"extends": "vue",
5-
"plugins": ["flowtype"],
3+
"plugins": [
4+
"flowtype"
5+
],
6+
"extends": [
7+
"plugin:vue-libs/recommended",
8+
"plugin:flowtype/recommended"
9+
],
610
"globals": {
711
"__WEEX__": true
8-
},
9-
"rules": {
10-
"no-useless-escape": 0,
11-
"flowtype/define-flow-type": 1,
12-
"flowtype/use-flow-type": 1
1312
}
1413
}

.github/ISSUE_TEMPLATE.md

+3
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ IMPORTANT: Please use the following link to create a new issue:
44
https://new-issue.vuejs.org/
55
66
If your issue was not created using the app above, it will be closed immediately.
7+
8+
中文用户请注意:
9+
请使用上面的链接来创建新的 issue。如果不是用上述工具创建的 issue 会被自动关闭。
710
-->

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,10 @@
7171
"de-indent": "^1.0.2",
7272
"es6-promise": "^4.0.5",
7373
"eslint": "^3.10.1",
74-
"eslint-config-vue": "^2.0.1",
7574
"eslint-loader": "^1.3.0",
7675
"eslint-plugin-flowtype": "^2.16.0",
7776
"eslint-plugin-jasmine": "^2.1.0",
78-
"eslint-plugin-vue": "^2.0.0",
77+
"eslint-plugin-vue-libs": "^1.2.0",
7978
"file-loader": "^0.10.1",
8079
"flow-bin": "^0.45.0",
8180
"hash-sum": "^1.0.2",

src/core/global-api/use.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import { toArray } from '../util/index'
44

55
export function initUse (Vue: GlobalAPI) {
66
Vue.use = function (plugin: Function | Object) {
7-
/* istanbul ignore if */
8-
if (plugin.installed) {
7+
const cid = this.cid
8+
if (!plugin._installed) {
9+
plugin._installed = {}
10+
}
11+
if (plugin._installed[cid]) {
912
return this
1013
}
1114
// additional parameters
@@ -16,7 +19,7 @@ export function initUse (Vue: GlobalAPI) {
1619
} else if (typeof plugin === 'function') {
1720
plugin.apply(null, args)
1821
}
19-
plugin.installed = true
22+
plugin._installed[cid] = true
2023
return this
2124
}
2225
}

src/core/observer/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
198198
target[key] = val
199199
return val
200200
}
201-
const ob = (target : any).__ob__
201+
const ob = (target: any).__ob__
202202
if (target._isVue || (ob && ob.vmCount)) {
203203
process.env.NODE_ENV !== 'production' && warn(
204204
'Avoid adding reactive properties to a Vue instance or its root $data ' +
@@ -223,7 +223,7 @@ export function del (target: Array<any> | Object, key: any) {
223223
target.splice(key, 1)
224224
return
225225
}
226-
const ob = (target : any).__ob__
226+
const ob = (target: any).__ob__
227227
if (target._isVue || (ob && ob.vmCount)) {
228228
process.env.NODE_ENV !== 'production' && warn(
229229
'Avoid deleting properties on a Vue instance or its root $data ' +

src/core/util/env.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if (inBrowser) {
2626
/* istanbul ignore next */
2727
supportsPassive = true
2828
}
29-
} : Object)) // https://github.com/facebook/flow/issues/285
29+
}: Object)) // https://github.com/facebook/flow/issues/285
3030
window.addEventListener('test-passive', null, opts)
3131
} catch (e) {}
3232
}

src/platforms/web/runtime/components/transition.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,23 @@ function isSameChild (child: VNode, oldChild: VNode): boolean {
7272
return oldChild.key === child.key && oldChild.tag === child.tag
7373
}
7474

75+
function isAsyncPlaceholder (node: VNode): boolean {
76+
return node.isComment && node.asyncFactory
77+
}
78+
7579
export default {
7680
name: 'transition',
7781
props: transitionProps,
7882
abstract: true,
7983

8084
render (h: Function) {
81-
let children: ?Array<VNode> = this.$slots.default
85+
let children: ?Array<VNode> = this.$options._renderChildren
8286
if (!children) {
8387
return
8488
}
8589

8690
// filter out text nodes (possible whitespaces)
87-
children = children.filter((c: VNode) => c.tag)
91+
children = children.filter((c: VNode) => c.tag || isAsyncPlaceholder(c))
8892
/* istanbul ignore if */
8993
if (!children.length) {
9094
return
@@ -151,7 +155,12 @@ export default {
151155
child.data.show = true
152156
}
153157

154-
if (oldChild && oldChild.data && !isSameChild(child, oldChild)) {
158+
if (
159+
oldChild &&
160+
oldChild.data &&
161+
!isSameChild(child, oldChild) &&
162+
!isAsyncPlaceholder(oldChild)
163+
) {
155164
// replace old child transition data with fresh one
156165
// important for dynamic transitions!
157166
const oldData: Object = oldChild && (oldChild.data.transition = extend({}, data))
@@ -165,6 +174,9 @@ export default {
165174
})
166175
return placeholder(h, rawChild)
167176
} else if (mode === 'in-out') {
177+
if (isAsyncPlaceholder(child)) {
178+
return oldRawChild
179+
}
168180
let delayedLeave
169181
const performLeave = () => { delayedLeave() }
170182
mergeVNodeHook(data, 'afterEnter', performLeave)

src/platforms/web/util/element.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const isHTMLTag = makeMap(
1919
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
2020
'output,progress,select,textarea,' +
2121
'details,dialog,menu,menuitem,summary,' +
22-
'content,element,shadow,template'
22+
'content,element,shadow,template,blockquote,iframe,tfoot'
2323
)
2424

2525
// this map is intentionally selective, only covering SVG elements that may

src/platforms/weex/compiler/modules/props.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { cached, camelize } from 'shared/util'
44

55
const normalize = cached(camelize)
66

7-
function normalizeKeyName (str: string) : string {
7+
function normalizeKeyName (str: string): string {
88
if (str.match(/^v\-/)) {
99
return str.replace(/(v-[a-z\-]+\:)([a-z\-]+)$/i, ($, directive, prop) => {
1010
return directive + normalize(prop)

test/helpers/test-object-option.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Vue from 'vue'
22

3-
export default function testObjectOption (name: string) {
3+
export default function testObjectOption (name) {
44
it('should warn non object', () => {
55
const options = {}
66
options[name] = () => {}

test/unit/features/global-api/use.spec.js

+12
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,23 @@ describe('Global API: use', () => {
1414
Vue.use(pluginStub, options)
1515
expect(Vue.options.directives['plugin-test']).toBe(def)
1616
delete Vue.options.directives['plugin-test']
17+
expect(Vue.options.directives['plugin-test']).toBeUndefined()
18+
19+
// should not double apply
20+
Vue.use(pluginStub, options)
21+
expect(Vue.options.directives['plugin-test']).toBeUndefined()
1722
})
1823

1924
it('should apply Function plugin', () => {
2025
Vue.use(pluginStub.install, options)
2126
expect(Vue.options.directives['plugin-test']).toBe(def)
2227
delete Vue.options.directives['plugin-test']
2328
})
29+
30+
it('should work on extended constructors without polluting the base', () => {
31+
const Ctor = Vue.extend({})
32+
Ctor.use(pluginStub, options)
33+
expect(Vue.options.directives['plugin-test']).toBeUndefined()
34+
expect(Ctor.options.directives['plugin-test']).toBe(def)
35+
})
2436
})

test/unit/features/transition/transition.spec.js

+181
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,187 @@ if (!isIE9) {
877877
expect(`<transition> can only be used on a single element`).toHaveBeenWarned()
878878
})
879879

880+
it('transition out-in on async component (resolve before leave complete)', done => {
881+
const vm = new Vue({
882+
template: `
883+
<div>
884+
<transition name="test-anim" mode="out-in">
885+
<component-a v-if="ok"></component-a>
886+
<component-b v-else></component-b>
887+
</transition>
888+
</div>
889+
`,
890+
components: {
891+
componentA: resolve => {
892+
setTimeout(() => {
893+
resolve({ template: '<div><h1>component A</h1></div>' })
894+
next1()
895+
}, duration / 2)
896+
},
897+
componentB: resolve => {
898+
setTimeout(() => {
899+
resolve({ template: '<div><h1>component B</h1></div>' })
900+
}, duration / 2)
901+
}
902+
},
903+
data: {
904+
ok: true
905+
}
906+
}).$mount(el)
907+
908+
expect(vm.$el.innerHTML).toBe('<!---->')
909+
910+
function next1 () {
911+
Vue.nextTick(() => {
912+
expect(vm.$el.children.length).toBe(1)
913+
expect(vm.$el.textContent).toBe('component A')
914+
expect(vm.$el.children[0].className).toBe('test-anim-enter test-anim-enter-active')
915+
nextFrame(() => {
916+
expect(vm.$el.children[0].className).toBe('test-anim-enter-active test-anim-enter-to')
917+
setTimeout(() => {
918+
expect(vm.$el.children[0].className).toBe('')
919+
vm.ok = false
920+
next2()
921+
}, duration + buffer)
922+
})
923+
})
924+
}
925+
926+
function next2 () {
927+
waitForUpdate(() => {
928+
expect(vm.$el.children.length).toBe(1)
929+
expect(vm.$el.textContent).toBe('component A')
930+
expect(vm.$el.children[0].className).toBe('test-anim-leave test-anim-leave-active')
931+
}).thenWaitFor(nextFrame).then(() => {
932+
expect(vm.$el.children[0].className).toBe('test-anim-leave-active test-anim-leave-to')
933+
}).thenWaitFor(duration + buffer).then(() => {
934+
expect(vm.$el.children.length).toBe(1)
935+
expect(vm.$el.textContent).toBe('component B')
936+
expect(vm.$el.children[0].className).toBe('test-anim-enter-active test-anim-enter-to')
937+
}).thenWaitFor(duration + buffer).then(() => {
938+
expect(vm.$el.children[0].className).toBe('')
939+
}).then(done)
940+
}
941+
})
942+
943+
it('transition out-in on async component (resolve after leave complete)', done => {
944+
const vm = new Vue({
945+
template: `
946+
<div>
947+
<transition name="test-anim" mode="out-in">
948+
<component-a v-if="ok"></component-a>
949+
<component-b v-else></component-b>
950+
</transition>
951+
</div>
952+
`,
953+
components: {
954+
componentA: { template: '<div><h1>component A</h1></div>' },
955+
componentB: resolve => {
956+
setTimeout(() => {
957+
resolve({ template: '<div><h1>component B</h1></div>' })
958+
Vue.nextTick(next)
959+
}, (duration + buffer) * 1.5)
960+
}
961+
},
962+
data: {
963+
ok: true
964+
}
965+
}).$mount(el)
966+
967+
expect(vm.$el.innerHTML).toBe('<div><h1>component A</h1></div>')
968+
969+
let next
970+
971+
vm.ok = false
972+
waitForUpdate(() => {
973+
expect(vm.$el.children.length).toBe(1)
974+
expect(vm.$el.textContent).toBe('component A')
975+
expect(vm.$el.children[0].className).toBe('test-anim-leave test-anim-leave-active')
976+
}).thenWaitFor(nextFrame).then(() => {
977+
expect(vm.$el.children[0].className).toBe('test-anim-leave-active test-anim-leave-to')
978+
}).thenWaitFor(duration + buffer).then(() => {
979+
expect(vm.$el.children.length).toBe(0)
980+
expect(vm.$el.innerHTML).toBe('<!---->')
981+
}).thenWaitFor(_next => { next = _next }).then(() => {
982+
expect(vm.$el.children.length).toBe(1)
983+
expect(vm.$el.textContent).toBe('component B')
984+
expect(vm.$el.children[0].className).toBe('test-anim-enter test-anim-enter-active')
985+
}).thenWaitFor(nextFrame).then(() => {
986+
expect(vm.$el.children[0].className).toBe('test-anim-enter-active test-anim-enter-to')
987+
}).thenWaitFor(duration + buffer).then(() => {
988+
expect(vm.$el.children.length).toBe(1)
989+
expect(vm.$el.textContent).toBe('component B')
990+
expect(vm.$el.children[0].className).toBe('')
991+
}).then(done)
992+
})
993+
994+
it('transition in-out on async component', done => {
995+
const vm = new Vue({
996+
template: `
997+
<div>
998+
<transition name="test-anim" mode="in-out">
999+
<component-a v-if="ok"></component-a>
1000+
<component-b v-else></component-b>
1001+
</transition>
1002+
</div>
1003+
`,
1004+
components: {
1005+
componentA: resolve => {
1006+
setTimeout(() => {
1007+
resolve({ template: '<div><h1>component A</h1></div>' })
1008+
next1()
1009+
}, duration / 2)
1010+
},
1011+
componentB: resolve => {
1012+
setTimeout(() => {
1013+
resolve({ template: '<div><h1>component B</h1></div>' })
1014+
next2()
1015+
}, duration / 2)
1016+
}
1017+
},
1018+
data: {
1019+
ok: true
1020+
}
1021+
}).$mount(el)
1022+
1023+
expect(vm.$el.innerHTML).toBe('<!---->')
1024+
1025+
function next1 () {
1026+
Vue.nextTick(() => {
1027+
expect(vm.$el.children.length).toBe(1)
1028+
expect(vm.$el.textContent).toBe('component A')
1029+
expect(vm.$el.children[0].className).toBe('test-anim-enter test-anim-enter-active')
1030+
nextFrame(() => {
1031+
expect(vm.$el.children[0].className).toBe('test-anim-enter-active test-anim-enter-to')
1032+
setTimeout(() => {
1033+
expect(vm.$el.children[0].className).toBe('')
1034+
vm.ok = false
1035+
}, duration + buffer)
1036+
})
1037+
})
1038+
}
1039+
1040+
function next2 () {
1041+
waitForUpdate(() => {
1042+
expect(vm.$el.children.length).toBe(2)
1043+
expect(vm.$el.textContent).toBe('component Acomponent B')
1044+
expect(vm.$el.children[0].className).toBe('')
1045+
expect(vm.$el.children[1].className).toBe('test-anim-enter test-anim-enter-active')
1046+
}).thenWaitFor(nextFrame).then(() => {
1047+
expect(vm.$el.children[1].className).toBe('test-anim-enter-active test-anim-enter-to')
1048+
}).thenWaitFor(duration + buffer).then(() => {
1049+
expect(vm.$el.children.length).toBe(2)
1050+
expect(vm.$el.textContent).toBe('component Acomponent B')
1051+
expect(vm.$el.children[0].className).toBe('test-anim-leave-active test-anim-leave-to')
1052+
expect(vm.$el.children[1].className).toBe('')
1053+
}).thenWaitFor(duration + buffer).then(() => {
1054+
expect(vm.$el.children.length).toBe(1)
1055+
expect(vm.$el.textContent).toBe('component B')
1056+
expect(vm.$el.children[0].className).toBe('')
1057+
}).then(done)
1058+
}
1059+
})
1060+
8801061
describe('explicit durations -', () => {
8811062
it('single value', done => {
8821063
const vm = new Vue({

0 commit comments

Comments
 (0)