Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic directive arguments #9373

Merged
merged 7 commits into from
Jan 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion flow/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,20 @@ declare type ModuleOptions = {
declare type ASTModifiers = { [key: string]: boolean };
declare type ASTIfCondition = { exp: ?string; block: ASTElement };
declare type ASTIfConditions = Array<ASTIfCondition>;
declare type ASTAttr = { name: string; value: any; start?: number; end?: number };

declare type ASTAttr = {
name: string;
value: any;
dynamic?: boolean;
start?: number;
end?: number
};

declare type ASTElementHandler = {
value: string;
params?: Array<any>;
modifiers: ?ASTModifiers;
dynamic?: boolean;
start?: number;
end?: number;
};
Expand All @@ -80,6 +88,7 @@ declare type ASTDirective = {
rawName: string;
value: string;
arg: ?string;
isDynamicArg: boolean;
modifiers: ?ASTModifiers;
start?: number;
end?: number;
Expand Down Expand Up @@ -109,6 +118,7 @@ declare type ASTElement = {

text?: string;
attrs?: Array<ASTAttr>;
dynamicAttrs?: Array<ASTAttr>;
props?: Array<ASTAttr>;
plain?: boolean;
pre?: true;
Expand Down
1 change: 1 addition & 0 deletions flow/vnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ declare type VNodeDirective = {
value?: any;
oldValue?: any;
arg?: string;
oldArg?: string;
modifiers?: ASTModifiers;
def?: Object;
};
Expand Down
27 changes: 18 additions & 9 deletions src/compiler/codegen/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,23 @@ export function genHandlers (
events: ASTElementHandlers,
isNative: boolean
): string {
let res = isNative ? 'nativeOn:{' : 'on:{'
const prefix = isNative ? 'nativeOn:' : 'on:'
let staticHandlers = ``
let dynamicHandlers = ``
for (const name in events) {
res += `"${name}":${genHandler(name, events[name])},`
const handlerCode = genHandler(events[name])
if (events[name] && events[name].dynamic) {
dynamicHandlers += `${name},${handlerCode},`
} else {
staticHandlers += `"${name}":${handlerCode},`
}
}
staticHandlers = `{${staticHandlers.slice(0, -1)}}`
if (dynamicHandlers) {
return prefix + `_d(${staticHandlers},[${dynamicHandlers.slice(0, -1)}])`
} else {
return prefix + staticHandlers
}
return res.slice(0, -1) + '}'
}

// Generate handler code with binding params on Weex
Expand All @@ -81,16 +93,13 @@ function genWeexHandler (params: Array<any>, handlerCode: string) {
'}'
}

function genHandler (
name: string,
handler: ASTElementHandler | Array<ASTElementHandler>
): string {
function genHandler (handler: ASTElementHandler | Array<ASTElementHandler>): string {
if (!handler) {
return 'function(){}'
}

if (Array.isArray(handler)) {
return `[${handler.map(handler => genHandler(name, handler)).join(',')}]`
return `[${handler.map(handler => genHandler(handler)).join(',')}]`
}

const isMethodPath = simplePathRE.test(handler.value)
Expand Down Expand Up @@ -154,7 +163,7 @@ function genHandler (
}

function genKeyFilter (keys: Array<string>): string {
return `if(!('button' in $event)&&${keys.map(genFilterCode).join('&&')})return null;`
return `if(('keyCode' in $event)&&${keys.map(genFilterCode).join('&&')})return null;`
}

function genFilterCode (key: string): string {
Expand Down
32 changes: 23 additions & 9 deletions src/compiler/codegen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,11 @@ export function genData (el: ASTElement, state: CodegenState): string {
}
// attributes
if (el.attrs) {
data += `attrs:{${genProps(el.attrs)}},`
data += `attrs:${genProps(el.attrs)},`
}
// DOM props
if (el.props) {
data += `domProps:{${genProps(el.props)}},`
data += `domProps:${genProps(el.props)},`
}
// event handlers
if (el.events) {
Expand Down Expand Up @@ -288,6 +288,12 @@ export function genData (el: ASTElement, state: CodegenState): string {
}
}
data = data.replace(/,$/, '') + '}'
// v-bind dynamic argument wrap
// v-bind with dynamic arguments must be applied using the same v-bind object
// merge helper so that class/style/mustUseProp attrs are handled correctly.
if (el.dynamicAttrs) {
data = `_b(${data},"${el.tag}",${genProps(el.dynamicAttrs)})`
}
// v-bind data wrap
if (el.wrapData) {
data = el.wrapData(data)
Expand Down Expand Up @@ -319,7 +325,7 @@ function genDirectives (el: ASTElement, state: CodegenState): string | void {
res += `{name:"${dir.name}",rawName:"${dir.rawName}"${
dir.value ? `,value:(${dir.value}),expression:${JSON.stringify(dir.value)}` : ''
}${
dir.arg ? `,arg:"${dir.arg}"` : ''
dir.arg ? `,arg:${dir.isDynamicArg ? dir.arg : `"${dir.arg}"`}` : ''
}${
dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : ''
}},`
Expand Down Expand Up @@ -509,17 +515,25 @@ function genComponent (
}

function genProps (props: Array<ASTAttr>): string {
let res = ''
let staticProps = ``
let dynamicProps = ``
for (let i = 0; i < props.length; i++) {
const prop = props[i]
/* istanbul ignore if */
if (__WEEX__) {
res += `"${prop.name}":${generateValue(prop.value)},`
const value = __WEEX__
? generateValue(prop.value)
: transformSpecialNewlines(prop.value)
if (prop.dynamic) {
dynamicProps += `${prop.name},${value},`
} else {
res += `"${prop.name}":${transformSpecialNewlines(prop.value)},`
staticProps += `"${prop.name}":${value},`
}
}
return res.slice(0, -1)
staticProps = `{${staticProps.slice(0, -1)}}`
if (dynamicProps) {
return `_d(${staticProps},[${dynamicProps.slice(0, -1)}])`
} else {
return staticProps
}
}

/* istanbul ignore next */
Expand Down
50 changes: 37 additions & 13 deletions src/compiler/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ export function pluckModuleFunction<F: Function> (
: []
}

export function addProp (el: ASTElement, name: string, value: string, range?: Range) {
(el.props || (el.props = [])).push(rangeSetItem({ name, value }, range))
export function addProp (el: ASTElement, name: string, value: string, range?: Range, dynamic?: boolean) {
(el.props || (el.props = [])).push(rangeSetItem({ name, value, dynamic }, range))
el.plain = false
}

export function addAttr (el: ASTElement, name: string, value: any, range?: Range) {
(el.attrs || (el.attrs = [])).push(rangeSetItem({ name, value }, range))
export function addAttr (el: ASTElement, name: string, value: any, range?: Range, dynamic?: boolean) {
const attrs = dynamic
? (el.dynamicAttrs || (el.dynamicAttrs = []))
: (el.attrs || (el.attrs = []))
attrs.push(rangeSetItem({ name, value, dynamic }, range))
el.plain = false
}

Expand All @@ -42,21 +45,36 @@ export function addDirective (
rawName: string,
value: string,
arg: ?string,
isDynamicArg: boolean,
modifiers: ?ASTModifiers,
range?: Range
) {
(el.directives || (el.directives = [])).push(rangeSetItem({ name, rawName, value, arg, modifiers }, range))
(el.directives || (el.directives = [])).push(rangeSetItem({
name,
rawName,
value,
arg,
isDynamicArg,
modifiers
}, range))
el.plain = false
}

function prependModifierMarker (symbol: string, name: string, dynamic?: boolean): string {
return dynamic
? `_p(${name},"${symbol}")`
: symbol + name // mark the event as captured
}

export function addHandler (
el: ASTElement,
name: string,
value: string,
modifiers: ?ASTModifiers,
important?: boolean,
warn?: ?Function,
range?: Range
range?: Range,
dynamic?: boolean
) {
modifiers = modifiers || emptyObject
// warn prevent and passive modifier
Expand All @@ -75,28 +93,34 @@ export function addHandler (
// normalize click.right and click.middle since they don't actually fire
// this is technically browser-specific, but at least for now browsers are
// the only target envs that have right/middle clicks.
if (name === 'click') {
if (modifiers.right) {
if (modifiers.right) {
if (dynamic) {
name = `(${name})==='click'?'contextmenu':(${name})`
} else if (name === 'click') {
name = 'contextmenu'
delete modifiers.right
} else if (modifiers.middle) {
}
} else if (modifiers.middle) {
if (dynamic) {
name = `(${name})==='click'?'mouseup':(${name})`
} else if (name === 'click') {
name = 'mouseup'
}
}

// check capture modifier
if (modifiers.capture) {
delete modifiers.capture
name = '!' + name // mark the event as captured
name = prependModifierMarker('!', name, dynamic)
}
if (modifiers.once) {
delete modifiers.once
name = '~' + name // mark the event as once
name = prependModifierMarker('~', name, dynamic)
}
/* istanbul ignore if */
if (modifiers.passive) {
delete modifiers.passive
name = '&' + name // mark the event as passive
name = prependModifierMarker('&', name, dynamic)
}

let events
Expand All @@ -107,7 +131,7 @@ export function addHandler (
events = el.events || (el.events = {})
}

const newHandler: any = rangeSetItem({ value: value.trim() }, range)
const newHandler: any = rangeSetItem({ value: value.trim(), dynamic }, range)
if (modifiers !== emptyObject) {
newHandler.modifiers = modifiers
}
Expand Down
Loading