diff --git a/flow/compiler.js b/flow/compiler.js index 673dc5b4a54..a49f24ec940 100644 --- a/flow/compiler.js +++ b/flow/compiler.js @@ -72,8 +72,8 @@ declare type ASTNode = ASTElement | ASTText | ASTExpression; declare type ASTElement = { type: 1; tag: string; - attrsList: Array<{ name: string; value: string }>; - attrsMap: { [key: string]: string | null }; + attrsList: Array<{ name: string; value: any }>; + attrsMap: { [key: string]: any }; parent: ASTElement | void; children: Array; @@ -84,7 +84,7 @@ declare type ASTElement = { hasBindings?: boolean; text?: string; - attrs?: Array<{ name: string; value: string }>; + attrs?: Array<{ name: string; value: any }>; props?: Array<{ name: string; value: string }>; plain?: boolean; pre?: true; diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index c1d35e3953d..f027b2aeec8 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -475,15 +475,22 @@ function genComponent ( })` } -function genProps (props: Array<{ name: string, value: string }>): string { +function genProps (props: Array<{ name: string, value: any }>): string { let res = '' for (let i = 0; i < props.length; i++) { const prop = props[i] - res += `"${prop.name}":${transformSpecialNewlines(prop.value)},` + res += `"${prop.name}":${generateValue(prop.value)},` } return res.slice(0, -1) } +function generateValue (value) { + if (typeof value === 'string') { + return transformSpecialNewlines(value) + } + return JSON.stringify(value) +} + // #3895, #4268 function transformSpecialNewlines (text: string): string { return text diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index 49d6d6ae39a..7ed3ae238db 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -19,7 +19,7 @@ export function addProp (el: ASTElement, name: string, value: string) { (el.props || (el.props = [])).push({ name, value }) } -export function addAttr (el: ASTElement, name: string, value: string) { +export function addAttr (el: ASTElement, name: string, value: any) { (el.attrs || (el.attrs = [])).push({ name, value }) } diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index 2e77e78018a..5f1cb108fe0 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -25,7 +25,7 @@ export const forAliasRE = /(.*?)\s+(?:in|of)\s+(.*)/ export const forIteratorRE = /\((\{[^}]*\}|[^,]*),([^,]*)(?:,([^,]*))?\)/ const argRE = /:(.*)$/ -const bindRE = /^:|^v-bind:/ +export const bindRE = /^:|^v-bind:/ const modifierRE = /\.[^.]+/g const decodeHTMLCached = cached(he.decode) diff --git a/src/core/vdom/helpers/update-listeners.js b/src/core/vdom/helpers/update-listeners.js index d587eecf38a..6b92f5da6de 100644 --- a/src/core/vdom/helpers/update-listeners.js +++ b/src/core/vdom/helpers/update-listeners.js @@ -1,13 +1,15 @@ /* @flow */ import { warn } from 'core/util/index' -import { cached, isUndef } from 'shared/util' +import { cached, isUndef, isPlainObject } from 'shared/util' const normalizeEvent = cached((name: string): { name: string, once: boolean, capture: boolean, - passive: boolean + passive: boolean, + handler?: Function, + params?: Array } => { const passive = name.charAt(0) === '&' name = passive ? name.slice(1) : name @@ -47,11 +49,15 @@ export function updateListeners ( remove: Function, vm: Component ) { - let name, cur, old, event + let name, def, cur, old, event for (name in on) { - cur = on[name] + def = cur = on[name] old = oldOn[name] event = normalizeEvent(name) + if (isPlainObject(def)) { + cur = def.handler + event.params = def.params + } if (isUndef(cur)) { process.env.NODE_ENV !== 'production' && warn( `Invalid handler for event "${event.name}": got ` + String(cur), @@ -61,7 +67,7 @@ export function updateListeners ( if (isUndef(cur.fns)) { cur = on[name] = createFnInvoker(cur) } - add(event.name, cur, event.once, event.capture, event.passive) + add(event.name, cur, event.once, event.capture, event.passive, event.params) } else if (cur !== old) { old.fns = cur on[name] = old diff --git a/src/platforms/weex/compiler/modules/recycle-list/index.js b/src/platforms/weex/compiler/modules/recycle-list/index.js index 82cc6e8f605..323df23ae87 100644 --- a/src/platforms/weex/compiler/modules/recycle-list/index.js +++ b/src/platforms/weex/compiler/modules/recycle-list/index.js @@ -1,13 +1,22 @@ /* @flow */ import { transformText } from './text' +import { transformVBind } from './v-bind' +import { transformVIf } from './v-if' +import { transformVFor } from './v-for' let currentRecycleList = null -function preTransformNode (el: ASTElement) { +function preTransformNode (el: ASTElement, options: CompilerOptions) { if (el.tag === 'recycle-list') { currentRecycleList = el } + if (currentRecycleList) { + // TODO + transformVBind(el) + transformVIf(el, options) // and v-else-if and v-else + transformVFor(el, options) + } } function transformNode (el: ASTElement) { diff --git a/src/platforms/weex/compiler/modules/recycle-list/text.js b/src/platforms/weex/compiler/modules/recycle-list/text.js index a950aff93a9..fb72c81b555 100644 --- a/src/platforms/weex/compiler/modules/recycle-list/text.js +++ b/src/platforms/weex/compiler/modules/recycle-list/text.js @@ -16,7 +16,9 @@ function genText (node: ASTNode) { export function transformText (el: ASTElement) { // weex can only contain text, so the parser // always generates a single child. - addAttr(el, 'value', genText(el.children[0])) - el.children = [] - el.plain = false + if (el.children.length) { + addAttr(el, 'value', genText(el.children[0])) + el.children = [] + el.plain = false + } } diff --git a/src/platforms/weex/compiler/modules/recycle-list/v-bind.js b/src/platforms/weex/compiler/modules/recycle-list/v-bind.js new file mode 100644 index 00000000000..425e7f67bf8 --- /dev/null +++ b/src/platforms/weex/compiler/modules/recycle-list/v-bind.js @@ -0,0 +1,25 @@ +/* @flow */ + +import { camelize } from 'shared/util' +import { bindRE } from 'compiler/parser/index' +import { getAndRemoveAttr } from 'compiler/helpers' + +function parseAttrName (name: string): string { + return camelize(name.replace(bindRE, '')) +} + +export function transformVBind (el: ASTElement) { + for (const attr in el.attrsMap) { + if (bindRE.test(attr)) { + const name: string = parseAttrName(attr) + const value = { + '@binding': getAndRemoveAttr(el, attr) + } + delete el.attrsMap[attr] + el.attrsMap[name] = value + el.attrsList.push({ name, value }) + // addAttr(el, name, value) + // el.hasBindings = false + } + } +} diff --git a/src/platforms/weex/compiler/modules/recycle-list/v-for.js b/src/platforms/weex/compiler/modules/recycle-list/v-for.js new file mode 100644 index 00000000000..29e6c6f5835 --- /dev/null +++ b/src/platforms/weex/compiler/modules/recycle-list/v-for.js @@ -0,0 +1,33 @@ +/* @flow */ + +import { forAliasRE, forIteratorRE } from 'compiler/parser/index' +import { getAndRemoveAttr } from 'compiler/helpers' + +export function transformVFor (el: ASTElement, options: CompilerOptions) { + const exp = getAndRemoveAttr(el, 'v-for') + if (!exp) { + return + } + const inMatch = exp.match(forAliasRE) + if (inMatch) { + const alias = inMatch[1].trim() + const desc: Object = { + '@expression': inMatch[2].trim(), + '@alias': alias + } + const iteratorMatch = alias.match(forIteratorRE) + if (iteratorMatch) { + desc['@alias'] = iteratorMatch[1].trim() + desc['@index'] = iteratorMatch[2].trim() + if (iteratorMatch[3]) { + desc['@key'] = iteratorMatch[2].trim() + desc['@index'] = iteratorMatch[3].trim() + } + } + delete el.attrsMap['v-for'] + el.attrsMap['[[repeat]]'] = desc + el.attrsList.push({ name: '[[repeat]]', value: desc }) + } else if (process.env.NODE_ENV !== 'production' && options.warn) { + options.warn(`Invalid v-for expression: ${exp}`) + } +} diff --git a/src/platforms/weex/compiler/modules/recycle-list/v-if.js b/src/platforms/weex/compiler/modules/recycle-list/v-if.js new file mode 100644 index 00000000000..f01010a251d --- /dev/null +++ b/src/platforms/weex/compiler/modules/recycle-list/v-if.js @@ -0,0 +1,48 @@ +/* @flow */ + +import { getAndRemoveAttr } from 'compiler/helpers' + +function hasConditionDirective (el: ASTElement): boolean { + for (const attr in el.attrsMap) { + if (/^v\-if|v\-else|v\-else\-if$/.test(attr)) { + return true + } + } + return false +} + +function getPrevMatch (el: ASTElement): any { + if (el.parent && el.parent.children) { + const prev: Object = el.parent.children[el.parent.children.length - 1] + return prev.attrsMap['[[match]]'] + } +} + +export function transformVIf (el: ASTElement, options: CompilerOptions) { + if (hasConditionDirective(el)) { + let exp + const ifExp = getAndRemoveAttr(el, 'v-if') + const elseifExp = getAndRemoveAttr(el, 'v-else-if') + if (ifExp) { + exp = ifExp + } else { + const prevMatch = getPrevMatch(el) + if (prevMatch) { + exp = elseifExp + ? `!(${prevMatch}) && (${elseifExp})` // v-else-if + : `!(${prevMatch})` // v-else + } else if (process.env.NODE_ENV !== 'production' && options.warn) { + options.warn( + `v-${elseifExp ? ('else-if="' + elseifExp + '"') : 'else'} ` + + `used on element <${el.tag}> without corresponding v-if.` + ) + return + } + } + el.attrsMap['[[match]]'] = exp + el.attrsList.push({ name: '[[match]]', value: exp }) + delete el.attrsMap['v-if'] + delete el.attrsMap['v-else-if'] + delete el.attrsMap['v-else'] + } +} diff --git a/src/platforms/weex/entry-framework.js b/src/platforms/weex/entry-framework.js index 303ad36b5f0..007b8aa1f79 100644 --- a/src/platforms/weex/entry-framework.js +++ b/src/platforms/weex/entry-framework.js @@ -162,10 +162,10 @@ const jsHandlers = { } } -function fireEvent (instance, nodeId, type, e, domChanges) { +function fireEvent (instance, nodeId, type, e, domChanges, params) { const el = instance.document.getRef(nodeId) if (el) { - return instance.document.fireEvent(el, type, e, domChanges) + return instance.document.fireEvent(el, type, e, domChanges, params) } return new Error(`invalid element reference "${nodeId}"`) } diff --git a/src/platforms/weex/runtime/modules/events.js b/src/platforms/weex/runtime/modules/events.js index 824f08e6154..bb642f60030 100755 --- a/src/platforms/weex/runtime/modules/events.js +++ b/src/platforms/weex/runtime/modules/events.js @@ -8,7 +8,9 @@ function add ( event: string, handler: Function, once: boolean, - capture: boolean + capture: boolean, + passive?: boolean, + params?: Array ) { if (capture) { console.log('Weex do not support event in bubble phase.') @@ -26,7 +28,7 @@ function add ( } } } - target.addEvent(event, handler) + target.addEvent(event, handler, params) } function remove (