From c06555324e6f34e184d8893d86763bcab8151eed Mon Sep 17 00:00:00 2001 From: alex-stepchenkov-neyber Date: Thu, 1 Mar 2018 13:51:02 +0200 Subject: [PATCH 1/3] Return only when the provided expression is a function but not when it is a statement or expression --- src/compiler/codegen/events.js | 2 +- test/unit/modules/compiler/codegen.spec.js | 44 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 722e32a4d60..9ebd8f531c5 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -119,7 +119,7 @@ function genHandler ( code += genModifierCode } const handlerCode = isMethodPath - ? handler.value + '($event)' + ? `return ${handler.value}($event)` : isFunctionExpression ? `(${handler.value})($event)` : handler.value diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 745ef33c228..b5e5a267570 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -265,42 +265,42 @@ describe('codegen', () => { 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))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key))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))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))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)&&_k($event.keyCode,"delete",[8,46],$event.key))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"keydown":function($event){if(!('button' in $event)&&_k($event.keyCode,"enter",13,$event.key)&&_k($event.keyCode,"delete",[8,46],$event.key))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))return null;onInput($event)}}})}` + `with(this){return _c('input',{on:{"input":function($event){if(!('button' in $event)&&_k($event.keyCode,"custom",undefined,$event.key))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)}}})}` ) }) @@ -308,74 +308,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))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))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))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))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)}}})}` ) }) @@ -445,7 +445,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)}]}})}` ) }) From d4569337cf992d562c4b5c1bbbefe13031efb6da Mon Sep 17 00:00:00 2001 From: alex-stepchenkov-neyber Date: Thu, 1 Mar 2018 15:50:07 +0200 Subject: [PATCH 2/3] Return value for function expression --- src/compiler/codegen/events.js | 2 +- test/unit/modules/compiler/codegen.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 9ebd8f531c5..1cbff814d1e 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -121,7 +121,7 @@ function genHandler ( const handlerCode = isMethodPath ? `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 b5e5a267570..c0b7e78f620 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -420,7 +420,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))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))return null;return (e=>current++)($event)}}})}` ) }) From 9e9f6c53694910664a2519749708803474bea768 Mon Sep 17 00:00:00 2001 From: alex-stepchenkov-neyber Date: Sat, 3 Mar 2018 04:30:55 +0200 Subject: [PATCH 3/3] Add more tests for #7704 --- test/unit/modules/compiler/codegen.spec.js | 45 +++++++++++++++++++ .../modules/vdom/patch/edge-cases.spec.js | 37 +++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index c0b7e78f620..992a53ccca8 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -262,6 +262,51 @@ 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( '', diff --git a/test/unit/modules/vdom/patch/edge-cases.spec.js b/test/unit/modules/vdom/patch/edge-cases.spec.js index df60d0132ee..3d0a8b83628 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.