1 |
|
2 |
|
3 | const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/
|
4 | const fnInvokeRE = /\([^)]*?\);*$/
|
5 | const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
|
6 |
|
7 |
|
8 | const keyCodes: { [key: string]: number | Array<number> } = {
|
9 | esc: 27,
|
10 | tab: 9,
|
11 | enter: 13,
|
12 | space: 32,
|
13 | up: 38,
|
14 | left: 37,
|
15 | right: 39,
|
16 | down: 40,
|
17 | 'delete': [8, 46]
|
18 | }
|
19 |
|
20 |
|
21 | const keyNames: { [key: string]: string | Array<string> } = {
|
22 |
|
23 | esc: ['Esc', 'Escape'],
|
24 | tab: 'Tab',
|
25 | enter: 'Enter',
|
26 |
|
27 | space: [' ', 'Spacebar'],
|
28 |
|
29 | up: ['Up', 'ArrowUp'],
|
30 | left: ['Left', 'ArrowLeft'],
|
31 | right: ['Right', 'ArrowRight'],
|
32 | down: ['Down', 'ArrowDown'],
|
33 |
|
34 | 'delete': ['Backspace', 'Delete', 'Del']
|
35 | }
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | const genGuard = condition => `if(${condition})return null;`
|
41 |
|
42 | const modifierCode: { [key: string]: string } = {
|
43 | stop: '$event.stopPropagation();',
|
44 | prevent: '$event.preventDefault();',
|
45 | self: genGuard(`$event.target !== $event.currentTarget`),
|
46 | ctrl: genGuard(`!$event.ctrlKey`),
|
47 | shift: genGuard(`!$event.shiftKey`),
|
48 | alt: genGuard(`!$event.altKey`),
|
49 | meta: genGuard(`!$event.metaKey`),
|
50 | left: genGuard(`'button' in $event && $event.button !== 0`),
|
51 | middle: genGuard(`'button' in $event && $event.button !== 1`),
|
52 | right: genGuard(`'button' in $event && $event.button !== 2`)
|
53 | }
|
54 |
|
55 | export function genHandlers (
|
56 | events: ASTElementHandlers,
|
57 | isNative: boolean
|
58 | ): string {
|
59 | const prefix = isNative ? 'nativeOn:' : 'on:'
|
60 | let staticHandlers = ``
|
61 | let dynamicHandlers = ``
|
62 | for (const name in events) {
|
63 | const handlerCode = genHandler(events[name])
|
64 | if (events[name] && events[name].dynamic) {
|
65 | dynamicHandlers += `${name},${handlerCode},`
|
66 | } else {
|
67 | staticHandlers += `"${name}":${handlerCode},`
|
68 | }
|
69 | }
|
70 | staticHandlers = `{${staticHandlers.slice(0, -1)}}`
|
71 | if (dynamicHandlers) {
|
72 | return prefix + `_d(${staticHandlers},[${dynamicHandlers.slice(0, -1)}])`
|
73 | } else {
|
74 | return prefix + staticHandlers
|
75 | }
|
76 | }
|
77 |
|
78 |
|
79 |
|
80 | function genWeexHandler (params: Array<any>, handlerCode: string) {
|
81 | let innerHandlerCode = handlerCode
|
82 | const exps = params.filter(exp => simplePathRE.test(exp) && exp !== '$event')
|
83 | const bindings = exps.map(exp => ({ '@binding': exp }))
|
84 | const args = exps.map((exp, i) => {
|
85 | const key = `$_${i + 1}`
|
86 | innerHandlerCode = innerHandlerCode.replace(exp, key)
|
87 | return key
|
88 | })
|
89 | args.push('$event')
|
90 | return '{\n' +
|
91 | `handler:function(${args.join(',')}){${innerHandlerCode}},\n` +
|
92 | `params:${JSON.stringify(bindings)}\n` +
|
93 | '}'
|
94 | }
|
95 |
|
96 | function genHandler (handler: ASTElementHandler | Array<ASTElementHandler>): string {
|
97 | if (!handler) {
|
98 | return 'function(){}'
|
99 | }
|
100 |
|
101 | if (Array.isArray(handler)) {
|
102 | return `[${handler.map(handler => genHandler(handler)).join(',')}]`
|
103 | }
|
104 |
|
105 | const isMethodPath = simplePathRE.test(handler.value)
|
106 | const isFunctionExpression = fnExpRE.test(handler.value)
|
107 | const isFunctionInvocation = simplePathRE.test(handler.value.replace(fnInvokeRE, ''))
|
108 |
|
109 | if (!handler.modifiers) {
|
110 | if (isMethodPath || isFunctionExpression) {
|
111 | return handler.value
|
112 | }
|
113 |
|
114 | if (__WEEX__ && handler.params) {
|
115 | return genWeexHandler(handler.params, handler.value)
|
116 | }
|
117 | return `function($event){${
|
118 | isFunctionInvocation ? `return ${handler.value}` : handler.value
|
119 | }}`
|
120 | } else {
|
121 | let code = ''
|
122 | let genModifierCode = ''
|
123 | const keys = []
|
124 | for (const key in handler.modifiers) {
|
125 | if (modifierCode[key]) {
|
126 | genModifierCode += modifierCode[key]
|
127 |
|
128 | if (keyCodes[key]) {
|
129 | keys.push(key)
|
130 | }
|
131 | } else if (key === 'exact') {
|
132 | const modifiers: ASTModifiers = (handler.modifiers: any)
|
133 | genModifierCode += genGuard(
|
134 | ['ctrl', 'shift', 'alt', 'meta']
|
135 | .filter(keyModifier => !modifiers[keyModifier])
|
136 | .map(keyModifier => `$event.${keyModifier}Key`)
|
137 | .join('||')
|
138 | )
|
139 | } else {
|
140 | keys.push(key)
|
141 | }
|
142 | }
|
143 | if (keys.length) {
|
144 | code += genKeyFilter(keys)
|
145 | }
|
146 |
|
147 | if (genModifierCode) {
|
148 | code += genModifierCode
|
149 | }
|
150 | const handlerCode = isMethodPath
|
151 | ? `return ${handler.value}($event)`
|
152 | : isFunctionExpression
|
153 | ? `return (${handler.value})($event)`
|
154 | : isFunctionInvocation
|
155 | ? `return ${handler.value}`
|
156 | : handler.value
|
157 |
|
158 | if (__WEEX__ && handler.params) {
|
159 | return genWeexHandler(handler.params, code + handlerCode)
|
160 | }
|
161 | return `function($event){${code}${handlerCode}}`
|
162 | }
|
163 | }
|
164 |
|
165 | function genKeyFilter (keys: Array<string>): string {
|
166 | return (
|
167 |
|
168 |
|
169 |
|
170 | `if(!$event.type.indexOf('key')&&` +
|
171 | `${keys.map(genFilterCode).join('&&')})return null;`
|
172 | )
|
173 | }
|
174 |
|
175 | function genFilterCode (key: string): string {
|
176 | const keyVal = parseInt(key, 10)
|
177 | if (keyVal) {
|
178 | return `$event.keyCode!==${keyVal}`
|
179 | }
|
180 | const keyCode = keyCodes[key]
|
181 | const keyName = keyNames[key]
|
182 | return (
|
183 | `_k($event.keyCode,` +
|
184 | `${JSON.stringify(key)},` +
|
185 | `${JSON.stringify(keyCode)},` +
|
186 | `$event.key,` +
|
187 | `${JSON.stringify(keyName)}` +
|
188 | `)`
|
189 | )
|
190 | }
|