diff options
author | Robert Pocklington <rpocklin@gmail.com> | 2014-08-19 17:54:13 +1000 |
---|---|---|
committer | Robert Pocklington <rpocklin@gmail.com> | 2014-08-19 17:54:13 +1000 |
commit | b5eb6502bbbe903a87d8a1f92f2613d94e4cf489 (patch) | |
tree | d15ede816877e1c52f0e0c75df6b63854c289969 | |
parent | c245b704fa6ae7c9e1646f051df4ef885063dbba (diff) | |
parent | 950ece85b4c5b18451a809b1f4b79720e05f8378 (diff) | |
download | jquery.hotkeys-b5eb6502bbbe903a87d8a1f92f2613d94e4cf489.zip jquery.hotkeys-b5eb6502bbbe903a87d8a1f92f2613d94e4cf489.tar.gz jquery.hotkeys-b5eb6502bbbe903a87d8a1f92f2613d94e4cf489.tar.bz2 |
Merge pull request #44 from rpocklin/master
Batch update of specs and fixing a few regression issues on keypress.
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | jquery.hotkeys.js | 19 | ||||
-rw-r--r-- | test/SpecRunner.html | 2 | ||||
-rw-r--r-- | test/spec/bindingSpec.js | 164 | ||||
-rw-r--r-- | test/spec/keyBindingSpec.js | 141 |
5 files changed, 156 insertions, 172 deletions
@@ -35,7 +35,7 @@ $('input.foo').on('keyup', null, '$', function(){ ## Example -[Example](http://htmlpreview.github.com/?https://github.com/jeresig/jquery.hotkeys/master/test-static-05.html) +[Example](https://rawgit.com/jeresig/jquery.hotkeys/master/test-static-01.html) ## Event Types diff --git a/jquery.hotkeys.js b/jquery.hotkeys.js index e4f57d2..18a80dd 100644 --- a/jquery.hotkeys.js +++ b/jquery.hotkeys.js @@ -135,31 +135,38 @@ keys = handleObj.data.keys.toLowerCase().split(" "); handleObj.handler = function(event) { - // Don't fire in text-accepting inputs that we didn't directly bind to + // Don't fire in text-accepting inputs that we didn't directly bind to if (this !== event.target && (/textarea|select/i.test(event.target.nodeName) || (jQuery.hotkeys.options.filterTextInputs && jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) { return; } - var special = jQuery.hotkeys.specialKeys[event.keyCode], + var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which], character = String.fromCharCode(event.which).toLowerCase(), modif = "", possible = {}; - jQuery.each(["alt", "ctrl", "meta", "shift"], function(index, specialKey) { + jQuery.each(["alt", "ctrl", "shift"], function(index, specialKey) { + if (event[specialKey + 'Key'] && special !== specialKey) { modif += specialKey + '+'; } }); - modif = modif.replace('alt+ctrl+meta+shift', 'hyper'); + // metaKey is triggered off ctrlKey erronously + if (event.metaKey && !event.ctrlKey && special !== "meta") { + modif += "meta+"; + } + + if (event.metaKey && special !== "meta" && modif.indexOf("alt+ctrl+shift+") > -1) { + modif = modif.replace("alt+ctrl+shift+", "hyper+"); + } if (special) { possible[modif + special] = true; } - - if (character) { + else { possible[modif + character] = true; possible[modif + jQuery.hotkeys.shiftNums[character]] = true; diff --git a/test/SpecRunner.html b/test/SpecRunner.html index f1b0583..19faa49 100644 --- a/test/SpecRunner.html +++ b/test/SpecRunner.html @@ -32,7 +32,7 @@ <script src="lib/underscore.js"></script> - <script src="spec/bindingSpec.js"></script> + <script src="spec/keyBindingSpec.js"></script> <script src="../.grunt/grunt-contrib-jasmine/reporter.js"></script> diff --git a/test/spec/bindingSpec.js b/test/spec/bindingSpec.js deleted file mode 100644 index 9e1832f..0000000 --- a/test/spec/bindingSpec.js +++ /dev/null @@ -1,164 +0,0 @@ -// use http://jonathan.tang.name/files/js_keycode/test_keycode.html -// to discover key codes -describe("binding functions to key combinations", function() { - - beforeEach(function() { - - jQuery.hotkeys.options.filterTextInputs = true; - - this.cleanup = function($el) { - $el.remove(); - $(document).unbind(); - }; - - this.bindAndTriggerKeyEvent = function(keyAsText, keyCode, callback, keyModifiers) { - - var keyEvent = 'keyup'; - - keyModifiers = _.extend({ - ctrl: false, - alt: false, - shift: false, - meta: false - }, keyModifiers); - - $(document).bind(keyEvent, keyAsText, callback); - var event = this.createKeyEvent(keyCode, keyEvent); - - event.altKey = !!keyModifiers.alt; - event.ctrlKey = !!keyModifiers.ctrl; - event.shiftKey = !!keyModifiers['shift']; - event.metaKey = !!keyModifiers.meta; - - return $(document).trigger(event); - }; - - this.assertTextInputKeyEventTriggered = function(bindDirectly, expectToBeTriggered) { - - var keyEvent = 'keyup'; - var keyCode = '65'; - var keyAsText = 'a'; - - var i = 0; - - _.each(this.textInputTypes, function(input_type) { - var spy = sinon.spy(); - - var $el = this.createInputEl(input_type, ++i); - var $bindElement = bindDirectly ? $el : $(document); - - $bindElement.bind(keyEvent, keyAsText, spy); - - var event = this.createKeyEvent(keyCode); - $el.trigger(event); - - expectToBeTriggered ? sinon.assert.calledOnce(spy) : sinon.assert.notCalled(spy); - this.cleanup($el); - - }, this); - }; - - this.callbackFn = sinon.spy(); - - this.fixture = $('<div id="container"></div>'); - $('body').append(this.fixture); - - this.createInputEl = function(type, id) { - var $el = $('<input type="' + type + '" id="' + id + '"/>'); - this.fixture.append($el); - return $el; - }; - - this.textInputTypes = jQuery.hotkeys.textAcceptingInputTypes; - - // creates new key event - this.createKeyEvent = function(keyCode, keyEvent) { - keyEvent = keyEvent || 'keyup'; - - var event = jQuery.Event(keyEvent); - event.keyCode = keyCode; - event.which = keyCode; - - return event; - }; - }); - - afterEach(function() { - this.cleanup(this.fixture); - }); - - it("should bind the 'return' key to the document and trigger the bound callback", function() { - - this.bindAndTriggerKeyEvent('return', '13', this.callbackFn); - sinon.assert.calledOnce(this.callbackFn); - }); - - it("should bind the 'alt+s' keys and call the callback handler function", function() { - - this.bindAndTriggerKeyEvent('alt+a', '65', this.callbackFn, { - alt: true - }); - sinon.assert.calledOnce(this.callbackFn); - }); - - it("should bind the 'shift+pagedown' keys and call the callback handler function", function() { - - this.bindAndTriggerKeyEvent('shift+pagedown', '34', this.callbackFn, { - shift: true - }); - sinon.assert.calledOnce(this.callbackFn); - }); - - it("should bind the 'alt+shift+a' with a namespace, trigger the callback handler and unbind correctly", function() { - - var spy = sinon.spy(); - - $(document).bind('keyup.a', 'alt+shift+a', spy); - $(document).bind('keyup.b', 'alt+shift+a', spy); - $(document).unbind('keyup.a'); // remove first binding, leaving only second - - this.bindAndTriggerKeyEvent('alt+shift+a', '65', this.callbackFn, { - shift: true, - alt: true - }); - - // ensure only second binding is still in effect - sinon.assert.calledOnce(spy); - }); - - it("should bind the 'meta+a' keys and call the callback handler function", function() { - - this.bindAndTriggerKeyEvent('meta+a', '65', this.callbackFn, { - meta: true - }); - sinon.assert.calledOnce(this.callbackFn); - }); - - it("should bind the 'hyper+a' keys and call the callback handler function", function() { - - this.bindAndTriggerKeyEvent('hyper+a', '65', this.callbackFn, { - meta: true, - shift: true, - alt: true, - ctrl: true - }); - sinon.assert.calledOnce(this.callbackFn); - }); - - it("should not trigger event handler callbacks bound to any standard input types if not bound directly", function() { - - this.assertTextInputKeyEventTriggered(false, false); - }); - - it("should bind and trigger events from a text input element if bound directly", function() { - - this.assertTextInputKeyEventTriggered(true, true); - }); - - it("should trigger event handler callbacks bound to any text input types if filter is turned off", function() { - - jQuery.hotkeys.options.filterTextInputs = false; - this.assertTextInputKeyEventTriggered(false, true); - }); - -}); diff --git a/test/spec/keyBindingSpec.js b/test/spec/keyBindingSpec.js new file mode 100644 index 0000000..a2d6309 --- /dev/null +++ b/test/spec/keyBindingSpec.js @@ -0,0 +1,141 @@ +// use http://jonathan.tang.name/files/js_keycode/test_keycode.html +// to discover key codes + +// NOTE: keypress events will only test correctly on single keypresses (or in combination with a shift key) +describe("binding functions to key combinations", function() { + + beforeEach(function() { + + this.callbackFn = sinon.spy(); + + this.fixture = $('<div id="container"></div>'); + $('body').append(this.fixture); + + this.createInputEl = function(type, id) { + var $el = $('<input type="' + type + '" id="' + id + '"/>'); + this.fixture.append($el); + return $el; + }; + + this.text_input_types = ["text", "password", "number", "email", "url", "range", "date", "month", "week", + "time", "datetime", "datetime-local", "search", "color", "tel"]; + + // creates new key event + this.createKeyEvent = function(keyCode, keyEventType) { + + keyEventType = keyEventType || 'keyup'; + + var event = jQuery.Event(keyEventType); + event.keyCode = keyCode; + event.which = keyCode; + + return event; + }; + + this.assertHotKeyBinding = function(keyEvent, keyCombinationAsText, keyCombinationAsKeyCode, modifiers, $el) { + + if (!keyEvent || !keyCombinationAsText || !keyCombinationAsKeyCode) { + throw new Error("Missing arguments for assertion, check your arguments."); + } + + modifiers = modifiers || []; + $el = $el || $(document); + + var spy = sinon.spy(); + + $el.bind(keyEvent, keyCombinationAsText, spy); + + var event = this.createKeyEvent(keyCombinationAsKeyCode, keyEvent); + + $.each(modifiers, function(index, modifier) { + event[modifier + 'Key'] = true; + }); + + $el.trigger(event); + sinon.assert.calledOnce(spy); + } + }); + + afterEach(function() { + this.fixture.remove(); + $(document).unbind(); + }); + + it("should bind the 'return' key to the document and trigger the bound callback", function() { + this.assertHotKeyBinding('keyup', 'return', 13); + }); + + it("should bind the 'alt+s' keys and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'alt+a', 65, ['alt']); + }); + it("should bind the 'ctrl+s' keys and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'ctrl+a', 65, ['ctrl']); + }); + + it("should bind the 'alt+f2' keys for keyup and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'alt+f2', 113, ['alt']); + }); + + it("should bind the 'shift+pagedown' keys and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'shift+pagedown', 34, ['shift']); + }); + + it("should bind the 'alt+shift+a' with a namespace, trigger the callback handler and unbind correctly", function() { + + var spy = sinon.spy(); + + $(document).bind('keyup.a', 'alt+shift+a', spy); + $(document).bind('keyup.b', 'alt+shift+a', spy); + $(document).unbind('keyup.a'); // remove first binding, leaving only second + + var event = this.createKeyEvent(65, 'keyup'); + event.altKey = true; + event.shiftKey = true; + $(document).trigger(event); + + // ensure only second binding is still in effect + sinon.assert.calledOnce(spy); + }); + + it("should bind the 'meta+a' keys and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'meta+a', 65, ['meta']); + }); + + it("should bind the 'hyper+a' keys and call the callback handler function", function() { + this.assertHotKeyBinding('keyup', 'hyper+a', 65, ['alt', 'ctrl', 'meta', 'shift']); + }); + + it("should not trigger event handler callbacks bound to any standard input types if not bound directly", function() { + + var i = 0; + + _.each(this.text_input_types, function(input_type) { + + var spy = sinon.spy(); + + var $el = this.createInputEl(input_type, ++i); + $(document).bind('keyup', 'a', spy); + + var event = this.createKeyEvent('65', 'keyup'); + $el.trigger(event); + + sinon.assert.notCalled(spy); + $(document).unbind(); + $el.remove(); + + }, this); + }); + + it("should bind and trigger events from an input element if bound directly", function() { + + var i = 0; + + _.each(this.text_input_types, function(input_type) { + + var $el = this.createInputEl(input_type, ++i); + this.assertHotKeyBinding('keyup', 'a', 65, [], $el); + $el.remove(); // unbound when removed + + }, this); + }); +}); |