diff --git a/src/directives/public/on.js b/src/directives/public/on.js
index 3c1c74e7f87..1a326b14ef4 100644
--- a/src/directives/public/on.js
+++ b/src/directives/public/on.js
@@ -14,6 +14,12 @@ const keyCodes = {
down: 40
}
+const eventKeys = ['stop', 'prevent', 'self', 'capture']
+const modifierKeys = ['ctrl', 'shift', 'alt', 'meta']
+const namedKeys = eventKeys.concat(modifierKeys).sort()
+
+var modifierKeyHandlers = {}
+
function keyFilter (handler, keys) {
var codes = keys.map(function (key) {
var charCode = key.charCodeAt(0)
@@ -58,6 +64,17 @@ function selfFilter (handler) {
}
}
+modifierKeys.forEach((key) => {
+ var keyName = key + 'Key'
+ modifierKeyHandlers[key] = function (handler) {
+ return function (e) {
+ if (e[keyName]) {
+ return handler.call(this, e)
+ }
+ }
+ }
+})
+
export default {
priority: ON,
@@ -110,13 +127,15 @@ export default {
if (this.modifiers.self) {
handler = selfFilter(handler)
}
+ modifierKeys.forEach((key) => {
+ if (this.modifiers[key]) {
+ handler = modifierKeyHandlers[key](handler)
+ }
+ })
// key filter
var keys = Object.keys(this.modifiers)
.filter(function (key) {
- return key !== 'stop' &&
- key !== 'prevent' &&
- key !== 'self' &&
- key !== 'capture'
+ return namedKeys.indexOf(key) === -1
})
if (keys.length) {
handler = keyFilter(handler, keys)
diff --git a/test/unit/specs/directives/public/on_spec.js b/test/unit/specs/directives/public/on_spec.js
index 49881077a64..eda11e03b88 100644
--- a/test/unit/specs/directives/public/on_spec.js
+++ b/test/unit/specs/directives/public/on_spec.js
@@ -86,6 +86,353 @@ describe('v-on', function () {
})
})
+ it('with ctrl modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.ctrlKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with shift modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.shiftKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with ctrl + shift modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.ctrlKey = true
+ e.shiftKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with ctrl + alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.ctrlKey = true
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with shift + alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.shiftKey = true
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with ctrl + shift + alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.ctrlKey = true
+ e.shiftKey = true
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + shift modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.shiftKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + ctrl modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.ctrlKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + shift + alt modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.shiftKey = true
+ e.altKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + shift + ctrl modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.shiftKey = true
+ e.ctrlKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + alt + ctrl modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.altKey = true
+ e.ctrlKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
+ it('with meta + shift + alt + ctrl modifier', function (done) {
+ new Vue({
+ el: el,
+ template: '{{a}}',
+ data: {a: 1},
+ methods: {
+ test: function () {
+ this.a++
+ }
+ }
+ })
+ var a = el.firstChild
+ trigger(a, 'keyup', function (e) {
+ e.keyCode = 65
+ e.metaKey = true
+ e.shiftKey = true
+ e.altKey = true
+ e.ctrlKey = true
+ })
+ _.nextTick(function () {
+ expect(a.textContent).toBe('2')
+ done()
+ })
+ })
+
it('with delete modifier capturing DEL', function (done) {
new Vue({
el: el,