From 38f51b0563c05f259b0c7c5420883fa76c758660 Mon Sep 17 00:00:00 2001 From: Nick Messing Date: Tue, 27 Jun 2017 09:27:40 +1200 Subject: [PATCH 1/4] feat($compile): Add .plain event modifier Add a new event modifier `.plain` to check if event is "plain" (no shift/ctrl/meta/alt key is pressed) https://github.com/vuejs/vue/issues/5976 --- src/compiler/codegen/events.js | 3 ++- src/core/instance/proxy.js | 2 +- test/unit/modules/compiler/codegen.spec.js | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 6a64e1a1919..53443b90108 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -31,7 +31,8 @@ const modifierCode: { [key: string]: string } = { 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`) + right: genGuard(`'button' in $event && $event.button !== 2`), + plain: genGuard(`$event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey`) } export function genHandlers ( diff --git a/src/core/instance/proxy.js b/src/core/instance/proxy.js index 8e581877bde..863673539a3 100644 --- a/src/core/instance/proxy.js +++ b/src/core/instance/proxy.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'production') { Proxy.toString().match(/native code/) if (hasProxy) { - const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta') + const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,plain') config.keyCodes = new Proxy(config.keyCodes, { set (target, key, value) { if (isBuiltInModifier(key)) { diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 8138164146d..fa17d2f1f35 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -298,6 +298,10 @@ describe('codegen', () => { '', `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;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)}}})}` + ) }) it('generate events with multiple modifiers', () => { From b5420276d6538e73f38c311863b3ac5f3dd0056b Mon Sep 17 00:00:00 2001 From: Nicolai Moraru Date: Mon, 14 Aug 2017 09:21:39 +1200 Subject: [PATCH 2/4] Rename to "bare" --- src/compiler/codegen/events.js | 2 +- src/core/instance/proxy.js | 2 +- test/unit/modules/compiler/codegen.spec.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index 53443b90108..b82b4d10e4d 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -32,7 +32,7 @@ const modifierCode: { [key: string]: string } = { left: genGuard(`'button' in $event && $event.button !== 0`), middle: genGuard(`'button' in $event && $event.button !== 1`), right: genGuard(`'button' in $event && $event.button !== 2`), - plain: genGuard(`$event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey`) + bare: genGuard(`$event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey`) } export function genHandlers ( diff --git a/src/core/instance/proxy.js b/src/core/instance/proxy.js index 863673539a3..f115c76f7a5 100644 --- a/src/core/instance/proxy.js +++ b/src/core/instance/proxy.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'production') { Proxy.toString().match(/native code/) if (hasProxy) { - const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,plain') + const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,bare') config.keyCodes = new Proxy(config.keyCodes, { set (target, key, value) { if (isBuiltInModifier(key)) { diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index fa17d2f1f35..2bdb010c4e7 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -299,7 +299,7 @@ describe('codegen', () => { `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;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)}}})}` ) }) From b6ca3374a2dd20e9fce6865a88bba2d49aa9ce27 Mon Sep 17 00:00:00 2001 From: Nicolai Moraru Date: Sun, 20 Aug 2017 16:01:59 +1200 Subject: [PATCH 3/4] Make bare smart so it can be used with key modifiers --- src/compiler/codegen/events.js | 11 +++++++++-- test/unit/modules/compiler/codegen.spec.js | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index b82b4d10e4d..eb1b55bce10 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -31,8 +31,7 @@ const modifierCode: { [key: string]: string } = { 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`), - bare: genGuard(`$event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey`) + right: genGuard(`'button' in $event && $event.button !== 2`) } export function genHandlers ( @@ -88,6 +87,14 @@ function genHandler ( if (keyCodes[key]) { keys.push(key) } + } else if (key === 'bare') { + const modifiers: ASTModifiers = (handler.modifiers: any) + genModifierCode += genGuard( + ['ctrl', 'shift', 'alt', 'meta'] + .filter(keyModifier => !modifiers[keyModifier]) + .map(keyModifier => `$event.${keyModifier}Key`) + .join(' || ') + ) } else { keys.push(key) } diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 2bdb010c4e7..1f1099b8358 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -302,6 +302,10 @@ describe('codegen', () => { '', `with(this){return _c('input',{on:{"click":function($event){if($event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey)return null;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)}}})}` + ) }) it('generate events with multiple modifiers', () => { From bf1c9c9365afbea99580b0d1bd52edbfa85099f6 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 4 Oct 2017 11:30:09 -0400 Subject: [PATCH 4/4] refactor: rename to exact, add tests --- src/compiler/codegen/events.js | 6 +- src/core/instance/proxy.js | 2 +- test/unit/features/directives/on.spec.js | 92 +++++++++++++++++++++- test/unit/modules/compiler/codegen.spec.js | 8 +- 4 files changed, 99 insertions(+), 9 deletions(-) diff --git a/src/compiler/codegen/events.js b/src/compiler/codegen/events.js index eb1b55bce10..67ae0368b65 100644 --- a/src/compiler/codegen/events.js +++ b/src/compiler/codegen/events.js @@ -87,14 +87,14 @@ function genHandler ( if (keyCodes[key]) { keys.push(key) } - } else if (key === 'bare') { + } else if (key === 'exact') { const modifiers: ASTModifiers = (handler.modifiers: any) genModifierCode += genGuard( ['ctrl', 'shift', 'alt', 'meta'] .filter(keyModifier => !modifiers[keyModifier]) .map(keyModifier => `$event.${keyModifier}Key`) - .join(' || ') - ) + .join('||') + ) } else { keys.push(key) } diff --git a/src/core/instance/proxy.js b/src/core/instance/proxy.js index f115c76f7a5..2c9837cfade 100644 --- a/src/core/instance/proxy.js +++ b/src/core/instance/proxy.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'production') { Proxy.toString().match(/native code/) if (hasProxy) { - const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,bare') + const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact') config.keyCodes = new Proxy(config.keyCodes, { set (target, key, value) { if (isBuiltInModifier(key)) { diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index e77d18d74ed..5b6c1febd9e 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -205,6 +205,96 @@ describe('Directive v-on', () => { expect(spy).toHaveBeenCalled() }) + // ctrl, shift, alt, meta + it('should support system modifers', () => { + vm = new Vue({ + el, + template: ` +
+ + + + +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(0) + triggerEvent(vm.$refs.ctrl, 'keyup', e => { e.ctrlKey = true }) + expect(spy.calls.count()).toBe(1) + + triggerEvent(vm.$refs.shift, 'keyup') + expect(spy.calls.count()).toBe(1) + triggerEvent(vm.$refs.shift, 'keyup', e => { e.shiftKey = true }) + expect(spy.calls.count()).toBe(2) + + triggerEvent(vm.$refs.alt, 'keyup') + expect(spy.calls.count()).toBe(2) + triggerEvent(vm.$refs.alt, 'keyup', e => { e.altKey = true }) + expect(spy.calls.count()).toBe(3) + + triggerEvent(vm.$refs.meta, 'keyup') + expect(spy.calls.count()).toBe(3) + triggerEvent(vm.$refs.meta, 'keyup', e => { e.metaKey = true }) + expect(spy.calls.count()).toBe(4) + }) + + it('should support exact modifier', () => { + vm = new Vue({ + el, + template: ` +
+ +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(1) + + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + }) + expect(spy.calls.count()).toBe(1) + + // should not trigger if has other system modifiers + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + e.altKey = true + }) + expect(spy.calls.count()).toBe(1) + }) + + it('should support system modifers with exact', () => { + vm = new Vue({ + el, + template: ` +
+ +
+ `, + methods: { foo: spy } + }) + + triggerEvent(vm.$refs.ctrl, 'keyup') + expect(spy.calls.count()).toBe(0) + + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + }) + expect(spy.calls.count()).toBe(1) + + // should not trigger if has other system modifiers + triggerEvent(vm.$refs.ctrl, 'keyup', e => { + e.ctrlKey = true + e.altKey = true + }) + expect(spy.calls.count()).toBe(1) + }) + it('should support number keyCode', () => { vm = new Vue({ el, @@ -492,7 +582,7 @@ describe('Directive v-on', () => { }) // Github Issue #5046 - it('should support keyboard modifier', () => { + it('should support keyboard modifier for direction keys', () => { const spyLeft = jasmine.createSpy() const spyRight = jasmine.createSpy() const spyUp = jasmine.createSpy() diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 1f1099b8358..cafc0bd3bc6 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -299,12 +299,12 @@ describe('codegen', () => { `with(this){return _c('input',{on:{"click":function($event){if(!$event.metaKey)return null;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;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;onClick($event)}}})}` ) })