UNPKG

vue

Version:

Reactive, component-oriented view layer for modern web interfaces.

122 lines (110 loc) 3.57 kB
/* @flow */ const fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/ const simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?']|\[".*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*\s*$/ // keyCode aliases const keyCodes: { [key: string]: number | Array<number> } = { esc: 27, tab: 9, enter: 13, space: 32, up: 38, left: 37, right: 39, down: 40, 'delete': [8, 46] } // #4868: modifiers that prevent the execution of the listener // need to explicitly return null so that we can determine whether to remove // the listener for .once const genGuard = condition => `if(${condition})return null;` const modifierCode: { [key: string]: string } = { stop: '$event.stopPropagation();', prevent: '$event.preventDefault();', self: genGuard(`$event.target !== $event.currentTarget`), ctrl: genGuard(`!$event.ctrlKey`), shift: genGuard(`!$event.shiftKey`), alt: genGuard(`!$event.altKey`), meta: genGuard(`!$event.metaKey`), left: genGuard(`'button' in $event && $event.button !== 0`), middle: genGuard(`'button' in $event && $event.button !== 1`), right: genGuard(`'button' in $event && $event.button !== 2`) } export function genHandlers ( events: ASTElementHandlers, isNative: boolean, warn: Function ): string { let res = isNative ? 'nativeOn:{' : 'on:{' for (const name in events) { const handler = events[name] // #5330: warn click.right, since right clicks do not actually fire click events. if (process.env.NODE_ENV !== 'production' && name === 'click' && handler && handler.modifiers && handler.modifiers.right ) { warn( `Use "contextmenu" instead of "click.right" since right clicks ` + `do not actually fire "click" events.` ) } res += `"${name}":${genHandler(name, handler)},` } return res.slice(0, -1) + '}' } function genHandler ( name: string, handler: ASTElementHandler | Array<ASTElementHandler> ): string { if (!handler) { return 'function(){}' } if (Array.isArray(handler)) { return `[${handler.map(handler => genHandler(name, handler)).join(',')}]` } const isMethodPath = simplePathRE.test(handler.value) const isFunctionExpression = fnExpRE.test(handler.value) if (!handler.modifiers) { return isMethodPath || isFunctionExpression ? handler.value : `function($event){${handler.value}}` // inline statement } else { let code = '' let genModifierCode = '' const keys = [] for (const key in handler.modifiers) { if (modifierCode[key]) { genModifierCode += modifierCode[key] // left/right if (keyCodes[key]) { keys.push(key) } } else { keys.push(key) } } if (keys.length) { code += genKeyFilter(keys) } // Make sure modifiers like prevent and stop get executed after key filtering if (genModifierCode) { code += genModifierCode } const handlerCode = isMethodPath ? handler.value + '($event)' : isFunctionExpression ? `(${handler.value})($event)` : handler.value return `function($event){${code}${handlerCode}}` } } function genKeyFilter (keys: Array<string>): string { return `if(!('button' in $event)&&${keys.map(genFilterCode).join('&&')})return null;` } function genFilterCode (key: string): string { const keyVal = parseInt(key, 10) if (keyVal) { return `$event.keyCode!==${keyVal}` } const alias = keyCodes[key] return `_k($event.keyCode,${JSON.stringify(key)}${alias ? ',' + JSON.stringify(alias) : ''})` }