summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Pocklington <rpocklin@gmail.com>2014-08-19 17:54:13 +1000
committerRobert Pocklington <rpocklin@gmail.com>2014-08-19 17:54:13 +1000
commitb5eb6502bbbe903a87d8a1f92f2613d94e4cf489 (patch)
treed15ede816877e1c52f0e0c75df6b63854c289969
parentc245b704fa6ae7c9e1646f051df4ef885063dbba (diff)
parent950ece85b4c5b18451a809b1f4b79720e05f8378 (diff)
downloadjquery.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.md2
-rw-r--r--jquery.hotkeys.js19
-rw-r--r--test/SpecRunner.html2
-rw-r--r--test/spec/bindingSpec.js164
-rw-r--r--test/spec/keyBindingSpec.js141
5 files changed, 156 insertions, 172 deletions
diff --git a/README.md b/README.md
index 6b5ba45..46807f8 100644
--- a/README.md
+++ b/README.md
@@ -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);
+ });
+});