diff options
| author | Teddy Wing | 2015-05-23 16:21:38 -0400 | 
|---|---|---|
| committer | Teddy Wing | 2015-05-23 16:21:38 -0400 | 
| commit | 3a09e4dd09a6af3b228fcda68aa0709626b5ee51 (patch) | |
| tree | a434d76ccae2a55cfe4f4c0215a99017de4bba33 /lib/mousetrap/plugins | |
| parent | 6183a0bb3caf4805ed4242a4ac104b9890db3601 (diff) | |
| download | Peniquitous-3a09e4dd09a6af3b228fcda68aa0709626b5ee51.tar.bz2 | |
Set up Bower. Install Mousetrap.
* Create limited bower.json file
* Create .bowerrc that tells Bower to use the `lib` directory
* Install Mousetrap for key events
Diffstat (limited to 'lib/mousetrap/plugins')
| -rw-r--r-- | lib/mousetrap/plugins/README.md | 24 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/bind-dictionary/README.md | 16 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js | 39 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js | 1 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/global-bind/README.md | 15 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/global-bind/mousetrap-global-bind.js | 43 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js | 1 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/pause/README.md | 13 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/pause/mousetrap-pause.js | 31 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/pause/mousetrap-pause.min.js | 1 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/README.md | 16 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/mousetrap-record.js | 205 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/mousetrap-record.min.js | 2 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/tests/index.html | 29 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/tests/jelly.css | 18 | ||||
| -rw-r--r-- | lib/mousetrap/plugins/record/tests/jelly.js | 53 | 
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); +        } +    }; + +})(); | 
