Skip to content

Instantly share code, notes, and snippets.

@moos
Last active December 10, 2021 23:03
Show Gist options
  • Save moos/22ee1584833de27f041c to your computer and use it in GitHub Desktop.
Save moos/22ee1584833de27f041c to your computer and use it in GitHub Desktop.
Number sequence handler for Mousetrap
/**
* Mousetrap numbers plugin -- add support for 'number' and 'numbers' keywords
*
* Usage:
*
* Mousetrap.bind('number', callback) - handle any single number
*
* Mousetrap.bind('numbers', callback) - handle a sequence of 1+ numbers
*
* // pre sequence
* Mousetrap.bind('a b numbers', callback) - handle a sequence of 'a b' followed by any numbers
*
* // post sequence
* Mousetrap.bind('numbers a b', callback) - handle a sequence of numbers followed by 'a b'
*
* callback receives (event, combo, numbers).
*
* Note: the array form of bind() is NOT supported for numbers, ie,
* Mousetrap.bind(['numbers'], callback) - NO!
*
* To use multiple number sequences -- instantiate new Mousetraps (as of v1.5):
*
* (new Mousetrap()).bind('numbers g', gotoPage)
* (new Mousetrap()).bind('numbers f', gotoForm)
*
*
* Created by github.com/moos on 4/4/15.
*
* MIT License
*/
!(function(Mousetrap) {
var NUMBERS = '0,1,2,3,4,5,6,7,8,9';
var SEQ_TIMEOUT = 1000;
var origBind = Mousetrap.prototype.bind;
Mousetrap.prototype.bind = function(keys, callback, action) {
// don't handle arrays
if (keys instanceof Array) {
return origBind.apply(this, arguments);
}
var key = keys,
combo = key;
// special key
if (key === 'number') {
this._bindMultiple.call(this, NUMBERS.split(','), callback, action);
return this;
}
// numbers sequence!
if (/numbers/.test(key)) {
// remove numbers
key = key.replace(/\s*numbers\s*/,'');
// make sure multiple spaces in a row become a single space
key = key.replace(/\s+/g, ' ');
var trapNumbers = new TrapNumbers(callback, combo, !key);
// bind post/pre sequence if any
if (key) this._bindMultiple.call(this, [key], bind(trapNumbers.onSeqComplete, trapNumbers), action);
// bind numbers
this.bind('number', bind(trapNumbers.onNumber, trapNumbers), action);
return this;
}
// normal case
return origBind.apply(this, arguments);
};
var bind = function(fn, context){
return function() {
fn.apply(context, arguments);
};
};
function TrapNumbers(callback, combo, seqOK){
this.numbers = [];
this.combo = combo;
this.keyTimer = null;
this.callback = callback;
this.executeOnLast = /numbers$/.test(combo);
this.seqOK = seqOK;
}
TrapNumbers.prototype = {
onNumber: function(e, key) {
this.numbers.push(key);
this.keyPing();
this.lastEvent = e;
},
keyPing: function(){
var self = this;
if (this.keyTimer) {
clearTimeout(this.keyTimer);
}
// clear the numbers after a while
this.keyTimer = setTimeout(function(){
if (self.executeOnLast) self.execute();
self.reset();
}, SEQ_TIMEOUT);
},
reset: function(){
this.numbers = [];
this.seqOK = false;
},
execute: function(){
if (this.seqOK && this.numbers.length) {
this.callback( this.lastEvent, this.combo, this.getNumber());
this.reset();
return true;
}
return false;
},
getNumber: function(){
return Number(this.numbers.join(''));
},
/**
* sequence complete handler - seq. can be either before or after numbers.
*/
onSeqComplete: function() {
this.seqOK = true;
if (!this.executeOnLast && this.execute()) return;
// must be before -- remember seq OK and ping timer
// also: reset any previously entered numbers
this.reset();
this.seqOK = true;
this.keyPing();
}
};
}) (Mousetrap);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment