From 7a0bb19d072b65451ba4fff8c19587cbcce95598 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 9 Mar 2018 00:09:53 +0200 Subject: [PATCH] fix(v-on): return handler value when using modifiers (#7704) --- src/compiler/codegen/events.js | 4 +- test/unit/modules/compiler/codegen.spec.js | 91 ++++++++++++++----- .../modules/vdom/patch/edge-cases.spec.js | 37 ++++++++ 3 files changed, 107 insertions(+), 25 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 084c2908dcf..58e7b014760 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -132,9 +132,9 @@ function genHandler ( code += genModifierCode } const handlerCode = isMethodPath - ? handler.value + '($event)' + ? `return ${handler.value}($event)` : isFunctionExpression - ? `(${handler.value})($event)` + ? `return (${handler.value})($event)` : handler.value /* istanbul ignore if */ if (__WEEX__ && handler.params) { diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index a072904ece0..93a27f3b245 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -269,45 +269,90 @@ describe('codegen', () => { ) }) + it('generate events with method call', () => { + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput($event);}}})}` + ) + // empty arguments + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput();}}})}` + ) + // without semicolon + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput($event)}}})}` + ) + // multiple args + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput($event, 'abc', 5);}}})}` + ) + // expression in args + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput($event, 2+2);}}})}` + ) + // tricky symbols in args + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput(');[\'());');}}})}` + ) + }) + + it('generate events with multiple statements', () => { + // normal function + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput1();onInput2()}}})}` + ) + // function with multiple args + assertCodegen( + '', + `with(this){return _c('input',{on:{"input":function($event){onInput1($event, 'text');onInput2('text2', $event)}}})}` + ) + }) + it('generate events with keycode', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;return onInput($event)}}})}` ) // multiple keycodes (delete) assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete"]))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete"]))return null;return onInput($event)}}})}` ) // multiple keycodes (chained) assertCodegen( '', - `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter")&&_k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete"]))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter")&&_k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete"]))return null;return onInput($event)}}})}` ) // number keycode assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&$event.keyCode!==13)return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&$event.keyCode!==13)return null;return onInput($event)}}})}` ) // custom keycode assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"custom",undefined,$event.key,undefined))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"custom",undefined,$event.key,undefined))return null;return onInput($event)}}})}` ) }) it('generate events with generic modifiers', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){$event.stopPropagation();onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){$event.stopPropagation();return onInput($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){$event.preventDefault();onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){$event.preventDefault();return onInput($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){if($event.target !== $event.currentTarget)return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if($event.target !== $event.currentTarget)return null;return onInput($event)}}})}` ) }) @@ -315,74 +360,74 @@ describe('codegen', () => { it('generate events with generic modifiers and keycode correct order', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;$event.preventDefault();onInput($event)}}})}` + `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;$event.preventDefault();return onInput($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;$event.stopPropagation();onInput($event)}}})}` + `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;$event.stopPropagation();return onInput($event)}}})}` ) }) it('generate events with mouse event modifiers', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if(!$event.ctrlKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if(!$event.ctrlKey)return null;return onClick($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if(!$event.shiftKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if(!$event.shiftKey)return null;return onClick($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if(!$event.altKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if(!$event.altKey)return null;return onClick($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;return onClick($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey)return null;return onClick($event)}}})}` ) assertCodegen( '', - `with(this){return _c('input',{on:{"click":function($event){if(!$event.ctrlKey)return null;if($event.shiftKey||$event.altKey||$event.metaKey)return null;onClick($event)}}})}` + `with(this){return _c('input',{on:{"click":function($event){if(!$event.ctrlKey)return null;if($event.shiftKey||$event.altKey||$event.metaKey)return null;return onClick($event)}}})}` ) }) it('generate events with multiple modifiers', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"input":function($event){$event.stopPropagation();$event.preventDefault();if($event.target !== $event.currentTarget)return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){$event.stopPropagation();$event.preventDefault();if($event.target !== $event.currentTarget)return null;return onInput($event)}}})}` ) }) it('generate events with capture modifier', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"!input":function($event){onInput($event)}}})}` + `with(this){return _c('input',{on:{"!input":function($event){return onInput($event)}}})}` ) }) it('generate events with once modifier', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"~input":function($event){onInput($event)}}})}` + `with(this){return _c('input',{on:{"~input":function($event){return onInput($event)}}})}` ) }) it('generate events with capture and once modifier', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"~!input":function($event){onInput($event)}}})}` + `with(this){return _c('input',{on:{"~!input":function($event){return onInput($event)}}})}` ) }) it('generate events with once and capture modifier', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"~!input":function($event){onInput($event)}}})}` + `with(this){return _c('input',{on:{"~!input":function($event){return onInput($event)}}})}` ) }) @@ -427,7 +472,7 @@ describe('codegen', () => { // with modifiers assertCodegen( ``, - `with(this){return _c('input',{on:{"keyup":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;(e=>current++)($event)}}})}` + `with(this){return _c('input',{on:{"keyup":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key,"Enter"))return null;return (e=>current++)($event)}}})}` ) }) @@ -452,7 +497,7 @@ describe('codegen', () => { it('generate multiple event handlers', () => { assertCodegen( '', - `with(this){return _c('input',{on:{"input":[function($event){current++},function($event){$event.stopPropagation();onInput($event)}]}})}` + `with(this){return _c('input',{on:{"input":[function($event){current++},function($event){$event.stopPropagation();return onInput($event)}]}})}` ) }) diff --git a/test/unit/modules/vdom/patch/edge-cases.spec.js b/test/unit/modules/vdom/patch/edge-cases.spec.js index 8d07f76dc33..adcfc95eedc 100644 --- a/test/unit/modules/vdom/patch/edge-cases.spec.js +++ b/test/unit/modules/vdom/patch/edge-cases.spec.js @@ -25,6 +25,43 @@ describe('vdom patch: edge cases', () => { }).then(done) }) + // exposed by #7705 + // methods and function expressions with modifiers should return result instead of undefined + // skipped odd children[1,3, ...] because they are rendered as text nodes with undefined value + it('should return listener\'s result for method name and function expression with and w/o modifiers', done => { + const dummyEvt = { preventDefault: () => {} } + new Vue({ + template: ` +
+
+
+
+
+
+ `, + methods: { + addFive ($event, toAdd = 0) { + return toAdd + 5 + } + }, + directives: { + test: { + bind (el, binding, vnode) { + waitForUpdate(() => { + expect(vnode.children[0].data.on.click()).toBe(5) + }).then(() => { + expect(vnode.children[2].data.on.click(dummyEvt)).toBe(5) + }).then(() => { + expect(vnode.children[4].data.on.click()).not.toBeDefined() + }).then(() => { + expect(vnode.children[6].data.on.click(dummyEvt)).not.toBeDefined() + }).then(done) + } + } + } + }).$mount() + }) + // #3533 // a static node is reused in createElm, which changes its elm reference // and is inserted into a different parent.