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,