Fix Issue 16: shortcut keys using js-hotkeys

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@134 eee81c28-f429-11dd-99c0-75d572ba1ddd
This commit is contained in:
Jeff Schiller
2009-06-17 02:04:10 +00:00
parent b4644c1812
commit 66b15f760f
4 changed files with 128 additions and 49 deletions

View File

@@ -0,0 +1,93 @@
#About
**jQuery.hotkeys** is a plug-in that lets you easily add and remove handlers for keyboard events anywhere in your code supporting almost any key combination.
It is based on a library [Shortcut.js](http://www.openjs.com/scripts/events/keyboard_shortcuts/shortcut.js) written by [Binny V A](http://www.openjs.com/).
The syntax is as follows:
<pre>
$(expression).bind(<types>,<options>, <handler>);
$(expression).unbind(<types>,<options>, <handler>);
$(document).bind('keydown', 'Ctrl+a', fn);
// e.g. replace '$' sign with 'EUR'
$('input.foo').bind('keyup', '$', function(){
this.value = this.value.replace('$', 'EUR');
});
$('div.foo').unbind('keydown', 'Ctrl+a', fn);
</pre>
## [Live Demo](http://jshotkeys.googlepages.com/test-static-01.html)
## Types
Supported types are `'keydown'`, `'keyup'` and `'keypress'`
## Options
The options are `'combi'` i.e. the key combination, and `'disableInInput'` which allow your code not to be executed when the cursor is located inside an input ( `$(elem).is('input') || $(elem).is('textarea')` ).
As you can see, the key combination can be passed as string or as an object. You may pass an object in case you wish to override the default option for `disableInInput` which is set to `false`:
<pre>
$(document).bind('keydown', {combi:'a', disableinInput: true}, fn);
</pre>
I.e. when cursor is within an input field, `'a'` will be inserted into the input field without interfering.
If you want to use more than one modifiers (e.g. alt+ctrl+z) you should define them by an alphabetical order e.g. alt+ctrl+shift
Modifiers are case insensitive, i.e. 'Ctrl+a' 'ctrl+a'.
## Handler
In previous versions there was an option propagate which is removed now and implemented at the user code level.
When using jQuery, if an event handler returns false, jQuery will call `stopPropagation()` and `preventDefault()`
## jQuery Compatibility
Tested with *jQuery 1.2.6*
It known to be working with all the major browsers on all available platforms (Win/Mac/Linux)
* IE 6/7/8
* FF 1.5/2/3
* Opera-9
* Safari-3
* Chrome-0.2
## Features added in this version (0.7.x)
* Implemented as $.fn - let you use `this`.
* jQuery selectors are supported.
* Extending `$.fn.bind` and `$.fn.unbind` so you get a single interface for binding events to handlers
## Overriding jQuery
The plugin wraps the following jQuery methods:
* $.fn.bind
* $.fn.unbind
* $.find
Even though the plugin overrides these methods, the original methods will *always* be called.
The plugin will add functionality only for the `keydown`, `keyup` and `keypress` event types. Any other types are passed untouched to the original `'bind()'` and `'unbind()'` methods.
Moreover, if you call `bind()` without passing the shortcut key combination e.g. `$(document).bind('keydown', fn)` only the original `'bind()'` method will be executed.
I also modified the `$.fn.find` method by adding a single line at the top of the function body. here is the code:
<pre>
jQuery.fn.find = function( selector ) {
// the line I added
this.query=selector;
// call jQuery original find
return jQuery.fn.__find__.apply(this, arguments);
};
</pre>
You can read about this at [jQuery's User Group](http://groups.google.com/group/jquery-en/browse_thread/thread/18f9825e8d22f18d)
###Notes
Firefox is the most liberal one in the manner of letting you capture all short-cuts even those that are built-in in the browser such as `Ctrl-t` for new tab, or `Ctrl-a` for selecting all text. You can always bubble them up to the browser by returning `true` in your handler.
Others, (IE) either let you handle built-in short-cuts, but will add their functionality after your code has executed. Or (Opera/Safari) will *not* pass those events to the DOM at all.
*So, if you bind `Ctrl-Q` or `Alt-F4` and your Safari/Opera window is closed don't be surprised.*
###Current Version is: beta 0.7

19
editor/js-hotkeys/jquery.hotkeys.min.js vendored Normal file
View File

@@ -0,0 +1,19 @@
(function(jQuery){jQuery.fn.__bind__=jQuery.fn.bind;jQuery.fn.__unbind__=jQuery.fn.unbind;jQuery.fn.__find__=jQuery.fn.find;var hotkeys={version:'0.7.9',override:/keypress|keydown|keyup/g,triggersMap:{},specialKeys:{27:'esc',9:'tab',32:'space',13:'return',8:'backspace',145:'scroll',20:'capslock',144:'numlock',19:'pause',45:'insert',36:'home',46:'del',35:'end',33:'pageup',34:'pagedown',37:'left',38:'up',39:'right',40:'down',109:'-',112:'f1',113:'f2',114:'f3',115:'f4',116:'f5',117:'f6',118:'f7',119:'f8',120:'f9',121:'f10',122:'f11',123:'f12',191:'/'},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":":","'":"\"",",":"<",".":">","/":"?","\\":"|"},newTrigger:function(type,combi,callback){var result={};result[type]={};result[type][combi]={cb:callback,disableInInput:false};return result;}};hotkeys.specialKeys=jQuery.extend(hotkeys.specialKeys,{96:'0',97:'1',98:'2',99:'3',100:'4',101:'5',102:'6',103:'7',104:'8',105:'9',106:'*',107:'+',109:'-',110:'.',111:'/'});jQuery.fn.find=function(selector){this.query=selector;return jQuery.fn.__find__.apply(this,arguments);};jQuery.fn.unbind=function(type,combi,fn){if(jQuery.isFunction(combi)){fn=combi;combi=null;}
if(combi&&typeof combi==='string'){var selectorId=((this.prevObject&&this.prevObject.query)||(this[0].id&&this[0].id)||this[0]).toString();var hkTypes=type.split(' ');for(var x=0;x<hkTypes.length;x++){delete hotkeys.triggersMap[selectorId][hkTypes[x]][combi];}}
return this.__unbind__(type,fn);};jQuery.fn.bind=function(type,data,fn){var handle=type.match(hotkeys.override);if(jQuery.isFunction(data)||!handle){return this.__bind__(type,data,fn);}
else{var result=null,pass2jq=jQuery.trim(type.replace(hotkeys.override,''));if(pass2jq){result=this.__bind__(pass2jq,data,fn);}
if(typeof data==="string"){data={'combi':data};}
if(data.combi){for(var x=0;x<handle.length;x++){var eventType=handle[x];var combi=data.combi.toLowerCase(),trigger=hotkeys.newTrigger(eventType,combi,fn),selectorId=((this.prevObject&&this.prevObject.query)||(this[0].id&&this[0].id)||this[0]).toString();trigger[eventType][combi].disableInInput=data.disableInInput;if(!hotkeys.triggersMap[selectorId]){hotkeys.triggersMap[selectorId]=trigger;}
else if(!hotkeys.triggersMap[selectorId][eventType]){hotkeys.triggersMap[selectorId][eventType]=trigger[eventType];}
var mapPoint=hotkeys.triggersMap[selectorId][eventType][combi];if(!mapPoint){hotkeys.triggersMap[selectorId][eventType][combi]=[trigger[eventType][combi]];}
else if(mapPoint.constructor!==Array){hotkeys.triggersMap[selectorId][eventType][combi]=[mapPoint];}
else{hotkeys.triggersMap[selectorId][eventType][combi][mapPoint.length]=trigger[eventType][combi];}
this.each(function(){var jqElem=jQuery(this);if(jqElem.attr('hkId')&&jqElem.attr('hkId')!==selectorId){selectorId=jqElem.attr('hkId')+";"+selectorId;}
jqElem.attr('hkId',selectorId);});result=this.__bind__(handle.join(' '),data,hotkeys.handler)}}
return result;}};hotkeys.findElement=function(elem){if(!jQuery(elem).attr('hkId')){if(jQuery.browser.opera||jQuery.browser.safari){while(!jQuery(elem).attr('hkId')&&elem.parentNode){elem=elem.parentNode;}}}
return elem;};hotkeys.handler=function(event){var target=hotkeys.findElement(event.currentTarget),jTarget=jQuery(target),ids=jTarget.attr('hkId');if(ids){ids=ids.split(';');var code=event.which,type=event.type,special=hotkeys.specialKeys[code],character=!special&&String.fromCharCode(code).toLowerCase(),shift=event.shiftKey,ctrl=event.ctrlKey,alt=event.altKey||event.originalEvent.altKey,mapPoint=null;for(var x=0;x<ids.length;x++){if(hotkeys.triggersMap[ids[x]][type]){mapPoint=hotkeys.triggersMap[ids[x]][type];break;}}
if(mapPoint){var trigger;if(!shift&&!ctrl&&!alt){trigger=mapPoint[special]||(character&&mapPoint[character]);}
else{var modif='';if(alt)modif+='alt+';if(ctrl)modif+='ctrl+';if(shift)modif+='shift+';trigger=mapPoint[modif+special];if(!trigger){if(character){trigger=mapPoint[modif+character]||mapPoint[modif+hotkeys.shiftNums[character]]||(modif==='shift+'&&mapPoint[hotkeys.shiftNums[character]]);}}}
if(trigger){var result=false;for(var x=0;x<trigger.length;x++){if(trigger[x].disableInInput){var elem=jQuery(event.target);if(jTarget.is("input")||jTarget.is("textarea")||jTarget.is("select")||elem.is("input")||elem.is("textarea")||elem.is("select")){return true;}}
result=result||trigger[x].cb.apply(this,[event]);}
return result;}}}};window.hotkeys=hotkeys;return jQuery;})(jQuery);

View File

@@ -4,6 +4,7 @@
<link rel="stylesheet" href="jpicker/jpicker.css" type="text/css"/>
<link rel="stylesheet" href="svg-editor.css" type="text/css"/>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script type="text/javascript" src="js-hotkeys/jquery.hotkeys.min.js"></script>
<script type="text/javascript" src="jquery.rightClick.js"></script>
<script type="text/javascript" src="jpicker/jpicker.js"></script>
<script type="text/javascript" src="svgcanvas.js"></script>
@@ -93,8 +94,8 @@
<img class="tool_button" id="tool_select" src="images/select.png" title="Select Tool [1]" alt="Select"/><br/>
<img class="tool_button_current" id="tool_path" src="images/path.png" title="Pencil Tool [2]" alt="Pencil"/><br/>
<img class="tool_button" id="tool_line" src="images/line.png" title="Line Tool [3]" alt="Line"/><br/>
<img class="tool_button" id="tools_rect_show" src="images/square.png" title="Square/Rect Tool [4/Shift+4]" alt="Square"/><br/>
<img class="tool_button" id="tools_ellipse_show" src="images/circle.png" title="Circle/Ellipse Tool [5/Shift+5]" alt="Circle"/><br/>
<img class="tool_button" id="tools_rect_show" src="images/square.png" title="Rect/Square Tool [4/Shift+4]" alt="Square"/><br/>
<img class="tool_button" id="tools_ellipse_show" src="images/circle.png" title="Ellipse/Circle Tool [5/Shift+5]" alt="Circle"/><br/>
<img class="tool_button" id="tool_text" src="images/text.png" title="Text Tool [6]" alt="Text"/>
<hr/>

View File

@@ -285,53 +285,19 @@ function svg_edit_setup() {
$('#tool_delete').mouseup(function(){$('#tool_delete').removeClass('tool_button_current');});
$('#tool_delete').mouseout(function(){$('#tool_delete').removeClass('tool_button_current');});
$('#workarea').keyup(function(event){
if( textBeingEntered ) { return; }
switch (event.keyCode) {
case 37: // left-arrow
break;
case 38: // up-arrow
break;
case 39: // right-arrow
break;
case 40: // down-arrow
break;
case 49: // 1
clickSelect();
break;
case 50: // 2
clickPath();
break;
case 51: // 3
clickLine();
break;
case 52: // 4
if (event.shiftKey)
clickSquare();
else
clickRect();
break;
case 53: // 5
if (event.shiftKey)
clickCircle();
else
clickEllipse();
break;
case 54: // 6
clickText();
break;
case 78: // N
clickClear();
break;
case 83: // S
clickSave();
break;
case 88: // X
clickDelete();
break;
}
});
// do keybindings using jquery-hotkeys plugin
$(document).bind('keydown', {combi:'1', disableInInput: true}, clickSelect);
$(document).bind('keydown', {combi:'2', disableInInput: true}, clickPath);
$(document).bind('keydown', {combi:'3', disableInInput: true}, clickLine);
$(document).bind('keydown', {combi:'Shift+4', disableInInput: true}, clickSquare);
$(document).bind('keydown', {combi:'4', disableInInput: true}, clickRect);
$(document).bind('keydown', {combi:'Shift+5', disableInInput: true}, clickCircle);
$(document).bind('keydown', {combi:'5', disableInInput: true}, clickEllipse);
$(document).bind('keydown', {combi:'6', disableInInput: true}, clickText);
$(document).bind('keydown', {combi:'N', disableInInput: true}, clickClear);
$(document).bind('keydown', {combi:'S', disableInInput: true}, clickSave);
$(document).bind('keydown', {combi:'X', disableInInput: true}, deleteSelected);
var colorPicker = function(elem) {
$('.tools_flyout').hide();
var oldbg = elem.css('background');