aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mousetrap/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mousetrap/plugins')
-rw-r--r--lib/mousetrap/plugins/README.md24
-rw-r--r--lib/mousetrap/plugins/bind-dictionary/README.md16
-rw-r--r--lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js39
-rw-r--r--lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js1
-rw-r--r--lib/mousetrap/plugins/global-bind/README.md15
-rw-r--r--lib/mousetrap/plugins/global-bind/mousetrap-global-bind.js43
-rw-r--r--lib/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js1
-rw-r--r--lib/mousetrap/plugins/pause/README.md13
-rw-r--r--lib/mousetrap/plugins/pause/mousetrap-pause.js31
-rw-r--r--lib/mousetrap/plugins/pause/mousetrap-pause.min.js1
-rw-r--r--lib/mousetrap/plugins/record/README.md16
-rw-r--r--lib/mousetrap/plugins/record/mousetrap-record.js205
-rw-r--r--lib/mousetrap/plugins/record/mousetrap-record.min.js2
-rw-r--r--lib/mousetrap/plugins/record/tests/index.html29
-rw-r--r--lib/mousetrap/plugins/record/tests/jelly.css18
-rw-r--r--lib/mousetrap/plugins/record/tests/jelly.js53
16 files changed, 507 insertions, 0 deletions
diff --git a/lib/mousetrap/plugins/README.md b/lib/mousetrap/plugins/README.md
new file mode 100644
index 0000000..704cf04
--- /dev/null
+++ b/lib/mousetrap/plugins/README.md
@@ -0,0 +1,24 @@
+# Plugins
+
+Plugins extend the functionality of Mousetrap. To use a plugin just include the plugin after mousetrap.
+
+```html
+<script src="mousetrap.js"></script>
+<script src="mousetrap-record.js"></script>
+```
+
+## Bind dictionary
+
+Allows you to make multiple bindings in a single ``Mousetrap.bind`` call.
+
+## Global bind
+
+Allows you to set global bindings that work even inside of input fields.
+
+## Pause/unpause
+
+Allows you to temporarily prevent Mousetrap events from firing.
+
+## Record
+
+Allows you to capture a keyboard shortcut or sequence defined by a user.
diff --git a/lib/mousetrap/plugins/bind-dictionary/README.md b/lib/mousetrap/plugins/bind-dictionary/README.md
new file mode 100644
index 0000000..6f956b6
--- /dev/null
+++ b/lib/mousetrap/plugins/bind-dictionary/README.md
@@ -0,0 +1,16 @@
+# Bind Dictionary
+
+This extension overwrites the default bind behavior and allows you to bind multiple combinations in a single bind call.
+
+Usage looks like:
+
+```javascript
+Mousetrap.bind({
+ 'a': function() { console.log('a'); },
+ 'b': function() { console.log('b'); }
+});
+```
+
+You can optionally pass in ``keypress``, ``keydown`` or ``keyup`` as a second argument.
+
+Other bind calls work the same way as they do by default.
diff --git a/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js b/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js
new file mode 100644
index 0000000..523fc86
--- /dev/null
+++ b/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js
@@ -0,0 +1,39 @@
+/**
+ * Overwrites default Mousetrap.bind method to optionally accept
+ * an object to bind multiple key events in a single call
+ *
+ * You can pass it in like:
+ *
+ * Mousetrap.bind({
+ * 'a': function() { console.log('a'); },
+ * 'b': function() { console.log('b'); }
+ * });
+ *
+ * And can optionally pass in 'keypress', 'keydown', or 'keyup'
+ * as a second argument
+ *
+ */
+/* global Mousetrap:true */
+(function(Mousetrap) {
+ var _oldBind = Mousetrap.prototype.bind;
+ var args;
+
+ Mousetrap.prototype.bind = function() {
+ var self = this;
+ args = arguments;
+
+ // normal call
+ if (typeof args[0] == 'string' || args[0] instanceof Array) {
+ return _oldBind.call(self, args[0], args[1], args[2]);
+ }
+
+ // object passed in
+ for (var key in args[0]) {
+ if (args[0].hasOwnProperty(key)) {
+ _oldBind.call(self, key, args[0][key], args[1]);
+ }
+ }
+ };
+
+ Mousetrap.init();
+}) (Mousetrap);
diff --git a/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js b/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js
new file mode 100644
index 0000000..bf9d8d0
--- /dev/null
+++ b/lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js
@@ -0,0 +1 @@
+(function(b){var c=b.prototype.bind,a;b.prototype.bind=function(){a=arguments;if("string"==typeof a[0]||a[0]instanceof Array)return c.call(this,a[0],a[1],a[2]);for(var b in a[0])a[0].hasOwnProperty(b)&&c.call(this,b,a[0][b],a[1])};b.init()})(Mousetrap);
diff --git a/lib/mousetrap/plugins/global-bind/README.md b/lib/mousetrap/plugins/global-bind/README.md
new file mode 100644
index 0000000..a37a219
--- /dev/null
+++ b/lib/mousetrap/plugins/global-bind/README.md
@@ -0,0 +1,15 @@
+# Global Bind
+
+This extension allows you to specify keyboard events that will work anywhere including inside textarea/input fields.
+
+Usage looks like:
+
+```javascript
+Mousetrap.bindGlobal('ctrl+s', function() {
+ _save();
+});
+```
+
+This means that a keyboard event bound using ``Mousetrap.bind`` will only work outside of form input fields, but using ``Moustrap.bindGlobal`` will work in both places.
+
+If you wanted to create keyboard shortcuts that only work when you are inside a specific textarea you can do that too by creating your own extension.
diff --git a/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.js b/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.js
new file mode 100644
index 0000000..1c4ac14
--- /dev/null
+++ b/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.js
@@ -0,0 +1,43 @@
+/**
+ * adds a bindGlobal method to Mousetrap that allows you to
+ * bind specific keyboard shortcuts that will still work
+ * inside a text input field
+ *
+ * usage:
+ * Mousetrap.bindGlobal('ctrl+s', _saveChanges);
+ */
+/* global Mousetrap:true */
+(function(Mousetrap) {
+ var _globalCallbacks = {};
+ var _originalStopCallback = Mousetrap.prototype.stopCallback;
+
+ Mousetrap.prototype.stopCallback = function(e, element, combo, sequence) {
+ var self = this;
+
+ if (self.paused) {
+ return true;
+ }
+
+ if (_globalCallbacks[combo] || _globalCallbacks[sequence]) {
+ return false;
+ }
+
+ return _originalStopCallback.call(self, e, element, combo);
+ };
+
+ Mousetrap.prototype.bindGlobal = function(keys, callback, action) {
+ var self = this;
+ self.bind(keys, callback, action);
+
+ if (keys instanceof Array) {
+ for (var i = 0; i < keys.length; i++) {
+ _globalCallbacks[keys[i]] = true;
+ }
+ return;
+ }
+
+ _globalCallbacks[keys] = true;
+ };
+
+ Mousetrap.init();
+}) (Mousetrap);
diff --git a/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js b/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js
new file mode 100644
index 0000000..073ce67
--- /dev/null
+++ b/lib/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js
@@ -0,0 +1 @@
+(function(a){var c={},d=a.prototype.stopCallback;a.prototype.stopCallback=function(e,b,a,f){return this.paused?!0:c[a]||c[f]?!1:d.call(this,e,b,a)};a.prototype.bindGlobal=function(a,b,d){this.bind(a,b,d);if(a instanceof Array)for(b=0;b<a.length;b++)c[a[b]]=!0;else c[a]=!0};a.init()})(Mousetrap);
diff --git a/lib/mousetrap/plugins/pause/README.md b/lib/mousetrap/plugins/pause/README.md
new file mode 100644
index 0000000..0b3b3bd
--- /dev/null
+++ b/lib/mousetrap/plugins/pause/README.md
@@ -0,0 +1,13 @@
+# Pause/unpause
+
+This extension allows Mousetrap to be paused and unpaused without having to reset keyboard shortcuts and rebind them.
+
+Usage looks like:
+
+```javascript
+// stop Mousetrap events from firing
+Mousetrap.pause();
+
+// allow Mousetrap events to fire again
+Mousetrap.unpause();
+```
diff --git a/lib/mousetrap/plugins/pause/mousetrap-pause.js b/lib/mousetrap/plugins/pause/mousetrap-pause.js
new file mode 100644
index 0000000..0138b8a
--- /dev/null
+++ b/lib/mousetrap/plugins/pause/mousetrap-pause.js
@@ -0,0 +1,31 @@
+/**
+ * adds a pause and unpause method to Mousetrap
+ * this allows you to enable or disable keyboard shortcuts
+ * without having to reset Mousetrap and rebind everything
+ */
+/* global Mousetrap:true */
+(function(Mousetrap) {
+ var _originalStopCallback = Mousetrap.prototype.stopCallback;
+
+ Mousetrap.prototype.stopCallback = function(e, element, combo) {
+ var self = this;
+
+ if (self.paused) {
+ return true;
+ }
+
+ return _originalStopCallback.call(self, e, element, combo);
+ };
+
+ Mousetrap.prototype.pause = function() {
+ var self = this;
+ self.paused = true;
+ };
+
+ Mousetrap.prototype.unpause = function() {
+ var self = this;
+ self.paused = false;
+ };
+
+ Mousetrap.init();
+}) (Mousetrap);
diff --git a/lib/mousetrap/plugins/pause/mousetrap-pause.min.js b/lib/mousetrap/plugins/pause/mousetrap-pause.min.js
new file mode 100644
index 0000000..d3df296
--- /dev/null
+++ b/lib/mousetrap/plugins/pause/mousetrap-pause.min.js
@@ -0,0 +1 @@
+(function(a){var b=a.prototype.stopCallback;a.prototype.stopCallback=function(a,c,d){return this.paused?!0:b.call(this,a,c,d)};a.prototype.pause=function(){this.paused=!0};a.prototype.unpause=function(){this.paused=!1};a.init()})(Mousetrap);
diff --git a/lib/mousetrap/plugins/record/README.md b/lib/mousetrap/plugins/record/README.md
new file mode 100644
index 0000000..903f605
--- /dev/null
+++ b/lib/mousetrap/plugins/record/README.md
@@ -0,0 +1,16 @@
+# Record
+
+This extension lets you use Mousetrap to record keyboard sequences and play them back:
+
+```html
+<button onclick="recordSequence()">Record</button>
+
+<script>
+ function recordSequence() {
+ Mousetrap.record(function(sequence) {
+ // sequence is an array like ['ctrl+k', 'c']
+ alert('You pressed: ' + sequence.join(' '));
+ });
+ }
+</script>
+```
diff --git a/lib/mousetrap/plugins/record/mousetrap-record.js b/lib/mousetrap/plugins/record/mousetrap-record.js
new file mode 100644
index 0000000..b7d364d
--- /dev/null
+++ b/lib/mousetrap/plugins/record/mousetrap-record.js
@@ -0,0 +1,205 @@
+/**
+ * This extension allows you to record a sequence using Mousetrap.
+ *
+ * @author Dan Tao <daniel.tao@gmail.com>
+ */
+(function(Mousetrap) {
+ /**
+ * the sequence currently being recorded
+ *
+ * @type {Array}
+ */
+ var _recordedSequence = [],
+
+ /**
+ * a callback to invoke after recording a sequence
+ *
+ * @type {Function|null}
+ */
+ _recordedSequenceCallback = null,
+
+ /**
+ * a list of all of the keys currently held down
+ *
+ * @type {Array}
+ */
+ _currentRecordedKeys = [],
+
+ /**
+ * temporary state where we remember if we've already captured a
+ * character key in the current combo
+ *
+ * @type {boolean}
+ */
+ _recordedCharacterKey = false,
+
+ /**
+ * a handle for the timer of the current recording
+ *
+ * @type {null|number}
+ */
+ _recordTimer = null,
+
+ /**
+ * the original handleKey method to override when Mousetrap.record() is
+ * called
+ *
+ * @type {Function}
+ */
+ _origHandleKey = Mousetrap.prototype.handleKey;
+
+ /**
+ * handles a character key event
+ *
+ * @param {string} character
+ * @param {Array} modifiers
+ * @param {Event} e
+ * @returns void
+ */
+ function _handleKey(character, modifiers, e) {
+ var self = this;
+
+ if (!self.recording) {
+ _origHandleKey.apply(self, arguments);
+ return;
+ }
+
+ // remember this character if we're currently recording a sequence
+ if (e.type == 'keydown') {
+ if (character.length === 1 && _recordedCharacterKey) {
+ _recordCurrentCombo();
+ }
+
+ for (i = 0; i < modifiers.length; ++i) {
+ _recordKey(modifiers[i]);
+ }
+ _recordKey(character);
+
+ // once a key is released, all keys that were held down at the time
+ // count as a keypress
+ } else if (e.type == 'keyup' && _currentRecordedKeys.length > 0) {
+ _recordCurrentCombo();
+ }
+ }
+
+ /**
+ * marks a character key as held down while recording a sequence
+ *
+ * @param {string} key
+ * @returns void
+ */
+ function _recordKey(key) {
+ var i;
+
+ // one-off implementation of Array.indexOf, since IE6-9 don't support it
+ for (i = 0; i < _currentRecordedKeys.length; ++i) {
+ if (_currentRecordedKeys[i] === key) {
+ return;
+ }
+ }
+
+ _currentRecordedKeys.push(key);
+
+ if (key.length === 1) {
+ _recordedCharacterKey = true;
+ }
+ }
+
+ /**
+ * marks whatever key combination that's been recorded so far as finished
+ * and gets ready for the next combo
+ *
+ * @returns void
+ */
+ function _recordCurrentCombo() {
+ _recordedSequence.push(_currentRecordedKeys);
+ _currentRecordedKeys = [];
+ _recordedCharacterKey = false;
+ _restartRecordTimer();
+ }
+
+ /**
+ * ensures each combo in a sequence is in a predictable order and formats
+ * key combos to be '+'-delimited
+ *
+ * modifies the sequence in-place
+ *
+ * @param {Array} sequence
+ * @returns void
+ */
+ function _normalizeSequence(sequence) {
+ var i;
+
+ for (i = 0; i < sequence.length; ++i) {
+ sequence[i].sort(function(x, y) {
+ // modifier keys always come first, in alphabetical order
+ if (x.length > 1 && y.length === 1) {
+ return -1;
+ } else if (x.length === 1 && y.length > 1) {
+ return 1;
+ }
+
+ // character keys come next (list should contain no duplicates,
+ // so no need for equality check)
+ return x > y ? 1 : -1;
+ });
+
+ sequence[i] = sequence[i].join('+');
+ }
+ }
+
+ /**
+ * finishes the current recording, passes the recorded sequence to the stored
+ * callback, and sets Mousetrap.handleKey back to its original function
+ *
+ * @returns void
+ */
+ function _finishRecording() {
+ if (_recordedSequenceCallback) {
+ _normalizeSequence(_recordedSequence);
+ _recordedSequenceCallback(_recordedSequence);
+ }
+
+ // reset all recorded state
+ _recordedSequence = [];
+ _recordedSequenceCallback = null;
+ _currentRecordedKeys = [];
+ }
+
+ /**
+ * called to set a 1 second timeout on the current recording
+ *
+ * this is so after each key press in the sequence the recording will wait for
+ * 1 more second before executing the callback
+ *
+ * @returns void
+ */
+ function _restartRecordTimer() {
+ clearTimeout(_recordTimer);
+ _recordTimer = setTimeout(_finishRecording, 1000);
+ }
+
+ /**
+ * records the next sequence and passes it to a callback once it's
+ * completed
+ *
+ * @param {Function} callback
+ * @returns void
+ */
+ Mousetrap.prototype.record = function(callback) {
+ var self = this;
+ self.recording = true;
+ _recordedSequenceCallback = function() {
+ self.recording = false;
+ callback.apply(self, arguments);
+ };
+ };
+
+ Mousetrap.prototype.handleKey = function() {
+ var self = this;
+ _handleKey.apply(self, arguments);
+ };
+
+ Mousetrap.init();
+
+})(Mousetrap);
diff --git a/lib/mousetrap/plugins/record/mousetrap-record.min.js b/lib/mousetrap/plugins/record/mousetrap-record.min.js
new file mode 100644
index 0000000..25f3e71
--- /dev/null
+++ b/lib/mousetrap/plugins/record/mousetrap-record.min.js
@@ -0,0 +1,2 @@
+(function(d){function n(b,a,h){if(this.recording)if("keydown"==h.type){1===b.length&&g&&k();for(i=0;i<a.length;++i)l(a[i]);l(b)}else"keyup"==h.type&&0<c.length&&k();else p.apply(this,arguments)}function l(b){var a;for(a=0;a<c.length;++a)if(c[a]===b)return;c.push(b);1===b.length&&(g=!0)}function k(){e.push(c);c=[];g=!1;clearTimeout(m);m=setTimeout(q,1E3)}function r(b){var a;for(a=0;a<b.length;++a)b[a].sort(function(a,b){return 1<a.length&&1===b.length?-1:1===a.length&&1<b.length?1:a>b?1:-1}),b[a]=
+b[a].join("+")}function q(){f&&(r(e),f(e));e=[];f=null;c=[]}var e=[],f=null,c=[],g=!1,m=null,p=d.prototype.handleKey;d.prototype.record=function(b){var a=this;a.recording=!0;f=function(){a.recording=!1;b.apply(a,arguments)}};d.prototype.handleKey=function(){n.apply(this,arguments)};d.init()})(Mousetrap);
diff --git a/lib/mousetrap/plugins/record/tests/index.html b/lib/mousetrap/plugins/record/tests/index.html
new file mode 100644
index 0000000..5608f09
--- /dev/null
+++ b/lib/mousetrap/plugins/record/tests/index.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <title>Jelly</title>
+ <meta charset=utf-8>
+ <link href="jelly.css" rel="stylesheet">
+ </head>
+
+ <body>
+ <h1>Jelly</h1>
+
+ <h2>For testing the <strong>record</strong> extension</h2>
+
+ <p>Click "Record" to test recording a sequence.</p>
+ <button class="test-record">Record</button>
+ <div class="test-record-result"></div>
+
+ <script type="text/javascript" src="../../../tests/libs/jquery-1.7.2.min.js"></script>
+ <script type="text/javascript" src="../../../mousetrap.js"></script>
+ <script type="text/javascript" src="../mousetrap-record.js"></script>
+ <script type="text/javascript" src="jelly.js"></script>
+
+ <script type="text/javascript">
+ Jelly.spread();
+ </script>
+ </body>
+
+</html>
diff --git a/lib/mousetrap/plugins/record/tests/jelly.css b/lib/mousetrap/plugins/record/tests/jelly.css
new file mode 100644
index 0000000..a071c77
--- /dev/null
+++ b/lib/mousetrap/plugins/record/tests/jelly.css
@@ -0,0 +1,18 @@
+body {
+ font-family: helvetica, arial, sans-serif;
+ line-height: 20px;
+}
+
+kbd {
+ background-color: #ccc;
+ display: inline-block;
+ padding: 0.5ex 1em;
+}
+
+.test-record-result {
+ margin-top: 20px;
+}
+
+.test-record-result span:nth-child(n+2) {
+ margin-left: 10px;
+}
diff --git a/lib/mousetrap/plugins/record/tests/jelly.js b/lib/mousetrap/plugins/record/tests/jelly.js
new file mode 100644
index 0000000..57ff01a
--- /dev/null
+++ b/lib/mousetrap/plugins/record/tests/jelly.js
@@ -0,0 +1,53 @@
+/**
+ * Peanut butter goes great with jelly.
+ *
+ * @author Dan Tao <daniel.tao@gmail.com>
+ */
+var Jelly = (function() {
+ var recordButton = $("button.test-record"),
+ recordResult = $("div.test-record-result");
+
+ function _formatSequenceAsHtml(sequence) {
+ var combos = [],
+ i;
+
+ for (i = 0; i < sequence.length; ++i) {
+ combos.push('<span>' + _formatKeysAsHtml(sequence[i].split('+')) + '</span>');
+ }
+
+ return combos.join(' ');
+ }
+
+ function _formatKeysAsHtml(keys) {
+ var htmlKeys = [],
+ i;
+
+ for (i = 0; i < keys.length; ++i) {
+ htmlKeys.push('<kbd>' + keys[i] + '</kbd>');
+ }
+
+ return htmlKeys.join('+');
+ }
+
+ function _prepareRecordTest() {
+ recordButton.prop('disabled', true);
+ recordButton.text('Recording');
+
+ Mousetrap.record(function(sequence) {
+ recordResult.html(_formatSequenceAsHtml(sequence));
+ recordButton.prop('disabled', false);
+ recordButton.text('Record');
+ });
+
+ // take focus away from the button so that Mousetrap will actually
+ // capture keystrokes
+ recordButton.blur();
+ }
+
+ return {
+ spread: function() {
+ recordButton.click(_prepareRecordTest);
+ }
+ };
+
+})();