weex-vue-framework
Advanced tools
Comparing version 0.1.7 to 0.1.8
{ | ||
"name": "weex-vue-framework", | ||
"version": "0.1.7", | ||
"version": "0.1.8", | ||
"description": "Vue 2.0 Framework for Weex", | ||
@@ -9,22 +9,25 @@ "main": "dist/weex.common.js", | ||
"dist/weex.common.js.map", | ||
"dist/weex.compiler.js", | ||
"dist/weex.common.min.js", | ||
"src" | ||
], | ||
"scripts": { | ||
"dev:vue": "webpack --watch --config build/webpack.dist.dev.config.js", | ||
"dev": "webpack --watch --config build/webpack.weex.dev.config.js", | ||
"dev": "TARGET=weex-runtime-dev rollup -w -c build/config.js", | ||
"dev:compiler": "TARGET=weex-compiler rollup -w -c build/config.js", | ||
"dev:test": "karma start build/karma.dev.config.js", | ||
"dev:ssr": "webpack --watch --config build/webpack.ssr.dev.config.js", | ||
"dev:compiler": "webpack --watch --config build/webpack.compiler.dev.config.js", | ||
"build": "NODE_ENV=production node build/build.js weex.common.js,weex.compiler.js", | ||
"dev:ssr": "TARGET=web-server-renderer rollup -w -c build/config.js", | ||
"dev:web": "TARGET=web-standalone-dev rollup -w -c build/config.js", | ||
"dev:web:runtime": "TARGET=web-runtime-dev rollup -w -c build/config.js", | ||
"dev:web:compiler": "TARGET=web-compiler rollup -w -c build/config.js", | ||
"build": "node build/build.js", | ||
"build:ssr": "npm run build -- vue.common.js,vue-server-renderer", | ||
"test": "npm run lint && flow check && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr", | ||
"test:unit": "NODE_ENV=development karma start build/karma.unit.config.js", | ||
"test:cover": "NODE_ENV=development karma start build/karma.cover.config.js", | ||
"test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr", | ||
"test:unit": "karma start build/karma.unit.config.js", | ||
"test:cover": "karma start build/karma.cover.config.js", | ||
"test:e2e": "npm run build -- vue.js && node test/e2e/runner.js", | ||
"test:ssr": "npm run build:ssr && NODE_ENV=development VUE_ENV=server jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.json", | ||
"test:ssr": "npm run build:ssr && VUE_ENV=server jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.json", | ||
"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2", | ||
"test:types": "tsc -p ./types/test/tsconfig.json", | ||
"lint": "eslint src build test", | ||
"flow": "flow check", | ||
"sauce": "NODE_ENV=development SAUCE=true karma start build/karma.sauce.config.js", | ||
"sauce": "SAUCE=true karma start build/karma.sauce.config.js", | ||
"bench:ssr": "npm run build:ssr && NODE_ENV=production VUE_ENV=server node benchmarks/ssr/renderToString.js && NODE_ENV=production VUE_ENV=server node benchmarks/ssr/renderToStream.js", | ||
@@ -52,4 +55,4 @@ "release": "bash build/release.sh" | ||
"babel-preset-es2015": "^6.9.0", | ||
"babel-preset-es2015-rollup-vue": "^1.1.0", | ||
"babel-preset-flow-vue": "^1.0.0", | ||
"buble": "^0.13.1", | ||
"chromedriver": "^2.21.2", | ||
@@ -60,12 +63,15 @@ "codecov.io": "^0.1.6", | ||
"entities": "^1.1.1", | ||
"eslint": "^2.11.0", | ||
"eslint-config-vue": "^1.0.3", | ||
"es6-promise": "^3.2.1", | ||
"eslint": "^3.4.0", | ||
"eslint-config-vue": "^1.1.0", | ||
"eslint-loader": "^1.3.0", | ||
"eslint-plugin-flow-vars": "^0.4.0", | ||
"flow-bin": "^0.27.0", | ||
"eslint-plugin-flow-vars": "^0.5.0", | ||
"eslint-plugin-html": "^1.5.2", | ||
"flow-bin": "^0.31.1", | ||
"flow-remove-types": "github:yyx990803/flow-remove-types", | ||
"http-server": "^0.9.0", | ||
"jasmine": "^2.4.1", | ||
"jasmine-core": "^2.4.1", | ||
"jasmine": "2.4.x", | ||
"jasmine-core": "2.4.x", | ||
"karma": "^1.1.0", | ||
"karma-chrome-launcher": "^1.0.1", | ||
"karma-chrome-launcher": "^2.0.0", | ||
"karma-coverage": "^1.0.0", | ||
@@ -84,9 +90,12 @@ "karma-firefox-launcher": "^1.0.0", | ||
"phantomjs-prebuilt": "^2.1.1", | ||
"rollup": "^0.33.0", | ||
"rollup": "^0.34.10", | ||
"rollup-plugin-alias": "^1.2.0", | ||
"rollup-plugin-babel": "^2.4.0", | ||
"rollup-plugin-buble": "^0.13.0", | ||
"rollup-plugin-replace": "^1.1.0", | ||
"selenium-server": "2.53.0", | ||
"rollup-watch": "^2.5.0", | ||
"selenium-server": "2.53.1", | ||
"typescript": "^2.0.2", | ||
"uglify-js": "^2.6.2", | ||
"webpack": "^1.13.1" | ||
"webpack": "^1.13.2" | ||
}, | ||
@@ -93,0 +102,0 @@ "dependencies": { |
# Vue with Weex Platform | ||
*Note: This branch is checked out from `next` from `Vue` and it won't change the source code of `Vue`, just updates platform entries and build files only.* | ||
# vue-next [![CircleCI](https://img.shields.io/circleci/project/vuejs/vue/next.svg?maxAge=2592000)](https://circleci.com/gh/vuejs/vue/tree/next) [![Coverage](https://img.shields.io/codecov/c/github/vuejs/vue/next.svg)](https://codecov.io/gh/vuejs/vue/branch/next) [![Sauce Labs](https://saucelabs.com/open_sauce/build_status/vuejs.svg)](https://saucelabs.com/beta/builds/03f78da5c56a4e61bb80c61f1c01d7d8) | ||
### Current status: BETA | ||
Checkout the [2.0 Changes](https://github.com/vuejs/vue/issues/2873) issue or the [WIP documentation](https://github.com/vuejs/vuejs.org/tree/2.0/src/guide). | ||
### Build | ||
``` bash | ||
npm install | ||
npm run build | ||
``` |
@@ -44,18 +44,25 @@ /* @flow */ | ||
} else { | ||
let code = 'function($event){' | ||
let code = '' | ||
const keys = [] | ||
for (const key in handler.modifiers) { | ||
code += modifierCode[key] || genKeyFilter(key) | ||
if (modifierCode[key]) { | ||
code += modifierCode[key] | ||
} else { | ||
keys.push(key) | ||
} | ||
} | ||
if (keys.length) { | ||
code = genKeyFilter(keys) + code | ||
} | ||
const handlerCode = simplePathRE.test(handler.value) | ||
? handler.value + '($event)' | ||
: handler.value | ||
return code + handlerCode + '}' | ||
return 'function($event){' + code + handlerCode + '}' | ||
} | ||
} | ||
function genKeyFilter (key: string): string { | ||
const code = | ||
parseInt(key, 10) || // number keyCode | ||
keyCodes[key] || // built-in alias | ||
`_k(${JSON.stringify(key)})` // custom alias | ||
function genKeyFilter (keys: Array<string>): string { | ||
const code = keys.length === 1 | ||
? normalizeKeyCode(keys[0]) | ||
: Array.prototype.concat.apply([], keys.map(normalizeKeyCode)) | ||
if (Array.isArray(code)) { | ||
@@ -67,1 +74,9 @@ return `if(${code.map(c => `$event.keyCode!==${c}`).join('&&')})return;` | ||
} | ||
function normalizeKeyCode (key) { | ||
return ( | ||
parseInt(key, 10) || // number keyCode | ||
keyCodes[key] || // built-in alias | ||
`_k(${JSON.stringify(key)})` // custom alias | ||
) | ||
} |
@@ -6,3 +6,2 @@ /* @flow */ | ||
import baseDirectives from '../directives/index' | ||
import { no } from 'shared/util' | ||
@@ -14,3 +13,2 @@ // configurable state | ||
let platformDirectives | ||
let isPlatformReservedTag | ||
let staticRenderFns | ||
@@ -34,5 +32,3 @@ let currentOptions | ||
platformDirectives = options.directives || {} | ||
isPlatformReservedTag = options.isReservedTag || no | ||
const code = ast ? genElement(ast) : '_h("div")' | ||
// console.log(code) | ||
staticRenderFns = prevStaticRenderFns | ||
@@ -50,3 +46,3 @@ return { | ||
staticRenderFns.push(`with(this){return ${genElement(el)}}`) | ||
return `_m(${staticRenderFns.length - 1})` | ||
return `_m(${staticRenderFns.length - 1}${el.staticInFor ? ',true' : ''})` | ||
} else if (el.for && !el.forProcessed) { | ||
@@ -67,7 +63,3 @@ return genFor(el) | ||
const data = genData(el) | ||
// if the element is potentially a component, | ||
// wrap its children as a thunk. | ||
const children = !el.inlineTemplate | ||
? genChildren(el, !isPlatformReservedTag(el.tag) /* asThunk */) | ||
: null | ||
const children = el.inlineTemplate ? null : genChildren(el) | ||
code = `_h('${el.tag}'${ | ||
@@ -83,6 +75,2 @@ data ? `,${data}` : '' // data | ||
} | ||
// check keep-alive | ||
if (el.keepAlive) { | ||
code = `_h("KeepAlive",{props:{child:${code}}})` | ||
} | ||
return code | ||
@@ -92,3 +80,3 @@ } | ||
function genIf (el: ASTElement): string { | ||
function genIf (el: any): string { | ||
const exp = el.if | ||
@@ -102,6 +90,6 @@ el.ifProcessed = true // avoid recursion | ||
? genElement(el.elseBlock) | ||
: 'void 0' | ||
: '_e()' | ||
} | ||
function genFor (el: ASTElement): string { | ||
function genFor (el: any): string { | ||
const exp = el.for | ||
@@ -153,7 +141,2 @@ const alias = el.alias | ||
} | ||
// v-show, used to avoid transition being applied | ||
// since v-show takes it over | ||
if (el.attrsMap['v-show']) { | ||
data += 'show:true,' | ||
} | ||
// attributes | ||
@@ -176,3 +159,3 @@ if (el.attrs) { | ||
if (el.nativeEvents) { | ||
data += `${genHandlers(el.nativeEvents, true)}` | ||
data += `${genHandlers(el.nativeEvents, true)},` | ||
} | ||
@@ -230,10 +213,6 @@ // inline-template | ||
function genChildren (el: ASTElement, asThunk?: boolean): string | void { | ||
if (!el.children.length) { | ||
return | ||
function genChildren (el: ASTElement): string | void { | ||
if (el.children.length) { | ||
return '[' + el.children.map(genNode).join(',') + ']' | ||
} | ||
const code = '[' + el.children.map(genNode).join(',') + ']' | ||
return asThunk | ||
? `function(){return ${code}}` | ||
: code | ||
} | ||
@@ -256,11 +235,11 @@ | ||
function genSlot (el: ASTElement): string { | ||
const slot = `$slots[${el.slotName || '"default"'}]` | ||
const slotName = el.slotName || '"default"' | ||
const children = genChildren(el) | ||
return children | ||
? `(${slot}||${children})` | ||
: slot | ||
? `_t(${slotName},${children})` | ||
: `_t(${slotName})` | ||
} | ||
function genComponent (el: ASTElement): string { | ||
const children = genChildren(el, true) | ||
function genComponent (el: any): string { | ||
const children = genChildren(el) | ||
return `_h(${el.component},${genData(el)}${ | ||
@@ -267,0 +246,0 @@ children ? `,${children}` : '' |
@@ -49,3 +49,4 @@ /* @flow */ | ||
value: string, | ||
modifiers: ?{ [key: string]: true } | ||
modifiers: ?{ [key: string]: true }, | ||
important: ?boolean | ||
) { | ||
@@ -68,5 +69,5 @@ // check capture modifier | ||
if (Array.isArray(handlers)) { | ||
handlers.push(newHandler) | ||
important ? handlers.unshift(newHandler) : handlers.push(newHandler) | ||
} else if (handlers) { | ||
events[name] = [handlers, newHandler] | ||
events[name] = important ? [newHandler, handlers] : [handlers, newHandler] | ||
} else { | ||
@@ -73,0 +74,0 @@ events[name] = newHandler |
@@ -28,3 +28,3 @@ /* @flow */ | ||
// second pass: mark static roots. | ||
markStaticRoots(root) | ||
markStaticRoots(root, false) | ||
} | ||
@@ -52,11 +52,14 @@ | ||
function markStaticRoots (node: ASTNode) { | ||
if (node.type === 1 && (node.once || node.static)) { | ||
node.staticRoot = true | ||
return | ||
} | ||
if (node.children) { | ||
for (let i = 0, l = node.children.length; i < l; i++) { | ||
markStaticRoots(node.children[i]) | ||
function markStaticRoots (node: ASTNode, isInFor: boolean) { | ||
if (node.type === 1) { | ||
if (node.once || node.static) { | ||
node.staticRoot = true | ||
node.staticInFor = isInFor | ||
return | ||
} | ||
if (node.children) { | ||
for (let i = 0, l = node.children.length; i < l; i++) { | ||
markStaticRoots(node.children[i], !!node.for) | ||
} | ||
} | ||
} | ||
@@ -63,0 +66,0 @@ } |
@@ -54,2 +54,3 @@ /** | ||
const gtRE = />/g | ||
const quoteRE = /"/g | ||
@@ -60,3 +61,3 @@ function decodeAttr (value, shouldDecodeTags) { | ||
} | ||
return value.replace(ampRE, '&') | ||
return value.replace(ampRE, '&').replace(quoteRE, '"') | ||
} | ||
@@ -135,6 +136,6 @@ | ||
} else { | ||
const stackedTag = lastTag.toLowerCase() | ||
const reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i')) | ||
let endTagLength = 0 | ||
const rest = html.replace(reStackedTag, function (all, text, endTag) { | ||
var stackedTag = lastTag.toLowerCase() | ||
var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i')) | ||
var endTagLength = 0 | ||
var rest = html.replace(reStackedTag, function (all, text, endTag) { | ||
endTagLength = endTag.length | ||
@@ -141,0 +142,0 @@ if (stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript') { |
@@ -88,6 +88,6 @@ /* @flow */ | ||
if (isForbiddenTag(element)) { | ||
if (process.env.VUE_ENV !== 'server' && isForbiddenTag(element)) { | ||
element.forbidden = true | ||
process.env.NODE_ENV !== 'production' && warn( | ||
'Templates should only be responsbile for mapping the state to the ' + | ||
'Templates should only be responsible for mapping the state to the ' + | ||
'UI. Avoid placing tags with side-effects in your templates, such as ' + | ||
@@ -269,10 +269,3 @@ `<${tag}>.` | ||
el.ref = ref | ||
let parent = el | ||
while (parent) { | ||
if (parent.for !== undefined) { | ||
el.refInFor = true | ||
break | ||
} | ||
parent = parent.parent | ||
} | ||
el.refInFor = checkInFor(el) | ||
} | ||
@@ -350,5 +343,2 @@ } | ||
} | ||
if (getAndRemoveAttr(el, 'keep-alive') != null) { | ||
el.keepAlive = true | ||
} | ||
if (getAndRemoveAttr(el, 'inline-template') != null) { | ||
@@ -414,2 +404,13 @@ el.inlineTemplate = true | ||
function checkInFor (el: ASTElement): boolean { | ||
let parent = el | ||
while (parent) { | ||
if (parent.for !== undefined) { | ||
return true | ||
} | ||
parent = parent.parent | ||
} | ||
return false | ||
} | ||
function parseModifiers (name: string): Object | void { | ||
@@ -416,0 +417,0 @@ const match = name.match(modifierRE) |
@@ -6,3 +6,3 @@ /* @flow */ | ||
const defaultTagRE = /\{\{((?:.|\\n)+?)\}\}/g | ||
const defaultTagRE = /\{\{((?:.|\n)+?)\}\}/g | ||
const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g | ||
@@ -9,0 +9,0 @@ |
import { callHook } from 'core/instance/lifecycle' | ||
import { getRealChild } from 'core/vdom/helpers' | ||
import { getFirstComponentChild } from 'core/vdom/helpers' | ||
@@ -7,5 +7,2 @@ export default { | ||
abstract: true, | ||
props: { | ||
child: Object | ||
}, | ||
created () { | ||
@@ -15,18 +12,18 @@ this.cache = Object.create(null) | ||
render () { | ||
const rawChild = this.child | ||
const realChild = getRealChild(this.child) | ||
if (realChild && realChild.componentOptions) { | ||
const opts = realChild.componentOptions | ||
// same constructor may get registered as different local components | ||
// so cid alone is not enough (#3269) | ||
const key = opts.Ctor.cid + '::' + opts.tag | ||
const vnode = getFirstComponentChild(this.$slots.default) | ||
if (vnode && vnode.componentOptions) { | ||
const opts = vnode.componentOptions | ||
const key = vnode.key == null | ||
// same constructor may get registered as different local components | ||
// so cid alone is not enough (#3269) | ||
? opts.Ctor.cid + '::' + opts.tag | ||
: vnode.key | ||
if (this.cache[key]) { | ||
const child = realChild.child = this.cache[key].child | ||
realChild.elm = this.$el = child.$el | ||
vnode.child = this.cache[key].child | ||
} else { | ||
this.cache[key] = realChild | ||
this.cache[key] = vnode | ||
} | ||
realChild.data.keepAlive = true | ||
vnode.data.keepAlive = true | ||
} | ||
return rawChild | ||
return vnode | ||
}, | ||
@@ -33,0 +30,0 @@ destroyed () { |
@@ -11,4 +11,4 @@ import config from './config' | ||
Vue.version = '2.0.0-beta.5' | ||
Vue.version = '0.1.8' | ||
export default Vue |
@@ -7,3 +7,6 @@ /* @flow */ | ||
import { warn, validateProp, remove, noop } from '../util/index' | ||
import { resolveSlots } from './render' | ||
export let activeInstance: any = null | ||
export function initLifecycle (vm: Component) { | ||
@@ -80,3 +83,7 @@ const options = vm.$options | ||
const prevEl = vm.$el | ||
if (!vm._vnode) { | ||
const prevActiveInstance = activeInstance | ||
activeInstance = vm | ||
const prevVnode = vm._vnode | ||
vm._vnode = vnode | ||
if (!prevVnode) { | ||
// Vue.prototype.__patch__ is injected in entry points | ||
@@ -86,5 +93,5 @@ // based on the rendering backend used. | ||
} else { | ||
vm.$el = vm.__patch__(vm._vnode, vnode) | ||
vm.$el = vm.__patch__(prevVnode, vnode) | ||
} | ||
vm._vnode = vnode | ||
activeInstance = prevActiveInstance | ||
// update __vue__ reference | ||
@@ -113,2 +120,3 @@ if (prevEl) { | ||
const vm: Component = this | ||
const hasChildren = !!(vm.$options._renderChildren || renderChildren) | ||
vm.$options._parentVnode = parentVnode | ||
@@ -138,2 +146,7 @@ vm.$options._renderChildren = renderChildren | ||
} | ||
// resolve slots + force update if has children | ||
if (hasChildren) { | ||
vm.$slots = resolveSlots(renderChildren) | ||
vm.$forceUpdate() | ||
} | ||
} | ||
@@ -146,7 +159,2 @@ | ||
} | ||
if (vm._watchers.length) { | ||
for (let i = 0; i < vm._watchers.length; i++) { | ||
vm._watchers[i].update(true /* shallow */) | ||
} | ||
} | ||
} | ||
@@ -153,0 +161,0 @@ |
@@ -12,3 +12,3 @@ /* not type checking this file because flow doesn't play well with Proxy */ | ||
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + | ||
'require,__webpack_require__' // for Webpack/Browserify | ||
'require' // for Webpack/Browserify | ||
) | ||
@@ -23,11 +23,12 @@ | ||
const has = key in target | ||
const isAllowedGlobal = allowedGlobals(key) | ||
if (!has && !isAllowedGlobal) { | ||
const isAllowed = allowedGlobals(key) || key.charAt(0) === '_' | ||
if (!has && !isAllowed) { | ||
warn( | ||
`Trying to access non-existent property "${key}" while rendering. ` + | ||
`Make sure to declare reactive data properties in the data option.`, | ||
`Property or method "${key}" is not defined on the instance but ` + | ||
`referenced during render. Make sure to declare reactive data ` + | ||
`properties in the data option.`, | ||
target | ||
) | ||
} | ||
return !isAllowedGlobal | ||
return has || !isAllowed | ||
} | ||
@@ -34,0 +35,0 @@ } |
/* @flow */ | ||
import config from '../config' | ||
import VNode, { emptyVNode } from '../vdom/vnode' | ||
import VNode, { emptyVNode, cloneVNode, cloneVNodes } from '../vdom/vnode' | ||
import { normalizeChildren } from '../vdom/helpers' | ||
@@ -13,8 +13,2 @@ import { | ||
export const renderState: { | ||
activeInstance: ?Component | ||
} = { | ||
activeInstance: null | ||
} | ||
export function initRender (vm: Component) { | ||
@@ -24,3 +18,3 @@ vm.$vnode = null // the placeholder node in parent tree | ||
vm._staticTrees = null | ||
vm.$slots = {} | ||
vm.$slots = resolveSlots(vm.$options._renderChildren) | ||
// bind the public createElement fn to this instance | ||
@@ -41,11 +35,5 @@ // so that we get proper render context inside it. | ||
const vm: Component = this | ||
// set current active instance | ||
const prev = renderState.activeInstance | ||
renderState.activeInstance = vm | ||
const { | ||
render, | ||
staticRenderFns, | ||
_renderChildren, | ||
_parentVnode | ||
@@ -60,5 +48,2 @@ } = vm.$options | ||
vm.$vnode = _parentVnode | ||
// resolve slots. becaues slots are rendered in parent scope, | ||
// we set the activeInstance to parent. | ||
vm.$slots = resolveSlots(_renderChildren) | ||
// render self | ||
@@ -98,4 +83,2 @@ let vnode | ||
vnode.parent = _parentVnode | ||
// restore render state | ||
renderState.activeInstance = prev | ||
return vnode | ||
@@ -110,11 +93,28 @@ } | ||
Vue.prototype._n = toNumber | ||
// empty vnode | ||
Vue.prototype._e = emptyVNode | ||
// render static tree by index | ||
Vue.prototype._m = function renderStatic (index?: number): Object | void { | ||
Vue.prototype._m = function renderStatic ( | ||
index: number, | ||
isInFor?: boolean | ||
): VNode | Array<VNode> { | ||
let tree = this._staticTrees[index] | ||
if (!tree) { | ||
tree = this._staticTrees[index] = this.$options.staticRenderFns[index].call( | ||
this._renderProxy | ||
) | ||
// if has already-rendered static tree and not inside v-for, | ||
// we can reuse the same tree by doing a shallow clone. | ||
if (tree && !isInFor) { | ||
return Array.isArray(tree) | ||
? cloneVNodes(tree) | ||
: cloneVNode(tree) | ||
} | ||
// otherwise, render a fresh tree. | ||
tree = this._staticTrees[index] = this.$options.staticRenderFns[index].call(this._renderProxy) | ||
if (Array.isArray(tree)) { | ||
for (let i = 0; i < tree.length; i++) { | ||
tree[i].isStatic = true | ||
tree[i].key = `__static__${index}_${i}` | ||
} | ||
} else { | ||
tree.isStatic = true | ||
tree.key = `__static__${index}` | ||
} | ||
@@ -157,2 +157,26 @@ return tree | ||
// renderSlot | ||
Vue.prototype._t = function ( | ||
name: string, | ||
fallback: ?Array<VNode> | ||
): ?Array<VNode> { | ||
let slotNodes = this.$slots[name] | ||
if (slotNodes) { | ||
// warn duplicate slot usage | ||
if (process.env.NODE_ENV !== 'production') { | ||
slotNodes._rendered && warn( | ||
`Duplicate presense of slot "${name}" found in the same render tree ` + | ||
`- this will likely cause render errors.`, | ||
this | ||
) | ||
slotNodes._rendered = true | ||
} | ||
// clone slot nodes on re-renders | ||
if (this._isMounted) { | ||
slotNodes = cloneVNodes(slotNodes) | ||
} | ||
} | ||
return slotNodes || fallback | ||
} | ||
// apply v-bind object | ||
@@ -173,8 +197,12 @@ Vue.prototype._b = function bindProps ( | ||
} | ||
const data = vnode.data | ||
const data: any = vnode.data | ||
for (const key in value) { | ||
const hash = asProp || config.mustUseProp(key) | ||
? data.domProps || (data.domProps = {}) | ||
: data.attrs || (data.attrs = {}) | ||
hash[key] = value[key] | ||
if (key === 'class' || key === 'style') { | ||
data[key] = value[key] | ||
} else { | ||
const hash = asProp || config.mustUseProp(key) | ||
? data.domProps || (data.domProps = {}) | ||
: data.attrs || (data.attrs = {}) | ||
hash[key] = value[key] | ||
} | ||
} | ||
@@ -191,3 +219,5 @@ } | ||
export function resolveSlots (renderChildren: any): Object { | ||
export function resolveSlots ( | ||
renderChildren: ?VNodeChildren | ||
): { [key: string]: Array<VNode> } { | ||
const slots = {} | ||
@@ -217,3 +247,3 @@ if (!renderChildren) { | ||
defaultSlot.length === 1 && | ||
defaultSlot[0].text === ' ' | ||
(defaultSlot[0].text === ' ' || defaultSlot[0].isComment) | ||
)) { | ||
@@ -220,0 +250,0 @@ slots.default = defaultSlot |
@@ -7,2 +7,4 @@ /* @flow */ | ||
import { | ||
set, | ||
del, | ||
observe, | ||
@@ -196,2 +198,5 @@ defineReactive, | ||
Vue.prototype.$set = set | ||
Vue.prototype.$delete = del | ||
Vue.prototype.$watch = function ( | ||
@@ -198,0 +203,0 @@ expOrFn: string | Function, |
@@ -203,3 +203,3 @@ /* @flow */ | ||
'Avoid adding reactive properties to a Vue instance or its root $data ' + | ||
'at runtime - delcare it upfront in the data option.' | ||
'at runtime - declare it upfront in the data option.' | ||
) | ||
@@ -206,0 +206,0 @@ return |
@@ -29,3 +29,3 @@ import config from '../config' | ||
if (str === 'anonymous component') { | ||
str += ` - use the "name" option for better debugging messages.)` | ||
str += ` - use the "name" option for better debugging messages.` | ||
} | ||
@@ -32,0 +32,0 @@ return `(found in ${str})` |
@@ -54,5 +54,5 @@ /* @flow */ | ||
if (typeof MutationObserver !== 'undefined' && !hasMutationObserverBug) { | ||
let counter = 1 | ||
const observer = new MutationObserver(nextTickHandler) | ||
const textNode = document.createTextNode(String(counter)) | ||
var counter = 1 | ||
var observer = new MutationObserver(nextTickHandler) | ||
var textNode = document.createTextNode(String(counter)) | ||
observer.observe(textNode, { | ||
@@ -69,3 +69,3 @@ characterData: true | ||
// avoid bundling unnecessary code. | ||
const context = inBrowser | ||
var context = inBrowser | ||
? window | ||
@@ -72,0 +72,0 @@ : typeof global !== 'undefined' ? global : {} |
@@ -39,3 +39,3 @@ /* @flow */ | ||
strats.name = function (parent, child, vm) { | ||
if (vm) { | ||
if (vm && child) { | ||
warn( | ||
@@ -42,0 +42,0 @@ 'options "name" can only be used as a component definition option, ' + |
@@ -26,3 +26,3 @@ /* @flow */ | ||
// handle boolean props | ||
if (prop.type === Boolean) { | ||
if (getType(prop.type) === 'Boolean') { | ||
if (absent && !hasOwn(prop, 'default')) { | ||
@@ -135,23 +135,16 @@ value = false | ||
let valid | ||
let expectedType | ||
if (type === String) { | ||
expectedType = 'string' | ||
valid = typeof value === expectedType | ||
} else if (type === Number) { | ||
expectedType = 'number' | ||
valid = typeof value === expectedType | ||
} else if (type === Boolean) { | ||
expectedType = 'boolean' | ||
valid = typeof value === expectedType | ||
} else if (type === Function) { | ||
expectedType = 'function' | ||
valid = typeof value === expectedType | ||
} else if (type === Object) { | ||
expectedType = 'Object' | ||
let expectedType = getType(type) | ||
if (expectedType === 'String') { | ||
valid = typeof value === (expectedType = 'string') | ||
} else if (expectedType === 'Number') { | ||
valid = typeof value === (expectedType = 'number') | ||
} else if (expectedType === 'Boolean') { | ||
valid = typeof value === (expectedType = 'boolean') | ||
} else if (expectedType === 'Function') { | ||
valid = typeof value === (expectedType = 'function') | ||
} else if (expectedType === 'Object') { | ||
valid = isPlainObject(value) | ||
} else if (type === Array) { | ||
expectedType = 'Array' | ||
} else if (expectedType === 'Array') { | ||
valid = Array.isArray(value) | ||
} else { | ||
expectedType = type.name || type.toString() | ||
valid = value instanceof type | ||
@@ -164,1 +157,11 @@ } | ||
} | ||
/** | ||
* Use function string name to check built-in types, | ||
* because a simple equality check will fail when running | ||
* across different vms / iframes. | ||
*/ | ||
function getType (fn) { | ||
const match = fn && fn.toString().match(/^\s*function (\w+)/) | ||
return match && match[1] | ||
} |
@@ -6,3 +6,3 @@ /* @flow */ | ||
import { normalizeChildren } from './helpers' | ||
import { callHook } from '../instance/lifecycle' | ||
import { activeInstance, callHook } from '../instance/lifecycle' | ||
import { resolveSlots } from '../instance/render' | ||
@@ -17,18 +17,6 @@ import { warn, isObject, hasOwn, hyphenate, validateProp } from '../util/index' | ||
data?: VNodeData, | ||
parent: Component, | ||
context: Component, | ||
host: ?Component, | ||
children?: VNodeChildren, | ||
tag?: string | ||
): VNode | void { | ||
// ensure children is a thunk | ||
if (process.env.NODE_ENV !== 'production' && | ||
children && typeof children !== 'function') { | ||
warn( | ||
'A component\'s children should be a function that returns the ' + | ||
'children array. This allows the component to track the children ' + | ||
'dependencies and optimizes re-rendering.' | ||
) | ||
} | ||
if (!Ctor) { | ||
@@ -44,3 +32,3 @@ return | ||
if (process.env.NODE_ENV !== 'production') { | ||
warn(`Invalid Component definition: ${Ctor}`, parent) | ||
warn(`Invalid Component definition: ${String(Ctor)}`, context) | ||
} | ||
@@ -57,5 +45,4 @@ return | ||
// it's ok to queue this on every render because | ||
// $forceUpdate is buffered. this is only called | ||
// if the | ||
parent.$forceUpdate() | ||
// $forceUpdate is buffered by the scheduler. | ||
context.$forceUpdate() | ||
}) | ||
@@ -77,20 +64,3 @@ if (!Ctor) { | ||
if (Ctor.options.functional) { | ||
const props = {} | ||
const propOptions = Ctor.options.props | ||
if (propOptions) { | ||
Object.keys(propOptions).forEach(key => { | ||
props[key] = validateProp(key, propOptions, propsData) | ||
}) | ||
} | ||
return Ctor.options.render.call( | ||
null, | ||
parent.$createElement, | ||
{ | ||
props, | ||
parent, | ||
data, | ||
children: () => normalizeChildren(children), | ||
slots: () => resolveSlots(children) | ||
} | ||
) | ||
return createFunctionalComponent(Ctor, propsData, data, context, children) | ||
} | ||
@@ -117,4 +87,4 @@ | ||
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`, | ||
data, undefined, undefined, undefined, undefined, context, host, | ||
{ Ctor, propsData, listeners, parent, tag, children } | ||
data, undefined, undefined, undefined, undefined, context, | ||
{ Ctor, propsData, listeners, tag, children } | ||
) | ||
@@ -124,4 +94,32 @@ return vnode | ||
function createFunctionalComponent ( | ||
Ctor: Class<Component>, | ||
propsData: ?Object, | ||
data: VNodeData, | ||
context: Component, | ||
children?: VNodeChildren | ||
): VNode | void { | ||
const props = {} | ||
const propOptions = Ctor.options.props | ||
if (propOptions) { | ||
for (const key in propOptions) { | ||
props[key] = validateProp(key, propOptions, propsData) | ||
} | ||
} | ||
return Ctor.options.render.call( | ||
null, | ||
context.$createElement, | ||
{ | ||
props, | ||
data, | ||
parent: context, | ||
children: normalizeChildren(children), | ||
slots: () => resolveSlots(children) | ||
} | ||
) | ||
} | ||
export function createComponentInstanceForVnode ( | ||
vnode: any // we know it's MountedComponentVNode but flow doesn't | ||
vnode: any, // we know it's MountedComponentVNode but flow doesn't | ||
parent: any // activeInstance in lifecycle state | ||
): Component { | ||
@@ -131,3 +129,3 @@ const vnodeComponentOptions = vnode.componentOptions | ||
_isComponent: true, | ||
parent: vnodeComponentOptions.parent, | ||
parent, | ||
propsData: vnodeComponentOptions.propsData, | ||
@@ -149,4 +147,4 @@ _componentTag: vnodeComponentOptions.tag, | ||
function init (vnode: VNodeWithData, hydrating: boolean) { | ||
if (!vnode.child) { | ||
const child = vnode.child = createComponentInstanceForVnode(vnode) | ||
if (!vnode.child || vnode.child._isDestroyed) { | ||
const child = vnode.child = createComponentInstanceForVnode(vnode, activeInstance) | ||
child.$mount(hydrating ? vnode.elm : undefined, hydrating) | ||
@@ -168,6 +166,2 @@ } | ||
) | ||
// always update abstract components. | ||
if (child.$options.abstract) { | ||
child.$forceUpdate() | ||
} | ||
} | ||
@@ -208,26 +202,32 @@ | ||
let sync = true | ||
factory( | ||
// resolve | ||
(res: Object | Class<Component>) => { | ||
if (isObject(res)) { | ||
res = Vue.extend(res) | ||
const resolve = (res: Object | Class<Component>) => { | ||
if (isObject(res)) { | ||
res = Vue.extend(res) | ||
} | ||
// cache resolved | ||
factory.resolved = res | ||
// invoke callbacks only if this is not a synchronous resolve | ||
// (async resolves are shimmed as synchronous during SSR) | ||
if (!sync) { | ||
for (let i = 0, l = cbs.length; i < l; i++) { | ||
cbs[i](res) | ||
} | ||
// cache resolved | ||
factory.resolved = res | ||
// invoke callbacks only if this is not a synchronous resolve | ||
// (async resolves are shimmed as synchronous during SSR) | ||
if (!sync) { | ||
for (let i = 0, l = cbs.length; i < l; i++) { | ||
cbs[i](res) | ||
} | ||
} | ||
}, | ||
// reject | ||
reason => { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
`Failed to resolve async component: ${factory}` + | ||
(reason ? `\nReason: ${reason}` : '') | ||
) | ||
} | ||
) | ||
} | ||
const reject = reason => { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
`Failed to resolve async component: ${String(factory)}` + | ||
(reason ? `\nReason: ${reason}` : '') | ||
) | ||
} | ||
const res = factory(resolve, reject) | ||
// handle promise | ||
if (res && typeof res.then === 'function' && !factory.resolved) { | ||
res.then(resolve, reject) | ||
} | ||
sync = false | ||
@@ -234,0 +234,0 @@ // return in case resolved synchronously |
@@ -7,3 +7,2 @@ /* @flow */ | ||
import { normalizeChildren } from './helpers' | ||
import { renderState } from '../instance/render' | ||
import { warn, resolveAsset } from '../util/index' | ||
@@ -17,3 +16,3 @@ | ||
children: any | ||
): VNode | Array<VNode> | void { | ||
): VNode | void { | ||
if (data && (Array.isArray(data) || typeof data !== 'object')) { | ||
@@ -32,12 +31,3 @@ children = data | ||
children?: VNodeChildren | void | ||
): VNode | Array<VNode> | void { | ||
const parent: ?Component = renderState.activeInstance | ||
const host = context !== parent ? parent : undefined | ||
if (!parent) { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
'createElement cannot be called outside of component ' + | ||
'render functions.' | ||
) | ||
return | ||
} | ||
): VNode | void { | ||
if (data && data.__ob__) { | ||
@@ -62,7 +52,7 @@ process.env.NODE_ENV !== 'production' && warn( | ||
tag, data, normalizeChildren(children, ns), | ||
undefined, undefined, ns, context, host | ||
undefined, undefined, ns, context | ||
) | ||
} else if ((Ctor = resolveAsset(context.$options, 'components', tag))) { | ||
// component | ||
return createComponent(Ctor, data, parent, context, host, children, tag) | ||
return createComponent(Ctor, data, context, children, tag) | ||
} else { | ||
@@ -74,3 +64,3 @@ // unknown or unlisted namespaced elements | ||
tag, data, normalizeChildren(children, ns), | ||
undefined, undefined, ns, context, host | ||
undefined, undefined, ns, context | ||
) | ||
@@ -80,4 +70,4 @@ } | ||
// direct component options / constructor | ||
return createComponent(tag, data, parent, context, host, children) | ||
return createComponent(tag, data, context, children) | ||
} | ||
} |
/* @flow */ | ||
import { isPrimitive } from '../util/index' | ||
import { isPrimitive, warn } from '../util/index' | ||
import VNode from './vnode' | ||
@@ -8,10 +8,5 @@ | ||
children: any, | ||
ns: string | void | ||
ns: string | void, | ||
nestedIndex: number | void | ||
): Array<VNode> | void { | ||
// invoke children thunks. | ||
// components always receive their children as thunks so that they | ||
// can perform the actual render inside their own dependency collection cycle. | ||
if (typeof children === 'function') { | ||
children = children() | ||
} | ||
if (isPrimitive(children)) { | ||
@@ -27,7 +22,7 @@ return [createTextVNode(children)] | ||
if (Array.isArray(c)) { | ||
res.push.apply(res, normalizeChildren(c, ns)) | ||
res.push.apply(res, normalizeChildren(c, ns, i)) | ||
} else if (isPrimitive(c)) { | ||
if (last && last.text) { | ||
last.text += String(c) | ||
} else { | ||
} else if (c !== '') { | ||
// convert primitive to vnode | ||
@@ -44,2 +39,6 @@ res.push(createTextVNode(c)) | ||
} | ||
// default key for nested array children (likely generated by v-for) | ||
if (c.key == null && nestedIndex != null) { | ||
c.key = `__vlist_${nestedIndex}_${i}__` | ||
} | ||
res.push(c) | ||
@@ -68,11 +67,4 @@ } | ||
// in case the child is also an abstract component, e.g. <transition-control> | ||
// we want to recrusively retrieve the real component to be rendered | ||
export function getRealChild (vnode: ?VNode): ?VNode { | ||
const compOptions = vnode && vnode.componentOptions | ||
if (compOptions && compOptions.Ctor.options.abstract) { | ||
return getRealChild(compOptions.propsData && compOptions.propsData.child) | ||
} else { | ||
return vnode | ||
} | ||
export function getFirstComponentChild (children: ?Array<any>) { | ||
return children && children.filter(c => c && c.componentOptions)[0] | ||
} | ||
@@ -83,5 +75,9 @@ | ||
if (oldHook) { | ||
def[key] = function () { | ||
oldHook.apply(this, arguments) | ||
hook.apply(this, arguments) | ||
const injectedHash = def.__injected || (def.__injected = {}) | ||
if (!injectedHash[key]) { | ||
injectedHash[key] = true | ||
def[key] = function () { | ||
oldHook.apply(this, arguments) | ||
hook.apply(this, arguments) | ||
} | ||
} | ||
@@ -103,3 +99,7 @@ } else { | ||
old = oldOn[name] | ||
if (!old) { | ||
if (!cur) { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
`Handler for event "${name}" is undefined.` | ||
) | ||
} else if (!old) { | ||
capture = name.charAt(0) === '!' | ||
@@ -110,14 +110,19 @@ event = capture ? name.slice(1) : name | ||
} else { | ||
fn = cur | ||
cur = on[name] = {} | ||
cur.fn = fn | ||
add(event, (cur.invoker = fnInvoker(cur)), capture) | ||
if (!cur.invoker) { | ||
fn = cur | ||
cur = on[name] = {} | ||
cur.fn = fn | ||
cur.invoker = fnInvoker(cur) | ||
} | ||
add(event, cur.invoker, capture) | ||
} | ||
} else if (Array.isArray(old)) { | ||
old.length = cur.length | ||
for (let i = 0; i < old.length; i++) old[i] = cur[i] | ||
on[name] = old | ||
} else { | ||
old.fn = cur | ||
on[name] = old | ||
} else if (cur !== old) { | ||
if (Array.isArray(old)) { | ||
old.length = cur.length | ||
for (let i = 0; i < old.length; i++) old[i] = cur[i] | ||
on[name] = old | ||
} else { | ||
old.fn = cur | ||
on[name] = old | ||
} | ||
} | ||
@@ -124,0 +129,0 @@ } |
/* @flow */ | ||
import { resolveAsset } from 'core/util/options' | ||
import { mergeVNodeHook } from 'core/vdom/helpers' | ||
export default { | ||
create: function bindDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
applyDirectives(oldVnode, vnode, 'bind') | ||
let hasInsert = false | ||
forEachDirective(oldVnode, vnode, (def, dir) => { | ||
callHook(def, dir, 'bind', vnode, oldVnode) | ||
if (def.inserted) { | ||
hasInsert = true | ||
} | ||
}) | ||
if (hasInsert) { | ||
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', () => { | ||
applyDirectives(oldVnode, vnode, 'inserted') | ||
}) | ||
} | ||
}, | ||
update: function updateDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
applyDirectives(oldVnode, vnode, 'update') | ||
// if old vnode has directives but new vnode doesn't | ||
// we need to teardown the directives on the old one. | ||
if (oldVnode.data.directives && !vnode.data.directives) { | ||
applyDirectives(oldVnode, oldVnode, 'unbind') | ||
} | ||
}, | ||
@@ -22,17 +39,15 @@ postpatch: function postupdateDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
function applyDirectives ( | ||
function forEachDirective ( | ||
oldVnode: VNodeWithData, | ||
vnode: VNodeWithData, | ||
hook: string | ||
fn: Function | ||
) { | ||
const dirs = vnode.data.directives | ||
if (dirs) { | ||
const oldDirs = oldVnode.data.directives | ||
const isUpdate = hook === 'update' | ||
for (let i = 0; i < dirs.length; i++) { | ||
const dir = dirs[i] | ||
const def = resolveAsset(vnode.context.$options, 'directives', dir.name, true) | ||
const fn = def && def[hook] | ||
if (fn) { | ||
if (isUpdate && oldDirs) { | ||
if (def) { | ||
const oldDirs = oldVnode && oldVnode.data.directives | ||
if (oldDirs) { | ||
dir.oldValue = oldDirs[i].value | ||
@@ -43,3 +58,3 @@ } | ||
} | ||
fn(vnode.elm, dir, vnode, oldVnode) | ||
fn(def, dir) | ||
} | ||
@@ -49,1 +64,18 @@ } | ||
} | ||
function applyDirectives ( | ||
oldVnode: VNodeWithData, | ||
vnode: VNodeWithData, | ||
hook: string | ||
) { | ||
forEachDirective(oldVnode, vnode, (def, dir) => { | ||
callHook(def, dir, hook, vnode, oldVnode) | ||
}) | ||
} | ||
function callHook (def, dir, hook, vnode, oldVnode) { | ||
const fn = def && def[hook] | ||
if (fn) { | ||
fn(vnode.elm, dir, vnode, oldVnode) | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
/* flow */ | ||
/* @flow */ | ||
@@ -6,6 +6,6 @@ import { remove } from 'shared/util' | ||
export default { | ||
create (_, vnode) { | ||
create (_: any, vnode: VNodeWithData) { | ||
registerRef(vnode) | ||
}, | ||
update (oldVnode, vnode) { | ||
update (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (oldVnode.data.ref !== vnode.data.ref) { | ||
@@ -16,3 +16,3 @@ registerRef(oldVnode, true) | ||
}, | ||
destroy (vnode) { | ||
destroy (vnode: VNodeWithData) { | ||
registerRef(vnode, true) | ||
@@ -22,3 +22,3 @@ } | ||
function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) { | ||
export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) { | ||
const key = vnode.data.ref | ||
@@ -25,0 +25,0 @@ if (!key) return |
/** | ||
* Virtual DOM implementation based on Snabbdom by | ||
* Virtual DOM patching algorithm based on Snabbdom by | ||
* Simon Friis Vindum (@paldepind) | ||
* with custom modifications. | ||
* Licensed under the MIT License | ||
* https://github.com/paldepind/snabbdom/blob/master/LICENSE | ||
* | ||
* modified by Evan You (@yyx990803) | ||
* | ||
/* | ||
* Not type-checking this because this file is perf-critical and the cost | ||
@@ -13,2 +18,4 @@ * of making flow understand it is not worth it. | ||
import { isPrimitive, _toString, warn } from '../util/index' | ||
import { activeInstance } from '../instance/lifecycle' | ||
import { registerRef } from './modules/ref' | ||
@@ -28,8 +35,6 @@ const emptyData = {} | ||
function sameVnode (vnode1, vnode2) { | ||
if (vnode1.isStatic || vnode2.isStatic) { | ||
return vnode1 === vnode2 | ||
} | ||
return ( | ||
vnode1.key === vnode2.key && | ||
vnode1.tag === vnode2.tag && | ||
vnode1.isComment === vnode2.isComment && | ||
!vnode1.data === !vnode2.data | ||
@@ -81,5 +86,6 @@ ) | ||
function createElm (vnode, insertedVnodeQueue) { | ||
let i, elm | ||
function createElm (vnode, insertedVnodeQueue, nested) { | ||
let i | ||
const data = vnode.data | ||
vnode.isRootInsert = !nested | ||
if (isDef(data)) { | ||
@@ -92,8 +98,3 @@ if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode) | ||
if (isDef(i = vnode.child)) { | ||
if (vnode.data.pendingInsert) { | ||
insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert) | ||
} | ||
vnode.elm = vnode.child.$el | ||
invokeCreateHooks(vnode, insertedVnodeQueue) | ||
setScope(vnode) | ||
initComponent(vnode, insertedVnodeQueue) | ||
return vnode.elm | ||
@@ -119,18 +120,14 @@ } | ||
} | ||
elm = vnode.elm = vnode.ns | ||
vnode.elm = vnode.ns | ||
? nodeOps.createElementNS(vnode.ns, tag) | ||
: nodeOps.createElement(tag) | ||
setScope(vnode) | ||
if (Array.isArray(children)) { | ||
for (i = 0; i < children.length; ++i) { | ||
nodeOps.appendChild(elm, createElm(children[i], insertedVnodeQueue)) | ||
} | ||
} else if (isPrimitive(vnode.text)) { | ||
nodeOps.appendChild(elm, nodeOps.createTextNode(vnode.text)) | ||
} | ||
createChildren(vnode, children, insertedVnodeQueue) | ||
if (isDef(data)) { | ||
invokeCreateHooks(vnode, insertedVnodeQueue) | ||
} | ||
} else if (vnode.isComment) { | ||
vnode.elm = nodeOps.createComment(vnode.text) | ||
} else { | ||
elm = vnode.elm = nodeOps.createTextNode(vnode.text) | ||
vnode.elm = nodeOps.createTextNode(vnode.text) | ||
} | ||
@@ -140,2 +137,19 @@ return vnode.elm | ||
function createChildren (vnode, children, insertedVnodeQueue) { | ||
if (Array.isArray(children)) { | ||
for (let i = 0; i < children.length; ++i) { | ||
nodeOps.appendChild(vnode.elm, createElm(children[i], insertedVnodeQueue, true)) | ||
} | ||
} else if (isPrimitive(vnode.text)) { | ||
nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(vnode.text)) | ||
} | ||
} | ||
function isPatchable (vnode) { | ||
while (vnode.child) { | ||
vnode = vnode.child._vnode | ||
} | ||
return isDef(vnode.tag) | ||
} | ||
function invokeCreateHooks (vnode, insertedVnodeQueue) { | ||
@@ -152,2 +166,19 @@ for (let i = 0; i < cbs.create.length; ++i) { | ||
function initComponent (vnode, insertedVnodeQueue) { | ||
if (vnode.data.pendingInsert) { | ||
insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert) | ||
} | ||
vnode.elm = vnode.child.$el | ||
if (isPatchable(vnode)) { | ||
invokeCreateHooks(vnode, insertedVnodeQueue) | ||
setScope(vnode) | ||
} else { | ||
// empty component root. | ||
// skip all element-related modules except for ref (#3455) | ||
registerRef(vnode) | ||
// make sure to invoke the insert hook | ||
insertedVnodeQueue.push(vnode) | ||
} | ||
} | ||
// set scope id attribute for scoped CSS. | ||
@@ -158,6 +189,8 @@ // this is implemented as a special case to avoid the overhead | ||
let i | ||
if (isDef(i = vnode.host) && isDef(i = i.$options._scopeId)) { | ||
if (isDef(i = vnode.context) && isDef(i = i.$options._scopeId)) { | ||
nodeOps.setAttribute(vnode.elm, i, '') | ||
} | ||
if (isDef(i = vnode.context) && isDef(i = i.$options._scopeId)) { | ||
if (isDef(i = activeInstance) && | ||
i !== vnode.context && | ||
isDef(i = i.$options._scopeId)) { | ||
nodeOps.setAttribute(vnode.elm, i, '') | ||
@@ -195,4 +228,4 @@ } | ||
if (isDef(ch.tag)) { | ||
removeAndInvokeRemoveHook(ch) | ||
invokeDestroyHook(ch) | ||
removeAndInvokeRemoveHook(ch) | ||
} else { // Text node | ||
@@ -274,8 +307,4 @@ nodeOps.removeChild(parentElm, ch.elm) | ||
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) | ||
idxInOld = isDef(newStartVnode.key) | ||
? oldKeyToIdx[newStartVnode.key] | ||
: newStartVnode.isStatic | ||
? oldCh.indexOf(newStartVnode) | ||
: null | ||
if (isUndef(idxInOld) || idxInOld === -1) { // New element | ||
idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null | ||
if (isUndef(idxInOld)) { // New element | ||
nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm) | ||
@@ -314,3 +343,16 @@ newStartVnode = newCh[++newStartIdx] | ||
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) { | ||
if (oldVnode === vnode) return | ||
if (oldVnode === vnode) { | ||
return | ||
} | ||
// reuse element for static trees. | ||
// note we only do this if the vnode is cloned - | ||
// if the new node is not cloned it means the render functions have been | ||
// reset by the hot-reload-api and we need to do a proper re-render. | ||
if (vnode.isStatic && | ||
oldVnode.isStatic && | ||
vnode.key === oldVnode.key && | ||
vnode.isCloned) { | ||
vnode.elm = oldVnode.elm | ||
return | ||
} | ||
let i, hook | ||
@@ -324,3 +366,3 @@ const hasData = isDef(i = vnode.data) | ||
const ch = vnode.children | ||
if (hasData) { | ||
if (hasData && isPatchable(vnode)) { | ||
for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode) | ||
@@ -361,2 +403,3 @@ if (isDef(hook) && isDef(i = hook.update)) i(oldVnode, vnode) | ||
let bailed = false | ||
function hydrate (elm, vnode, insertedVnodeQueue) { | ||
@@ -374,3 +417,3 @@ if (process.env.NODE_ENV !== 'production') { | ||
// child component. it should have hydrated its own tree. | ||
invokeCreateHooks(vnode, insertedVnodeQueue) | ||
initComponent(vnode, insertedVnodeQueue) | ||
return true | ||
@@ -382,5 +425,25 @@ } | ||
const childNodes = nodeOps.childNodes(elm) | ||
for (let i = 0; i < children.length; i++) { | ||
const success = hydrate(childNodes[i], children[i], insertedVnodeQueue) | ||
if (!success) { | ||
// empty element, allow client to pick up and populate children | ||
if (!childNodes.length) { | ||
createChildren(vnode, children, insertedVnodeQueue) | ||
} else { | ||
let childrenMatch = true | ||
if (childNodes.length !== children.length) { | ||
childrenMatch = false | ||
} else { | ||
for (let i = 0; i < children.length; i++) { | ||
if (!hydrate(childNodes[i], children[i], insertedVnodeQueue)) { | ||
childrenMatch = false | ||
break | ||
} | ||
} | ||
} | ||
if (!childrenMatch) { | ||
if (process.env.NODE_ENV !== 'production' && | ||
typeof console !== 'undefined' && | ||
!bailed) { | ||
bailed = true | ||
console.warn('Parent: ', elm) | ||
console.warn('Mismatching childNodes vs. VNodes: ', childNodes, children) | ||
} | ||
return false | ||
@@ -398,20 +461,10 @@ } | ||
function assertNodeMatch (node, vnode) { | ||
let match = true | ||
if (!node) { | ||
match = false | ||
} else if (vnode.tag) { | ||
match = | ||
if (vnode.tag) { | ||
return ( | ||
vnode.tag.indexOf('vue-component') === 0 || | ||
vnode.tag === nodeOps.tagName(node).toLowerCase() | ||
) | ||
} else { | ||
match = _toString(vnode.text) === node.data | ||
return _toString(vnode.text) === node.data | ||
} | ||
if (process.env.NODE_ENV !== 'production' && !match) { | ||
warn( | ||
'The client-side rendered virtual DOM tree is not matching ' + | ||
'server-rendered content. Bailing hydration and performing ' + | ||
'full client-side render.' | ||
) | ||
} | ||
return match | ||
} | ||
@@ -437,3 +490,3 @@ | ||
// a successful hydration. | ||
if (oldVnode.hasAttribute('server-rendered')) { | ||
if (oldVnode.nodeType === 1 && oldVnode.hasAttribute('server-rendered')) { | ||
oldVnode.removeAttribute('server-rendered') | ||
@@ -446,2 +499,10 @@ hydrating = true | ||
return oldVnode | ||
} else if (process.env.NODE_ENV !== 'production') { | ||
warn( | ||
'The client-side rendered virtual DOM tree is not matching ' + | ||
'server-rendered content. This is likely caused by incorrect ' + | ||
'HTML markup, for example nesting block-level elements inside ' + | ||
'<p>, or missing <tbody>. Bailing hydration and performing ' + | ||
'full client-side render.' | ||
) | ||
} | ||
@@ -462,4 +523,6 @@ } | ||
vnode.parent.elm = vnode.elm | ||
for (let i = 0; i < cbs.create.length; ++i) { | ||
cbs.create[i](emptyNode, vnode.parent) | ||
if (isPatchable(vnode)) { | ||
for (let i = 0; i < cbs.create.length; ++i) { | ||
cbs.create[i](emptyNode, vnode.parent) | ||
} | ||
} | ||
@@ -466,0 +529,0 @@ } |
@@ -10,10 +10,12 @@ /* @flow */ | ||
ns: string | void; | ||
context: Component | void; | ||
host: ?Component; | ||
context: Component | void; // rendered in this component's scope | ||
key: string | number | void; | ||
componentOptions: VNodeComponentOptions | void; | ||
child: Component | void; | ||
parent: VNode | void; | ||
raw: ?boolean; | ||
isStatic: ?boolean; | ||
child: Component | void; // component instance | ||
parent: VNode | void; // compoennt placeholder node | ||
raw: boolean; // contains raw HTML? (server only) | ||
isStatic: boolean; // hoisted static node | ||
isRootInsert: boolean; // necessary for enter transition check | ||
isComment: boolean; // empty comment placeholder? | ||
isCloned: boolean; // is a cloned node? | ||
@@ -28,3 +30,2 @@ constructor ( | ||
context?: Component, | ||
host?: ?Component, | ||
componentOptions?: VNodeComponentOptions | ||
@@ -39,3 +40,2 @@ ) { | ||
this.context = context | ||
this.host = host | ||
this.key = data && data.key | ||
@@ -47,2 +47,5 @@ this.componentOptions = componentOptions | ||
this.isStatic = false | ||
this.isRootInsert = true | ||
this.isComment = false | ||
this.isCloned = false | ||
// apply construct hook. | ||
@@ -58,2 +61,36 @@ // this is applied during render, before patch happens. | ||
export const emptyVNode = () => new VNode(undefined, undefined, undefined, '') | ||
export const emptyVNode = () => { | ||
const node = new VNode() | ||
node.text = '' | ||
node.isComment = true | ||
return node | ||
} | ||
// optimized shallow clone | ||
// used for static nodes and slot nodes because they may be reused across | ||
// multiple renders, cloning them avoids errors when DOM manipulations rely | ||
// on their elm reference. | ||
export function cloneVNode (vnode: VNode): VNode { | ||
const cloned = new VNode( | ||
vnode.tag, | ||
vnode.data, | ||
vnode.children, | ||
vnode.text, | ||
vnode.elm, | ||
vnode.ns, | ||
vnode.context, | ||
vnode.componentOptions | ||
) | ||
cloned.isStatic = vnode.isStatic | ||
cloned.key = vnode.key | ||
cloned.isCloned = true | ||
return cloned | ||
} | ||
export function cloneVNodes (vnodes: Array<VNode>): Array<VNode> { | ||
const res = new Array(vnodes.length) | ||
for (let i = 0; i < vnodes.length; i++) { | ||
res[i] = cloneVNode(vnodes[i]) | ||
} | ||
return res | ||
} |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { extend } from 'shared/util' | ||
@@ -15,5 +17,6 @@ import { compile as baseCompile, baseOptions } from 'web/compiler/index' | ||
// allow injecting modules/directives | ||
const baseModules = baseOptions.modules || [] | ||
const modules = options.modules | ||
? baseOptions.modules.concat(options.modules) | ||
: baseOptions.modules | ||
? baseModules.concat(options.modules) | ||
: baseModules | ||
const directives = options.directives | ||
@@ -20,0 +23,0 @@ ? extend(extend({}, baseOptions.directives), options.directives) |
@@ -19,2 +19,11 @@ /* @flow */ | ||
el = el && query(el) | ||
/* istanbul ignore if */ | ||
if (el === document.body || el === document.documentElement) { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
`Do not mount Vue to <html> or <body> - mount to normal elements instead.` | ||
) | ||
return this | ||
} | ||
const options = this.$options | ||
@@ -21,0 +30,0 @@ // resolve template/el and convert to render function |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { extend } from 'shared/util' | ||
@@ -2,0 +4,0 @@ import { compile as baseCompile, baseOptions } from 'weex/compiler/index' |
/* @flow */ | ||
import { isIE } from 'web/util/index' | ||
import { addHandler, addProp, getBindingAttr } from 'compiler/helpers' | ||
@@ -15,19 +16,16 @@ | ||
const modifiers = dir.modifiers | ||
if (el.tag === 'select') { | ||
const tag = el.tag | ||
const type = el.attrsMap.type | ||
if (tag === 'select') { | ||
return genSelect(el, value) | ||
} else if (tag === 'input' && type === 'checkbox') { | ||
genCheckboxModel(el, value) | ||
} else if (tag === 'input' && type === 'radio') { | ||
genRadioModel(el, value) | ||
} else { | ||
switch (el.attrsMap.type) { | ||
case 'checkbox': | ||
genCheckboxModel(el, value) | ||
break | ||
case 'radio': | ||
genRadioModel(el, value) | ||
break | ||
default: | ||
return genDefaultModel(el, value, modifiers) | ||
} | ||
return genDefaultModel(el, value, modifiers) | ||
} | ||
} | ||
function genCheckboxModel (el: ASTElement, value: ?string) { | ||
function genCheckboxModel (el: ASTElement, value: string) { | ||
if (process.env.NODE_ENV !== 'production' && | ||
@@ -41,3 +39,3 @@ el.attrsMap.checked != null) { | ||
} | ||
const valueBinding = getBindingAttr(el, 'value') | ||
const valueBinding = getBindingAttr(el, 'value') || 'null' | ||
const trueValueBinding = getBindingAttr(el, 'true-value') || 'true' | ||
@@ -59,7 +57,8 @@ const falseValueBinding = getBindingAttr(el, 'false-value') || 'false' | ||
`else{$$i>-1&&(${value}=$$a.slice(0,$$i).concat($$a.slice($$i+1)))}` + | ||
`}else{${value}=$$c}` | ||
`}else{${value}=$$c}`, | ||
null, true | ||
) | ||
} | ||
function genRadioModel (el: ASTElement, value: ?string) { | ||
function genRadioModel (el: ASTElement, value: string) { | ||
if (process.env.NODE_ENV !== 'production' && | ||
@@ -73,5 +72,5 @@ el.attrsMap.checked != null) { | ||
} | ||
const valueBinding = getBindingAttr(el, 'value') | ||
const valueBinding = getBindingAttr(el, 'value') || 'null' | ||
addProp(el, 'checked', `(${value})===(${valueBinding})`) | ||
addHandler(el, 'change', `${value}=${valueBinding}`) | ||
addHandler(el, 'change', `${value}=${valueBinding}`, null, true) | ||
} | ||
@@ -81,3 +80,3 @@ | ||
el: ASTElement, | ||
value: ?string, | ||
value: string, | ||
modifiers: ?Object | ||
@@ -104,3 +103,3 @@ ): ?boolean { | ||
const { lazy, number, trim } = modifiers || {} | ||
const event = lazy ? 'change' : 'input' | ||
const event = lazy || (isIE && type === 'range') ? 'change' : 'input' | ||
const needCompositionGuard = !lazy && type !== 'range' | ||
@@ -119,3 +118,3 @@ const isNative = el.tag === 'input' || el.tag === 'textarea' | ||
addProp(el, 'value', isNative ? `_s(${value})` : `(${value})`) | ||
addHandler(el, event, code) | ||
addHandler(el, event, code, null, true) | ||
if (needCompositionGuard) { | ||
@@ -127,3 +126,3 @@ // need runtime directive code to help with composition events | ||
function genSelect (el: ASTElement, value: ?string) { | ||
function genSelect (el: ASTElement, value: string) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
@@ -136,3 +135,3 @@ el.children.some(checkOptionWarning) | ||
(el.attrsMap.multiple == null ? '[0]' : '') | ||
addHandler(el, 'change', code) | ||
addHandler(el, 'change', code, null, true) | ||
// need runtime to help with possible dynamically generated options | ||
@@ -142,11 +141,8 @@ return true | ||
function checkOptionWarning (option: ASTNode) { | ||
function checkOptionWarning (option: any): boolean { | ||
if (option.type === 1 && | ||
option.tag === 'option' && | ||
option.attrsMap.selected != null) { | ||
const parentModel = option.parent && | ||
option.parent.type === 1 && | ||
option.parent.attrsMap['v-model'] | ||
warn( | ||
`<select v-model="${parentModel}">:\n` + | ||
`<select v-model="${option.parent.attrsMap['v-model']}">:\n` + | ||
'inline selected attributes on <option> will be ignored when using v-model. ' + | ||
@@ -157,2 +153,3 @@ 'Declare initial values in the component\'s data option instead.' | ||
} | ||
return false | ||
} |
@@ -23,3 +23,5 @@ /* @flow */ | ||
} | ||
el.staticClass = JSON.stringify(staticClass) | ||
if (staticClass) { | ||
el.staticClass = JSON.stringify(staticClass) | ||
} | ||
const classBinding = getBindingAttr(el, 'class', false /* getStatic */) | ||
@@ -26,0 +28,0 @@ if (classBinding) { |
@@ -45,3 +45,3 @@ /* @flow */ | ||
if (c.tag) { | ||
if (c.key != null) { | ||
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) { | ||
children.push(c) | ||
@@ -124,4 +124,4 @@ map[c.key] = c | ||
if (c.data.moved) { | ||
const el = c.elm | ||
const s = el.style | ||
var el = c.elm | ||
var s = el.style | ||
addTransitionClass(el, moveClass) | ||
@@ -128,0 +128,0 @@ s.transform = s.WebkitTransform = s.transitionDuration = '' |
@@ -8,3 +8,3 @@ /* @flow */ | ||
import { camelize, extend } from 'shared/util' | ||
import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers' | ||
import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers' | ||
@@ -25,2 +25,13 @@ export const transitionProps = { | ||
// in case the child is also an abstract component, e.g. <keep-alive> | ||
// we want to recrusively retrieve the real component to be rendered | ||
function getRealChild (vnode: ?VNode): ?VNode { | ||
const compOptions = vnode && vnode.componentOptions | ||
if (compOptions && compOptions.Ctor.options.abstract) { | ||
return getRealChild(getFirstComponentChild(compOptions.children)) | ||
} else { | ||
return vnode | ||
} | ||
} | ||
export function extractTransitionData (comp: Component): Object { | ||
@@ -42,2 +53,16 @@ const data = {} | ||
function placeholder (h, rawChild) { | ||
return /\d-keep-alive$/.test(rawChild.tag) | ||
? h('keep-alive') | ||
: null | ||
} | ||
function hasParentTransition (vnode) { | ||
while ((vnode = vnode.parent)) { | ||
if (vnode.data.transition) { | ||
return true | ||
} | ||
} | ||
} | ||
export default { | ||
@@ -55,2 +80,3 @@ name: 'transition', | ||
children = children.filter(c => c.tag) | ||
/* istanbul ignore if */ | ||
if (!children.length) { | ||
@@ -84,3 +110,3 @@ return | ||
// parent container node also has transition, skip. | ||
if (this.$vnode.parent && this.$vnode.parent.data.transition) { | ||
if (hasParentTransition(this.$vnode)) { | ||
return rawChild | ||
@@ -93,4 +119,13 @@ } | ||
/* istanbul ignore if */ | ||
if (!child) return | ||
child.key = child.key || `__v${child.tag + this._uid}__` | ||
if (!child) { | ||
return rawChild | ||
} | ||
if (this._leaving) { | ||
return placeholder(h, rawChild) | ||
} | ||
child.key = child.key == null | ||
? `__v${child.tag + this._uid}__` | ||
: child.key | ||
const data = (child.data || (child.data = {})).transition = extractTransitionData(this) | ||
@@ -100,2 +135,8 @@ const oldRawChild = this._vnode | ||
// mark v-show | ||
// so that the transition module can hand over the control to the directive | ||
if (child.data.directives && child.data.directives.some(d => d.name === 'show')) { | ||
child.data.show = true | ||
} | ||
if (oldChild && oldChild.data && oldChild.key !== child.key) { | ||
@@ -108,12 +149,12 @@ // replace old child transition data with fresh one | ||
if (mode === 'out-in') { | ||
// return empty node and queue update when leave finishes | ||
// return placeholder node and queue update when leave finishes | ||
this._leaving = true | ||
mergeVNodeHook(oldData, 'afterLeave', () => { | ||
this._leaving = false | ||
this.$forceUpdate() | ||
}) | ||
return /\d-keep-alive$/.test(rawChild.tag) | ||
? h('keep-alive') | ||
: null | ||
return placeholder(h, rawChild) | ||
} else if (mode === 'in-out') { | ||
let delayedLeave | ||
const performLeave = () => { delayedLeave() } | ||
var delayedLeave | ||
var performLeave = () => { delayedLeave() } | ||
mergeVNodeHook(data, 'afterEnter', performLeave) | ||
@@ -120,0 +161,0 @@ mergeVNodeHook(data, 'enterCancelled', performLeave) |
@@ -67,5 +67,3 @@ /** | ||
const isMultiple = el.multiple | ||
if (!isMultiple) { | ||
el.selectedIndex = -1 | ||
} else if (!Array.isArray(value)) { | ||
if (isMultiple && !Array.isArray(value)) { | ||
process.env.NODE_ENV !== 'production' && warn( | ||
@@ -80,13 +78,22 @@ `<select multiple v-model="${binding.expression}"> ` + | ||
} | ||
let selected, option | ||
for (let i = 0, l = el.options.length; i < l; i++) { | ||
const option = el.options[i] | ||
option = el.options[i] | ||
if (isMultiple) { | ||
option.selected = value.indexOf(getValue(option)) > -1 | ||
selected = value.indexOf(getValue(option)) > -1 | ||
if (option.selected !== selected) { | ||
option.selected = selected | ||
} | ||
} else { | ||
if (getValue(option) === value) { | ||
el.selectedIndex = i | ||
break | ||
if (el.selectedIndex !== i) { | ||
el.selectedIndex = i | ||
} | ||
return | ||
} | ||
} | ||
} | ||
if (!isMultiple) { | ||
el.selectedIndex = -1 | ||
} | ||
} | ||
@@ -93,0 +100,0 @@ |
@@ -6,16 +6,29 @@ /* @flow */ | ||
// recursively search for possible transition defined inside the component root | ||
function locateNode (vnode: VNode): VNodeWithData { | ||
return vnode.child && (!vnode.data || !vnode.data.transition) | ||
? locateNode(vnode.child._vnode) | ||
: vnode | ||
} | ||
export default { | ||
bind (el: HTMLElement, { value }: VNodeDirective, vnode: VNodeWithData) { | ||
const transition = vnode.data.transition | ||
if (value && transition && transition.appear && !isIE9) { | ||
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) { | ||
vnode = locateNode(vnode) | ||
const transition = vnode.data && vnode.data.transition | ||
if (value && transition && !isIE9) { | ||
enter(vnode) | ||
} | ||
el.style.display = value ? '' : 'none' | ||
const originalDisplay = el.style.display === 'none' ? '' : el.style.display | ||
el.style.display = value ? originalDisplay : 'none' | ||
el.__vOriginalDisplay = originalDisplay | ||
}, | ||
update (el: HTMLElement, { value }: VNodeDirective, vnode: VNodeWithData) { | ||
const transition = vnode.data.transition | ||
update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) { | ||
/* istanbul ignore if */ | ||
if (value === oldValue) return | ||
vnode = locateNode(vnode) | ||
const transition = vnode.data && vnode.data.transition | ||
if (transition && !isIE9) { | ||
if (value) { | ||
enter(vnode) | ||
el.style.display = '' | ||
el.style.display = el.__vOriginalDisplay | ||
} else { | ||
@@ -27,5 +40,5 @@ leave(vnode, () => { | ||
} else { | ||
el.style.display = value ? '' : 'none' | ||
el.style.display = value ? el.__vOriginalDisplay : 'none' | ||
} | ||
} | ||
} |
@@ -24,2 +24,8 @@ /* @flow */ | ||
for (key in props) { | ||
// ignore children if the node has textContent or innerHTML, | ||
// as these will throw away existing DOM nodes and cause removal errors | ||
// on subsequent patches (#3360) | ||
if ((key === 'textContent' || key === 'innerHTML') && vnode.children) { | ||
vnode.children.length = 0 | ||
} | ||
cur = props[key] | ||
@@ -26,0 +32,0 @@ if (key === 'value') { |
@@ -6,3 +6,3 @@ // skip type checking this file because we need to attach private properties | ||
function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
function updateDOMListeners (oldVnode, vnode) { | ||
if (!oldVnode.data.on && !vnode.data.on) { | ||
@@ -9,0 +9,0 @@ return |
@@ -24,9 +24,16 @@ /* @flow */ | ||
function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (!oldVnode.data.style && !vnode.data.style) { | ||
if ((!oldVnode.data || !oldVnode.data.style) && !vnode.data.style) { | ||
return | ||
} | ||
let cur, name | ||
const elm: any = vnode.elm | ||
const el: any = vnode.elm | ||
const oldStyle: any = oldVnode.data.style || {} | ||
let style: any = vnode.data.style || {} | ||
// handle string | ||
if (typeof style === 'string') { | ||
el.style.cssText = style | ||
return | ||
} | ||
const needClone = style.__ob__ | ||
@@ -47,3 +54,3 @@ | ||
if (!style[name]) { | ||
elm.style[normalize(name)] = '' | ||
el.style[normalize(name)] = '' | ||
} | ||
@@ -55,3 +62,3 @@ } | ||
// ie9 setting to null has no effect, must use empty string | ||
elm.style[normalize(name)] = cur || '' | ||
el.style[normalize(name)] = cur || '' | ||
} | ||
@@ -58,0 +65,0 @@ } |
@@ -7,2 +7,3 @@ /* @flow */ | ||
import { mergeVNodeHook } from 'core/vdom/helpers' | ||
import { activeInstance } from 'core/instance/lifecycle' | ||
import { | ||
@@ -30,3 +31,3 @@ nextFrame, | ||
/* istanbul ignore if */ | ||
if (el._enterCb) { | ||
if (el._enterCb || el.nodeType !== 1) { | ||
return | ||
@@ -52,4 +53,13 @@ } | ||
const context = vnode.context.$parent || vnode.context | ||
const isAppear = !context._isMounted | ||
// activeInstance will always be the <transition> component managing this | ||
// transition. One edge case to check is when the <transition> is placed | ||
// as the root node of a child component. In that case we need to check | ||
// <transition>'s parent for appear check. | ||
const transitionNode = activeInstance.$vnode | ||
const context = transitionNode && transitionNode.parent | ||
? transitionNode.parent.context | ||
: activeInstance | ||
const isAppear = !context._isMounted || !vnode.isRootInsert | ||
if (isAppear && !appear && appear !== '') { | ||
@@ -88,11 +98,13 @@ return | ||
// remove pending leave element on enter by injecting an insert hook | ||
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', () => { | ||
const parent = el.parentNode | ||
const pendingNode = parent._pending && parent._pending[vnode.key] | ||
if (pendingNode && pendingNode.tag === vnode.tag && pendingNode.elm._leaveCb) { | ||
pendingNode.elm._leaveCb() | ||
} | ||
enterHook && enterHook(el, cb) | ||
}) | ||
if (!vnode.data.show) { | ||
// remove pending leave element on enter by injecting an insert hook | ||
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', () => { | ||
const parent = el.parentNode | ||
const pendingNode = parent && parent._pending && parent._pending[vnode.key] | ||
if (pendingNode && pendingNode.tag === vnode.tag && pendingNode.elm._leaveCb) { | ||
pendingNode.elm._leaveCb() | ||
} | ||
enterHook && enterHook(el, cb) | ||
}) | ||
} | ||
@@ -112,2 +124,6 @@ // start enter transition | ||
if (vnode.data.show) { | ||
enterHook && enterHook(el, cb) | ||
} | ||
if (!expectsCSS && !userWantsControl) { | ||
@@ -133,3 +149,3 @@ cb() | ||
/* istanbul ignore if */ | ||
if (el._leaveCb) { | ||
if (el._leaveCb || el.nodeType !== 1) { | ||
return | ||
@@ -136,0 +152,0 @@ } |
@@ -17,2 +17,6 @@ /* @flow */ | ||
export function createComment (text: string): Comment { | ||
return document.createComment(text) | ||
} | ||
export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) { | ||
@@ -46,3 +50,3 @@ parentNode.insertBefore(newNode, referenceNode) | ||
export function childNodes (node: Node): NodeList { | ||
export function childNodes (node: Node): NodeList<Node> { | ||
return node.childNodes | ||
@@ -49,0 +53,0 @@ } |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import * as nodeOps from 'web/runtime/node-ops' | ||
@@ -2,0 +4,0 @@ import { createPatchFunction } from 'core/vdom/patch' |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { inBrowser } from 'core/util/index' | ||
@@ -50,3 +52,3 @@ import { isIE9 } from 'web/util/index' | ||
el: Element, | ||
expectedType: ?stirng, | ||
expectedType: ?string, | ||
cb: Function | ||
@@ -62,5 +64,7 @@ ) { | ||
} | ||
const onEnd = () => { | ||
if (++ended >= propCount) { | ||
end() | ||
const onEnd = e => { | ||
if (e.target === el) { | ||
if (++ended >= propCount) { | ||
end() | ||
} | ||
} | ||
@@ -82,2 +86,3 @@ } | ||
timeout: number; | ||
hasTransform: boolean; | ||
} { | ||
@@ -84,0 +89,0 @@ const styles = window.getComputedStyle(el) |
@@ -9,13 +9,18 @@ /* @flow */ | ||
let styles = node.data.style | ||
let res = ' style="' | ||
let res = '' | ||
if (styles) { | ||
if (Array.isArray(styles)) { | ||
styles = toObject(styles) | ||
if (typeof styles === 'string') { | ||
res += styles | ||
} else { | ||
if (Array.isArray(styles)) { | ||
styles = toObject(styles) | ||
} | ||
for (const key in styles) { | ||
res += `${hyphenate(key)}:${styles[key]};` | ||
} | ||
res += staticStyle || '' | ||
} | ||
for (const key in styles) { | ||
res += `${hyphenate(key)}:${styles[key]};` | ||
} | ||
} | ||
return res + (staticStyle || '') + '"' | ||
return ` style=${JSON.stringify(res)}` | ||
} | ||
} |
@@ -7,10 +7,14 @@ /* @flow */ | ||
let data = vnode.data | ||
// Important: check if this is a component container node | ||
// or a child component root node | ||
let i | ||
if ((i = vnode.child) && (i = i._vnode.data)) { | ||
data = mergeClassData(i, data) | ||
let parentNode = vnode | ||
let childNode = vnode | ||
while (childNode.child) { | ||
childNode = childNode.child._vnode | ||
if (childNode.data) { | ||
data = mergeClassData(childNode.data, data) | ||
} | ||
} | ||
if ((i = vnode.parent) && (i = i.data)) { | ||
data = mergeClassData(data, i) | ||
while ((parentNode = parentNode.parent)) { | ||
if (parentNode.data) { | ||
data = mergeClassData(data, parentNode.data) | ||
} | ||
} | ||
@@ -17,0 +21,0 @@ return genClassFromData(data) |
@@ -14,4 +14,6 @@ /* @flow */ | ||
// some browsers, e.g. PhantomJS, encodes angular brackets | ||
// inside attribute values when retrieving innerHTML. | ||
// According to | ||
// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value | ||
// when serializing innerHTML, <, >, ", & should be encoded as entities. | ||
// However, only some browsers, e.g. PhantomJS, encodes < and >. | ||
// this causes problems with the in-browser parser. | ||
@@ -18,0 +20,0 @@ export const shouldDecodeTags = inBrowser ? (function () { |
@@ -9,3 +9,6 @@ /* @flow */ | ||
import directives from './directives/index' | ||
import { isReservedTag, isUnaryTag, mustUseProp, getTagNamespace } from '../util/index' | ||
import { | ||
isReservedTag, isUnaryTag, | ||
mustUseProp, getTagNamespace | ||
} from '../util/index' | ||
@@ -24,2 +27,3 @@ const cache: { [key: string]: CompiledFunctionResult } = Object.create(null) | ||
getTagNamespace | ||
} | ||
@@ -40,3 +44,3 @@ | ||
options?: CompilerOptions, | ||
vm: Component | ||
vm?: Component | ||
): CompiledFunctionResult { | ||
@@ -43,0 +47,0 @@ const _warn = (options && options.warn) || warn |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { | ||
@@ -5,3 +7,3 @@ getAndRemoveAttr | ||
function parse (el, options) { | ||
function parse (el: ASTElement, options: CompilerOptions) { | ||
const staticStyle = getAndRemoveAttr(el, 'append') | ||
@@ -13,3 +15,3 @@ if (staticStyle === 'tree') { | ||
function genData (el) { | ||
function genData (el: ASTElement): string { | ||
return el.atom ? `atom:true,` : '' | ||
@@ -16,0 +18,0 @@ } |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { parseText } from 'compiler/parser/text-parser' | ||
@@ -8,3 +10,8 @@ import { | ||
function transformNode (el, options) { | ||
type StaticClassResult = { | ||
dynamic: boolean, | ||
classResult: string | ||
} | ||
function transformNode (el: ASTElement, options: CompilerOptions) { | ||
const warn = options.warn || baseWarn | ||
@@ -33,3 +40,3 @@ const staticClass = getAndRemoveAttr(el, 'class') | ||
function genData (el) { | ||
function genData (el: ASTElement): string { | ||
let data = '' | ||
@@ -45,3 +52,3 @@ if (el.staticClass) { | ||
function parseStaticClass (staticClass, options) { | ||
function parseStaticClass (staticClass?: string, options: CompilerOptions): StaticClassResult { | ||
// "a b c" -> ["a", "b", "c"] => staticClass: ["a", "b", "c"] | ||
@@ -48,0 +55,0 @@ // "a {{x}} c" -> ["a", x, "c"] => classBinding: '["a", x, "c"]' |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import { cached, camelize } from 'shared/util' | ||
@@ -8,7 +10,10 @@ import { parseText } from 'compiler/parser/text-parser' | ||
const normalize = cached(function (prop) { | ||
return camelize(prop) | ||
}) | ||
type StaticStyleResult = { | ||
dynamic: boolean, | ||
styleResult: string | ||
} | ||
function transformNode (el, options) { | ||
const normalize = cached(camelize) | ||
function transformNode (el: ASTElement, options: CompilerOptions) { | ||
const staticStyle = getAndRemoveAttr(el, 'style') | ||
@@ -27,3 +32,3 @@ const { dynamic, styleResult } = parseStaticStyle(staticStyle, options) | ||
function genData (el) { | ||
function genData (el: ASTElement): string { | ||
let data = '' | ||
@@ -39,3 +44,3 @@ if (el.staticStyle) { | ||
function parseStaticStyle (staticStyle, options) { | ||
function parseStaticStyle (staticStyle?: string, options: CompilerOptions): StaticStyleResult { | ||
// "width: 200px; height: 200px;" -> {width: 200, height: 200} | ||
@@ -42,0 +47,0 @@ // "width: 200px; height: {{y}}" -> {width: 200, height: y} |
@@ -1,2 +0,6 @@ | ||
function updateAttrs (oldVnode, vnode) { | ||
/* @flow */ | ||
import { extend } from 'shared/util' | ||
function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (!oldVnode.data.attrs && !vnode.data.attrs) { | ||
@@ -8,3 +12,7 @@ return | ||
const oldAttrs = oldVnode.data.attrs || {} | ||
const attrs = vnode.data.attrs || {} | ||
let attrs = vnode.data.attrs || {} | ||
// clone observed objects, as the user probably wants to mutate it | ||
if (attrs.__ob__) { | ||
attrs = vnode.data.attrs = extend({}, attrs) | ||
} | ||
@@ -26,13 +34,4 @@ for (key in attrs) { | ||
export default { | ||
create: function (_, vnode) { | ||
const attrs = vnode.data.staticAttrs | ||
if (attrs) { | ||
for (let key in attrs) { | ||
if (!vnode.elm) debugger | ||
vnode.elm.setAttr(key, attrs[key]) | ||
} | ||
} | ||
updateAttrs(_, vnode) | ||
}, | ||
create: updateAttrs, | ||
update: updateAttrs | ||
} |
@@ -0,11 +1,13 @@ | ||
/* @flow */ | ||
import { extend } from 'shared/util' | ||
function updateClass (oldVnode, vnode) { | ||
function updateClass (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
const el = vnode.elm | ||
const ctx = vnode.context | ||
let data = vnode.data | ||
const staticClass = data.staticClass | ||
const klass = data.class | ||
if (!staticClass && !klass) { | ||
const data: VNodeData = vnode.data | ||
const oldData: VNodeData = oldVnode.data | ||
if (!data.staticClass && !data.class && | ||
(!oldData || (!oldData.staticClass && !oldData.class))) { | ||
return | ||
@@ -15,9 +17,10 @@ } | ||
const classList = [] | ||
if (staticClass) { | ||
classList.push.apply(classList, staticClass) | ||
if (data.staticClass) { | ||
classList.push.apply(classList, data.staticClass) | ||
} | ||
if (klass) { | ||
classList.push.apply(classList, klass) | ||
if (data.class) { | ||
classList.push.apply(classList, data.class) | ||
} | ||
// @todo: remove old class Style | ||
const style = getStyle(classList, ctx) | ||
@@ -29,3 +32,3 @@ for (const key in style) { | ||
function getStyle (classList, ctx) { | ||
function getStyle (classList: Array<string>, ctx: Component): Object { | ||
const stylesheet = ctx.$options.style || {} | ||
@@ -32,0 +35,0 @@ const result = {} |
@@ -0,4 +1,6 @@ | ||
/* @flow */ | ||
import { updateListeners } from 'core/vdom/helpers' | ||
function updateDOMListeners (oldVnode, vnode) { | ||
function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (!oldVnode.data.on && !vnode.data.on) { | ||
@@ -9,2 +11,3 @@ return | ||
const oldOn = oldVnode.data.on || {} | ||
// @todo: removeEvent | ||
updateListeners(on, oldOn, (event, handler, capture) => { | ||
@@ -11,0 +14,0 @@ if (capture) { |
import attrs from './attrs' | ||
import klass from './class' | ||
import events from './events' | ||
import props from './props' | ||
import domProps from './dom-props' | ||
import style from './style' | ||
@@ -11,4 +11,4 @@ | ||
events, | ||
props, | ||
domProps, | ||
style | ||
] |
@@ -0,8 +1,8 @@ | ||
/* @flow */ | ||
import { extend, cached, camelize } from 'shared/util' | ||
const normalize = cached(function (prop) { | ||
return camelize(prop) | ||
}) | ||
const normalize = cached(camelize) | ||
function createStyle (oldVnode, vnode) { | ||
function createStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (!vnode.data.staticStyle) { | ||
@@ -22,3 +22,3 @@ updateStyle(oldVnode, vnode) | ||
function updateStyle (oldVnode, vnode) { | ||
function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) { | ||
if (!oldVnode.data.style && !vnode.data.style) { | ||
@@ -32,2 +32,4 @@ return | ||
const needClone = style.__ob__ | ||
// handle array syntax | ||
@@ -38,2 +40,8 @@ if (Array.isArray(style)) { | ||
// clone the style for future updates, | ||
// in case the user mutates the style object in-place. | ||
if (needClone) { | ||
style = vnode.data.style = extend({}, style) | ||
} | ||
for (name in oldStyle) { | ||
@@ -40,0 +48,0 @@ if (!style[name]) { |
@@ -0,1 +1,3 @@ | ||
/* @flow */ | ||
import * as nodeOps from 'weex/runtime/node-ops' | ||
@@ -2,0 +4,0 @@ import { createPatchFunction } from 'core/vdom/patch' |
@@ -20,3 +20,7 @@ import runInVm from './run-in-vm' | ||
runInVm(code, context).then(app => { | ||
renderer.renderToStream(app).pipe(res) | ||
const renderStream = renderer.renderToStream(app) | ||
renderStream.on('error', err => { | ||
res.emit('error', err) | ||
}) | ||
renderStream.pipe(res) | ||
}).catch(err => { | ||
@@ -23,0 +27,0 @@ process.nextTick(() => { |
/* @flow */ | ||
import stream from 'stream' | ||
import { createWriteFunction } from './write' | ||
/** | ||
* Original RenderStream implmentation by Sasha Aickin (@aickin) | ||
* Licensed under the Apache License, Version 2.0 | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Modified by Evan You (@yyx990803) | ||
*/ | ||
import stream from 'stream' | ||
import { createWriteFunction } from './write' | ||
export default class RenderStream extends stream.Readable { | ||
@@ -12,0 +15,0 @@ buffer: string; |
@@ -7,2 +7,10 @@ /* @flow */ | ||
let warned = Object.create(null) | ||
const warnOnce = msg => { | ||
if (!warned[msg]) { | ||
warned[msg] = true | ||
console.warn(`\n\u001b[31m${msg}\u001b[39m\n`) | ||
} | ||
} | ||
const normalizeAsync = (cache, method) => { | ||
@@ -22,8 +30,16 @@ const fn = cache[method] | ||
const { render, template } = vm.$options | ||
if (!render && template) { | ||
const renderFns = ( | ||
compilationCache[template] || | ||
(compilationCache[template] = compileToFunctions(template)) | ||
) | ||
Object.assign(vm.$options, renderFns) | ||
if (!render) { | ||
if (template) { | ||
const renderFns = ( | ||
compilationCache[template] || | ||
(compilationCache[template] = compileToFunctions(template)) | ||
) | ||
Object.assign(vm.$options, renderFns) | ||
} else { | ||
throw new Error( | ||
`render function or template not defined in component: ${ | ||
vm.$options.name || vm.$options._componentTag || 'anonymous' | ||
}` | ||
) | ||
} | ||
} | ||
@@ -45,2 +61,5 @@ } | ||
// used to track and apply scope ids | ||
let activeInstance: any | ||
function renderNode ( | ||
@@ -56,7 +75,8 @@ node: VNode, | ||
const getKey = Ctor.options.serverCacheKey | ||
if (getKey && cache) { | ||
const key = Ctor.cid + '::' + getKey(node.componentOptions.propsData) | ||
const name = Ctor.options.name | ||
if (getKey && cache && name) { | ||
const key = name + '::' + getKey(node.componentOptions.propsData) | ||
if (has) { | ||
has(key, hit => { | ||
if (hit) { | ||
if (hit && get) { | ||
get(key, res => write(res, next)) | ||
@@ -67,3 +87,3 @@ } else { | ||
}) | ||
} else { | ||
} else if (get) { | ||
get(key, res => { | ||
@@ -78,4 +98,4 @@ if (res) { | ||
} else { | ||
if (getKey) { | ||
console.error( | ||
if (getKey && !cache) { | ||
warnOnce( | ||
`[vue-server-renderer] Component ${ | ||
@@ -87,2 +107,8 @@ Ctor.options.name || '(anonymous)' | ||
} | ||
if (getKey && !name) { | ||
warnOnce( | ||
`[vue-server-renderer] Components that implement "serverCacheKey" ` + | ||
`must also define a unique "name" option.` | ||
) | ||
} | ||
renderComponent(node, write, next, isRoot) | ||
@@ -93,2 +119,4 @@ } | ||
renderElement(node, write, next, isRoot) | ||
} else if (node.isComment) { | ||
write(`<!--${node.text}-->`, next) | ||
} else { | ||
@@ -101,7 +129,11 @@ write(node.raw ? node.text : encodeHTML(String(node.text)), next) | ||
function renderComponent (node, write, next, isRoot) { | ||
const child = createComponentInstanceForVnode(node) | ||
const prevActive = activeInstance | ||
const child = activeInstance = createComponentInstanceForVnode(node, activeInstance) | ||
normalizeRender(child) | ||
const childNode = child._render() | ||
childNode.parent = node | ||
renderNode(childNode, write, next, isRoot) | ||
renderNode(childNode, write, () => { | ||
activeInstance = prevActive | ||
next() | ||
}, isRoot) | ||
} | ||
@@ -189,3 +221,5 @@ | ||
let scopeId | ||
if (node.host && (scopeId = node.host.$options._scopeId)) { | ||
if (activeInstance && | ||
activeInstance !== node.context && | ||
(scopeId = activeInstance.$options._scopeId)) { | ||
markup += ` ${scopeId}` | ||
@@ -207,2 +241,4 @@ } | ||
) { | ||
warned = Object.create(null) | ||
activeInstance = component | ||
normalizeRender(component) | ||
@@ -209,0 +245,0 @@ renderNode(component._render(), write, done, true) |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
74
6
620628
48
12799
4