Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #31 from agnoster/keymaster

---

Removes all handlers associated with a given scope, allowing throw-away and re-usable scopes. Includes test. Adds 1 function, 8 lines of functional code, and 117 bytes to the minified version.

I took the liberty of adding a simple test for scope while I was at it.

I love how keymaster is so simple and small, I hope this addition does not constitute undue bloat.

If youre curious why I added this function: on a single-site app Im building we want to be able to be able to switch to different "apps" with their own shortcuts. However, when we navigate away from the app it is destroyed, and a new one is created when we navigate back. Allowing us to destroy the scope of all shortcuts the app registered means we dont need to worry about callbacks to a dead app being fired (and of course the app not getting garbage-collected because the closures hold references to it). Of course, if theres another, better way to do this, Id be happy to hear that too. Now, we can just do:

    // on app open
    key(n, this.appName, this.createNewItem);
    // ... and other shortcuts...
    key.setScope(this.appName);

    // on app close
    key.setScope(all);
    key.deleteScope(this.appName);

Conflicts:
	keymaster.js
	keymaster.min.js
  • Loading branch information...
commit f2c1db083c164462adbc796f9c92a850d572d20e 2 parents 1153827 + 9c60b2c
@madrobby authored
Showing with 51 additions and 2 deletions.
  1. +14 −0 keymaster.js
  2. +1 −1  keymaster.min.js
  3. +36 −1 test/keymaster.html
View
14 keymaster.js
@@ -138,6 +138,19 @@
function setScope(scope){ _scope = scope || 'all' };
function getScope(){ return _scope || 'all' };
+ // delete all handlers for a given scope
+ function deleteScope(scope){
+ var key, handlers, i;
+
+ for (key in _handlers) {
+ handlers = _handlers[key];
+ for (i = 0; i < handlers.length; ) {
+ if (handlers[i].scope === scope) handlers.splice(i, 1);
+ else i++;
+ }
+ }
+ };
+
// cross-browser events
function addEvent(object, event, method) {
if (object.addEventListener)
@@ -157,6 +170,7 @@
global.key = assignKey;
global.key.setScope = setScope;
global.key.getScope = getScope;
+ global.key.deleteScope = deleteScope;
if(typeof module !== 'undefined') module.exports = key;
View
2  keymaster.min.js
@@ -1,4 +1,4 @@
// keymaster.js
// (c) 2011 Thomas Fuchs
// keymaster.js may be freely distributed under the MIT license.
-(function(a){function h(a,b){var c=a.length;while(c--)if(a[c]===b)return c;return-1}function i(a){var b,g,i,j,k,m;g=(a.target||a.srcElement).tagName,b=a.keyCode;if(b==93||b==224)b=91;if(b in d){d[b]=!0;for(j in f)f[j]==b&&(l[j]=!0);return}if(g=="INPUT"||g=="SELECT"||g=="TEXTAREA")return;if(!(b in c))return;for(k=0;k<c[b].length;k++){i=c[b][k];if(i.scope==e||i.scope=="all"){m=i.mods.length>0;for(j in d)if(!d[j]&&h(i.mods,+j)>-1||d[j]&&h(i.mods,+j)==-1)m=!1;(i.mods.length==0&&!d[16]&&!d[18]&&!d[17]&&!d[91]||m)&&i.method(a,i)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}}function j(a){var b=a.keyCode,c;if(b==93||b==224)b=91;if(b in d){d[b]=!1;for(c in f)f[c]==b&&(l[c]=!1)}}function k(){for(b in d)d[b]=!1;for(b in f)l[b]=!1}function l(a,b,d){var e,h,i,j;d===undefined&&(d=b,b="all"),a=a.replace(/\s/g,""),e=a.split(","),e[e.length-1]==""&&(e[e.length-2]+=",");for(i=0;i<e.length;i++){h=[],a=e[i].split("+");if(a.length>1){h=a.slice(0,a.length-1);for(j=0;j<h.length;j++)h[j]=f[h[j]];a=[a[a.length-1]]}a=a[0],a=g[a]||a.toUpperCase().charCodeAt(0),a in c||(c[a]=[]),c[a].push({shortcut:e[i],scope:b,method:d,key:e[i],mods:h})}}function m(a){e=a||"all"}function n(){return e||"all"}function o(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220};for(b=1;b<20;b++)f["f"+b]=111+b;for(b in f)l[b]=!1;o(document,"keydown",i),o(document,"keyup",j),o(window,"focus",k),a.key=l,a.key.setScope=m,a.key.getScope=n,typeof module!="undefined"&&(module.exports=key)})(this)
+(function(a){function h(a,b){var c=a.length;while(c--)if(a[c]===b)return c;return-1}function i(a){var b,g,i,j,k,m;g=(a.target||a.srcElement).tagName,b=a.keyCode;if(b==93||b==224)b=91;if(b in d){d[b]=!0;for(j in f)f[j]==b&&(l[j]=!0);return}if(g=="INPUT"||g=="SELECT"||g=="TEXTAREA")return;if(!(b in c))return;for(k=0;k<c[b].length;k++){i=c[b][k];if(i.scope==e||i.scope=="all"){m=i.mods.length>0;for(j in d)if(!d[j]&&h(i.mods,+j)>-1||d[j]&&h(i.mods,+j)==-1)m=!1;(i.mods.length==0&&!d[16]&&!d[18]&&!d[17]&&!d[91]||m)&&i.method(a,i)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}}function j(a){var b=a.keyCode,c;if(b==93||b==224)b=91;if(b in d){d[b]=!1;for(c in f)f[c]==b&&(l[c]=!1)}}function k(){for(b in d)d[b]=!1;for(b in f)l[b]=!1}function l(a,b,d){var e,h,i,j;d===undefined&&(d=b,b="all"),a=a.replace(/\s/g,""),e=a.split(","),e[e.length-1]==""&&(e[e.length-2]+=",");for(i=0;i<e.length;i++){h=[],a=e[i].split("+");if(a.length>1){h=a.slice(0,a.length-1);for(j=0;j<h.length;j++)h[j]=f[h[j]];a=[a[a.length-1]]}a=a[0],a=g[a]||a.toUpperCase().charCodeAt(0),a in c||(c[a]=[]),c[a].push({shortcut:e[i],scope:b,method:d,key:e[i],mods:h})}}function m(a){e=a||"all"}function n(){return e||"all"}function o(a){var b,d,e;for(b in c){d=c[b];for(e=0;e<d.length;)d[e].scope===a?d.splice(e,1):e++}}function p(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220};for(b=1;b<20;b++)f["f"+b]=111+b;for(b in f)l[b]=!1;p(document,"keydown",i),p(document,"keyup",j),p(window,"focus",k),a.key=l,a.key.setScope=m,a.key.getScope=n,a.key.deleteScope=o,typeof module!="undefined"&&(module.exports=key)})(this);
View
37 test/keymaster.html
@@ -155,7 +155,42 @@
},
testScoping: function(t){
- // TODO
+ var sequence = '';
+
+ key('a', function(){ sequence += 'a' });
+ key('b', function(){ sequence += 'b' });
+ key('b', 'capital', function(){ sequence += 'B' });
+
+ keydown(65); keyup(65);
+ key.setScope('capital');
+ keydown(66); keyup(66);
+ keydown(65); keyup(65);
+ key.setScope('unknown');
+ keydown(66); keyup(66);
+ key.setScope('all');
+ keydown(65); keyup(65);
+
+ t.assertEqual('abBaba', sequence);
+ },
+
+ testDeleteScope: function(t){
+ var sequence = '';
+
+ key('a', function(){ sequence += 'a' });
+ key('b', function(){ sequence += 'b' });
+ key('a', 'capital', function(){ sequence += 'A' });
+ key('b', 'capital', function(){ sequence += 'B' });
+
+ keydown(65); keyup(65);
+ keydown(66); keyup(66);
+ key.setScope('capital');
+ keydown(65); keyup(65);
+ keydown(66); keyup(66);
+ key.deleteScope('capital');
+ keydown(65); keyup(65);
+ keydown(66); keyup(66);
+
+ t.assertEqual('abaAbBab', sequence);
},
testDoesntFireOnUserInputElements: function(t){
Please sign in to comment.
Something went wrong with that request. Please try again.