浏览代码

Keybindings improvements

Nicolas Petton 12 年之前
父节点
当前提交
96a51864dc
共有 10 个文件被更改,包括 844 次插入246 次删除
  1. 17 2
      css/helios.css
  2. 71 11
      js/Helios-Browser.deploy.js
  3. 101 21
      js/Helios-Browser.js
  4. 9 0
      js/Helios-Core.deploy.js
  5. 13 4
      js/Helios-Core.js
  6. 203 67
      js/Helios-KeyBindings.deploy.js
  7. 283 92
      js/Helios-KeyBindings.js
  8. 39 9
      st/Helios-Browser.st
  9. 3 2
      st/Helios-Core.st
  10. 105 38
      st/Helios-KeyBindings.st

+ 17 - 2
css/helios.css

@@ -29,7 +29,7 @@ a {
 
 .btn, .btn-group > .btn, .btn-group > .dropdown-menu {
     font-size: 13px;
-    padding: 2px 13px;
+    padding: 2px 8px;
 }
 
 .navbar-inner {
@@ -200,10 +200,11 @@ a {
     z-index: 20;
     position: fixed;
     bottom: 0px;
-    background: #EEE;
+    background: #ddd;
     width: 100%;
     border-top: 1px solid #AAA;
     font-size: 11px;
+    height: 22px;
 }
 
 .key_helper .command {
@@ -212,9 +213,23 @@ a {
 
 .key_helper .label {
     padding: 0 4px;
+    border-top: 1px solid white;
+    border-left: 1px solid white;
+    border-bottom: 1px solid #666;
+    border-right: 1px solid #666;
+    font-family: monospace;
 }
 
 .key_helper .action {
     padding: 0 5px;
     color: #666;
+}
+
+.key_helper .selected {
+    background: #0C8;
+    height: 30px;
+    padding: 4px;
+    color: white;
+    font-weight: bold;
+    text-shadow: 0 -1px 0 #666;
 }

+ 71 - 11
js/Helios-Browser.deploy.js

@@ -138,7 +138,8 @@ fn: function (aBindingGroup){
 var self=this;
 var $1;
 smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(66),"Browse"]);
-$1=smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(71),"Go to"]);
+smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(71),"Go to"]);
+$1=smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(84),"Toggle"]);
 return self}
 }),
 smalltalk.HLBrowser);
@@ -393,6 +394,27 @@ return self}
 }),
 smalltalk.HLClassesListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+fn: function (aBindingGroup){
+var self=this;
+var $1,$2;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(67),"Classes",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+$1=smalltalk.send(aBindingGroup,"_at_",["Toggle"]);
+smalltalk.send($1,"_addActionKey_labelled_callback_",[(73),"Instance side",(function(){
+return smalltalk.send(self,"_showInstance_",[true]);
+})]);
+$2=smalltalk.send($1,"_addActionKey_labelled_callback_",[(67),"Class side",(function(){
+return smalltalk.send(self,"_showInstance_",[false]);
+})]);
+return self}
+}),
+smalltalk.HLClassesListWidget);
+
 smalltalk.addMethod(
 "_renderButtonsOn_",
 smalltalk.method({
@@ -407,14 +429,14 @@ $2=smalltalk.send($1,"_with_",[(function(){
 $3=smalltalk.send(html,"_button",[]);
 smalltalk.send($3,"_class_",[smalltalk.send((smalltalk.String || String),"_streamContents_",[(function(str){
 smalltalk.send(str,"_nextPutAll_",["btn"]);
-$4=smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance",[]);
+$4=smalltalk.send(self,"_showInstance",[]);
 if(smalltalk.assert($4)){
 return smalltalk.send(str,"_nextPutAll_",[" active"]);
 };
 })])]);
 smalltalk.send($3,"_with_",["Instance"]);
 $5=smalltalk.send($3,"_onClick_",[(function(){
-return smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance_",[true]);
+return smalltalk.send(self,"_showInstance_",[true]);
 })]);
 $5;
 $6=smalltalk.send(html,"_button",[]);
@@ -534,17 +556,26 @@ return self}
 }),
 smalltalk.HLClassesListWidget);
 
+smalltalk.addMethod(
+"_showInstance",
+smalltalk.method({
+selector: "showInstance",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance",[]);
+return $1;
+}
+}),
+smalltalk.HLClassesListWidget);
+
 smalltalk.addMethod(
 "_showInstance_",
 smalltalk.method({
 selector: "showInstance:",
 fn: function (aBoolean){
 var self=this;
-var $1;
-$1=smalltalk.send(aBoolean,"__eq",[smalltalk.send(smalltalk.send(self,"_browser",[]),"_showInstance",[])]);
-if(! smalltalk.assert($1)){
-smalltalk.send(smalltalk.send(self,"_browser",[]),"_showInstance_",[aBoolean]);
-};
+smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance_",[aBoolean]);
 return self}
 }),
 smalltalk.HLClassesListWidget);
@@ -558,6 +589,9 @@ var self=this;
 smalltalk.send(anAnnouncer,"_on_do_",[(smalltalk.HLPackageSelected || HLPackageSelected),(function(ann){
 return smalltalk.send(self,"_packageSelected_",[smalltalk.send(ann,"_item",[])]);
 })]);
+smalltalk.send(anAnnouncer,"_on_do_",[(smalltalk.HLShowInstanceToggled || HLShowInstanceToggled),(function(ann){
+return smalltalk.send(self,"_refresh",[]);
+})]);
 return self}
 }),
 smalltalk.HLClassesListWidget);
@@ -736,6 +770,19 @@ return self}
 }),
 smalltalk.HLMethodsListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+fn: function (aBindingGroup){
+var self=this;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(77),"Methods",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+return self}
+}),
+smalltalk.HLMethodsListWidget);
+
 smalltalk.addMethod(
 "_renderContentOn_",
 smalltalk.method({
@@ -847,7 +894,7 @@ smalltalk.method({
 selector: "registerBindingsOn:",
 fn: function (aBindingGroup){
 var self=this;
-smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(67),"Packages",(function(){
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(80),"Packages",(function(){
 return smalltalk.send(self,"_focus",[]);
 })]);
 return self}
@@ -863,7 +910,7 @@ var self=this;
 var $1,$2,$3,$5,$6,$7,$8,$4,$9,$10;
 $1=smalltalk.send(html,"_span",[]);
 smalltalk.send($1,"_class_",["info"]);
-$2=smalltalk.send($1,"_with_",["Auto commit is"]);
+$2=smalltalk.send($1,"_with_",["Auto commit"]);
 $3=smalltalk.send(html,"_div",[]);
 smalltalk.send($3,"_class_",["btn-group switch"]);
 smalltalk.send($3,"_at_put_",["data-toggle","buttons-radio"]);
@@ -883,7 +930,7 @@ return $8;
 })]);
 $9=smalltalk.send(html,"_a",[]);
 smalltalk.send($9,"_class_",["btn"]);
-$10=smalltalk.send($9,"_with_",["Commit now"]);
+$10=smalltalk.send($9,"_with_",["Commit"]);
 return self}
 }),
 smalltalk.HLPackagesListWidget);
@@ -938,6 +985,19 @@ return self}
 }),
 smalltalk.HLProtocolsListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+fn: function (aBindingGroup){
+var self=this;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(84),"Protocols",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+return self}
+}),
+smalltalk.HLProtocolsListWidget);
+
 smalltalk.addMethod(
 "_renderContentOn_",
 smalltalk.method({

+ 101 - 21
js/Helios-Browser.js

@@ -179,10 +179,11 @@ fn: function (aBindingGroup){
 var self=this;
 var $1;
 smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(66),"Browse"]);
-$1=smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(71),"Go to"]);
+smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(71),"Go to"]);
+$1=smalltalk.send(aBindingGroup,"_addGroupKey_labelled_",[(84),"Toggle"]);
 return self},
 args: ["aBindingGroup"],
-source: "registerBindingsOn: aBindingGroup\x0a\x09aBindingGroup \x0a    \x09addGroupKey: 66 labelled: 'Browse';\x0a        addGroupKey: 71 labelled: 'Go to'",
+source: "registerBindingsOn: aBindingGroup\x0a\x09aBindingGroup \x0a    \x09addGroupKey: 66 labelled: 'Browse';\x0a        addGroupKey: 71 labelled: 'Go to';\x0a        addGroupKey: 84 labelled: 'Toggle'",
 messageSends: ["addGroupKey:labelled:"],
 referencedClasses: []
 }),
@@ -523,6 +524,32 @@ referencedClasses: []
 }),
 smalltalk.HLClassesListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+category: 'keybindings',
+fn: function (aBindingGroup){
+var self=this;
+var $1,$2;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(67),"Classes",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+$1=smalltalk.send(aBindingGroup,"_at_",["Toggle"]);
+smalltalk.send($1,"_addActionKey_labelled_callback_",[(73),"Instance side",(function(){
+return smalltalk.send(self,"_showInstance_",[true]);
+})]);
+$2=smalltalk.send($1,"_addActionKey_labelled_callback_",[(67),"Class side",(function(){
+return smalltalk.send(self,"_showInstance_",[false]);
+})]);
+return self},
+args: ["aBindingGroup"],
+source: "registerBindingsOn: aBindingGroup\x0a\x09(aBindingGroup at: 'Go to') \x0a    \x09addActionKey: 67 labelled: 'Classes' callback: [ self focus ].\x0a    (aBindingGroup at: 'Toggle') \x0a    \x09addActionKey: 73 labelled: 'Instance side' callback: [ self showInstance: true ];\x0a        addActionKey: 67 labelled: 'Class side' callback: [  self showInstance: false ]",
+messageSends: ["addActionKey:labelled:callback:", "focus", "at:", "showInstance:"],
+referencedClasses: []
+}),
+smalltalk.HLClassesListWidget);
+
 smalltalk.addMethod(
 "_renderButtonsOn_",
 smalltalk.method({
@@ -538,14 +565,14 @@ $2=smalltalk.send($1,"_with_",[(function(){
 $3=smalltalk.send(html,"_button",[]);
 smalltalk.send($3,"_class_",[smalltalk.send((smalltalk.String || String),"_streamContents_",[(function(str){
 smalltalk.send(str,"_nextPutAll_",["btn"]);
-$4=smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance",[]);
+$4=smalltalk.send(self,"_showInstance",[]);
 if(smalltalk.assert($4)){
 return smalltalk.send(str,"_nextPutAll_",[" active"]);
 };
 })])]);
 smalltalk.send($3,"_with_",["Instance"]);
 $5=smalltalk.send($3,"_onClick_",[(function(){
-return smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance_",[true]);
+return smalltalk.send(self,"_showInstance_",[true]);
 })]);
 $5;
 $6=smalltalk.send(html,"_button",[]);
@@ -568,8 +595,8 @@ smalltalk.send($9,"_at_put_",["data-toggle","button"]);
 $10=smalltalk.send($9,"_with_",["Comment"]);
 return self},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09html div \x0a        class: 'btn-group';\x0a\x09\x09at: 'data-toggle' put: 'buttons-radio';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self model showInstance ifTrue: [ \x0a                    \x09str nextPutAll: ' active'] ]);\x0a  \x09\x09\x09\x09with: 'Instance';\x0a                onClick: [ self model showInstance: true ].\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self model showInstance ifFalse: [ \x0a                    \x09str nextPutAll: ' active'] ]);\x0a  \x09\x09\x09\x09with: 'Class';\x0a\x09\x09\x09\x09onClick: [ self model showInstance: false ] ].\x0a                 \x0a  \x09html button \x0a           \x09class: 'btn';\x0a            at: 'data-toggle' put: 'button';\x0a  \x09\x09\x09with: 'Comment'",
-messageSends: ["class:", "div", "at:put:", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "model", "button", "onClick:", "showInstance:", "ifFalse:"],
+source: "renderButtonsOn: html\x0a\x09html div \x0a        class: 'btn-group';\x0a\x09\x09at: 'data-toggle' put: 'buttons-radio';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showInstance ifTrue: [ \x0a                    \x09str nextPutAll: ' active'] ]);\x0a  \x09\x09\x09\x09with: 'Instance';\x0a                onClick: [ self showInstance: true ].\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self model showInstance ifFalse: [ \x0a                    \x09str nextPutAll: ' active'] ]);\x0a  \x09\x09\x09\x09with: 'Class';\x0a\x09\x09\x09\x09onClick: [ self model showInstance: false ] ].\x0a                 \x0a  \x09html button \x0a           \x09class: 'btn';\x0a            at: 'data-toggle' put: 'button';\x0a  \x09\x09\x09with: 'Comment'",
+messageSends: ["class:", "div", "at:put:", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "button", "onClick:", "showInstance:", "ifFalse:", "model"],
 referencedClasses: ["String"]
 }),
 smalltalk.HLClassesListWidget);
@@ -699,6 +726,24 @@ referencedClasses: []
 }),
 smalltalk.HLClassesListWidget);
 
+smalltalk.addMethod(
+"_showInstance",
+smalltalk.method({
+selector: "showInstance",
+category: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance",[]);
+return $1;
+},
+args: [],
+source: "showInstance\x0a\x09^ self model showInstance",
+messageSends: ["showInstance", "model"],
+referencedClasses: []
+}),
+smalltalk.HLClassesListWidget);
+
 smalltalk.addMethod(
 "_showInstance_",
 smalltalk.method({
@@ -706,15 +751,11 @@ selector: "showInstance:",
 category: 'actions',
 fn: function (aBoolean){
 var self=this;
-var $1;
-$1=smalltalk.send(aBoolean,"__eq",[smalltalk.send(smalltalk.send(self,"_browser",[]),"_showInstance",[])]);
-if(! smalltalk.assert($1)){
-smalltalk.send(smalltalk.send(self,"_browser",[]),"_showInstance_",[aBoolean]);
-};
+smalltalk.send(smalltalk.send(self,"_model",[]),"_showInstance_",[aBoolean]);
 return self},
 args: ["aBoolean"],
-source: "showInstance: aBoolean\x0a\x09aBoolean = self browser showInstance ifFalse: [\x0a\x09\x09self browser showInstance: aBoolean ]",
-messageSends: ["ifFalse:", "showInstance:", "browser", "=", "showInstance"],
+source: "showInstance: aBoolean\x0a\x09self model showInstance: aBoolean",
+messageSends: ["showInstance:", "model"],
 referencedClasses: []
 }),
 smalltalk.HLClassesListWidget);
@@ -729,11 +770,14 @@ var self=this;
 smalltalk.send(anAnnouncer,"_on_do_",[(smalltalk.HLPackageSelected || HLPackageSelected),(function(ann){
 return smalltalk.send(self,"_packageSelected_",[smalltalk.send(ann,"_item",[])]);
 })]);
+smalltalk.send(anAnnouncer,"_on_do_",[(smalltalk.HLShowInstanceToggled || HLShowInstanceToggled),(function(ann){
+return smalltalk.send(self,"_refresh",[]);
+})]);
 return self},
 args: ["anAnnouncer"],
-source: "subscribeTo: anAnnouncer\x0a\x09anAnnouncer on: HLPackageSelected do: [ :ann |\x0a    \x09self packageSelected: ann item ]\x0a    ",
-messageSends: ["on:do:", "packageSelected:", "item"],
-referencedClasses: ["HLPackageSelected"]
+source: "subscribeTo: anAnnouncer\x0a\x09anAnnouncer on: HLPackageSelected do: [ :ann |\x0a    \x09self packageSelected: ann item ].\x0a    anAnnouncer on: HLShowInstanceToggled do: [ :ann |\x0a    \x09self refresh ]",
+messageSends: ["on:do:", "packageSelected:", "item", "refresh"],
+referencedClasses: ["HLPackageSelected", "HLShowInstanceToggled"]
 }),
 smalltalk.HLClassesListWidget);
 
@@ -961,6 +1005,24 @@ referencedClasses: []
 }),
 smalltalk.HLMethodsListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+category: 'keybindings',
+fn: function (aBindingGroup){
+var self=this;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(77),"Methods",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+return self},
+args: ["aBindingGroup"],
+source: "registerBindingsOn: aBindingGroup\x0a\x09(aBindingGroup at: 'Go to') \x0a    \x09addActionKey: 77 labelled: 'Methods' callback: [ self focus ]",
+messageSends: ["addActionKey:labelled:callback:", "focus", "at:"],
+referencedClasses: []
+}),
+smalltalk.HLMethodsListWidget);
+
 smalltalk.addMethod(
 "_renderContentOn_",
 smalltalk.method({
@@ -1108,12 +1170,12 @@ selector: "registerBindingsOn:",
 category: 'keybindings',
 fn: function (aBindingGroup){
 var self=this;
-smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(67),"Packages",(function(){
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(80),"Packages",(function(){
 return smalltalk.send(self,"_focus",[]);
 })]);
 return self},
 args: ["aBindingGroup"],
-source: "registerBindingsOn: aBindingGroup\x0a\x09(aBindingGroup at: 'Go to') \x0a    \x09addActionKey: 67 labelled: 'Packages' callback: [ self focus ]",
+source: "registerBindingsOn: aBindingGroup\x0a\x09(aBindingGroup at: 'Go to') \x0a    \x09addActionKey: 80 labelled: 'Packages' callback: [ self focus ]",
 messageSends: ["addActionKey:labelled:callback:", "focus", "at:"],
 referencedClasses: []
 }),
@@ -1129,7 +1191,7 @@ var self=this;
 var $1,$2,$3,$5,$6,$7,$8,$4,$9,$10;
 $1=smalltalk.send(html,"_span",[]);
 smalltalk.send($1,"_class_",["info"]);
-$2=smalltalk.send($1,"_with_",["Auto commit is"]);
+$2=smalltalk.send($1,"_with_",["Auto commit"]);
 $3=smalltalk.send(html,"_div",[]);
 smalltalk.send($3,"_class_",["btn-group switch"]);
 smalltalk.send($3,"_at_put_",["data-toggle","buttons-radio"]);
@@ -1149,10 +1211,10 @@ return $8;
 })]);
 $9=smalltalk.send(html,"_a",[]);
 smalltalk.send($9,"_class_",["btn"]);
-$10=smalltalk.send($9,"_with_",["Commit now"]);
+$10=smalltalk.send($9,"_with_",["Commit"]);
 return self},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x0a\x09html span class: 'info'; with: 'Auto commit is'.\x0a\x09html div \x0a        class: 'btn-group switch';\x0a\x09\x09at: 'data-toggle' put: 'buttons-radio';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn' ]);\x0a  \x09\x09\x09\x09with: 'On'.\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn active' ]);\x0a  \x09\x09\x09\x09with: 'Off' ].\x0a                \x0a    html a \x0a         \x09class: 'btn';\x0a\x09\x09\x09with: 'Commit now'.",
+source: "renderButtonsOn: html\x0a\x0a\x09html span class: 'info'; with: 'Auto commit'.\x0a\x09html div \x0a        class: 'btn-group switch';\x0a\x09\x09at: 'data-toggle' put: 'buttons-radio';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn' ]);\x0a  \x09\x09\x09\x09with: 'On'.\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn active' ]);\x0a  \x09\x09\x09\x09with: 'Off' ].\x0a                \x0a    html a \x0a         \x09class: 'btn';\x0a\x09\x09\x09with: 'Commit'.",
 messageSends: ["class:", "span", "with:", "div", "at:put:", "streamContents:", "nextPutAll:", "button", "a"],
 referencedClasses: ["String"]
 }),
@@ -1223,6 +1285,24 @@ referencedClasses: ["Array"]
 }),
 smalltalk.HLProtocolsListWidget);
 
+smalltalk.addMethod(
+"_registerBindingsOn_",
+smalltalk.method({
+selector: "registerBindingsOn:",
+category: 'keybindings',
+fn: function (aBindingGroup){
+var self=this;
+smalltalk.send(smalltalk.send(aBindingGroup,"_at_",["Go to"]),"_addActionKey_labelled_callback_",[(84),"Protocols",(function(){
+return smalltalk.send(self,"_focus",[]);
+})]);
+return self},
+args: ["aBindingGroup"],
+source: "registerBindingsOn: aBindingGroup\x0a\x09(aBindingGroup at: 'Go to') \x0a    \x09addActionKey: 84 labelled: 'Protocols' callback: [ self focus ]",
+messageSends: ["addActionKey:labelled:callback:", "focus", "at:"],
+referencedClasses: []
+}),
+smalltalk.HLProtocolsListWidget);
+
 smalltalk.addMethod(
 "_renderContentOn_",
 smalltalk.method({

+ 9 - 0
js/Helios-Core.deploy.js

@@ -1009,8 +1009,12 @@ smalltalk.method({
 selector: "next:",
 fn: function (aWidget){
 var self=this;
+var $1;
 self["@next"]=aWidget;
+$1=smalltalk.send(smalltalk.send(aWidget,"_previous",[]),"__eq",[self]);
+if(! smalltalk.assert($1)){
 smalltalk.send(aWidget,"_previous_",[self]);
+};
 return self}
 }),
 smalltalk.HLNavigationListWidget);
@@ -1049,7 +1053,12 @@ smalltalk.method({
 selector: "previous:",
 fn: function (aWidget){
 var self=this;
+var $1;
 self["@previous"]=aWidget;
+$1=smalltalk.send(smalltalk.send(aWidget,"_next",[]),"__eq",[self]);
+if(! smalltalk.assert($1)){
+smalltalk.send(aWidget,"_next_",[self]);
+};
 return self}
 }),
 smalltalk.HLNavigationListWidget);

+ 13 - 4
js/Helios-Core.js

@@ -1360,12 +1360,16 @@ selector: "next:",
 category: 'accessing',
 fn: function (aWidget){
 var self=this;
+var $1;
 self["@next"]=aWidget;
+$1=smalltalk.send(smalltalk.send(aWidget,"_previous",[]),"__eq",[self]);
+if(! smalltalk.assert($1)){
 smalltalk.send(aWidget,"_previous_",[self]);
+};
 return self},
 args: ["aWidget"],
-source: "next: aWidget\x0a\x09next := aWidget.\x0a    aWidget previous: self",
-messageSends: ["previous:"],
+source: "next: aWidget\x0a\x09next := aWidget.\x0a    aWidget previous = self ifFalse: [ aWidget previous: self ]",
+messageSends: ["ifFalse:", "previous:", "=", "previous"],
 referencedClasses: []
 }),
 smalltalk.HLNavigationListWidget);
@@ -1415,11 +1419,16 @@ selector: "previous:",
 category: 'accessing',
 fn: function (aWidget){
 var self=this;
+var $1;
 self["@previous"]=aWidget;
+$1=smalltalk.send(smalltalk.send(aWidget,"_next",[]),"__eq",[self]);
+if(! smalltalk.assert($1)){
+smalltalk.send(aWidget,"_next_",[self]);
+};
 return self},
 args: ["aWidget"],
-source: "previous: aWidget\x0a\x09previous := aWidget",
-messageSends: [],
+source: "previous: aWidget\x0a\x09previous := aWidget.\x0a    aWidget next = self ifFalse: [ aWidget next: self ]",
+messageSends: ["ifFalse:", "next:", "=", "next"],
 referencedClasses: []
 }),
 smalltalk.HLNavigationListWidget);

+ 203 - 67
js/Helios-KeyBindings.deploy.js

@@ -1,5 +1,16 @@
 smalltalk.addPackage('Helios-KeyBindings', {});
 smalltalk.addClass('HLBinding', smalltalk.Object, ['key', 'label'], 'Helios-KeyBindings');
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(self,"_subclassResponsibility",[]);
+return self}
+}),
+smalltalk.HLBinding);
+
 smalltalk.addMethod(
 "_isBindingAction",
 smalltalk.method({
@@ -66,6 +77,16 @@ return self}
 }),
 smalltalk.HLBinding);
 
+smalltalk.addMethod(
+"_renderOn_html_",
+smalltalk.method({
+selector: "renderOn:html:",
+fn: function (aBindingHelper,html){
+var self=this;
+return self}
+}),
+smalltalk.HLBinding);
+
 smalltalk.addMethod(
 "_shortcut",
 smalltalk.method({
@@ -99,6 +120,17 @@ smalltalk.HLBinding.klass);
 
 
 smalltalk.addClass('HLBindingAction', smalltalk.HLBinding, ['callback'], 'Helios-KeyBindings');
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(aKeyBinder,"_applyBindingAction_",[self]);
+return self}
+}),
+smalltalk.HLBindingAction);
+
 smalltalk.addMethod(
 "_callback",
 smalltalk.method({
@@ -174,6 +206,17 @@ return self}
 }),
 smalltalk.HLBindingGroup);
 
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(aKeyBinder,"_applyBindingGroup_",[self]);
+return self}
+}),
+smalltalk.HLBindingGroup);
+
 smalltalk.addMethod(
 "_at_",
 smalltalk.method({
@@ -192,9 +235,9 @@ return $1;
 smalltalk.HLBindingGroup);
 
 smalltalk.addMethod(
-"_atkey_",
+"_atKey_",
 smalltalk.method({
-selector: "atkey:",
+selector: "atKey:",
 fn: function (anInteger){
 var self=this;
 var $1;
@@ -237,6 +280,17 @@ return true;
 }),
 smalltalk.HLBindingGroup);
 
+smalltalk.addMethod(
+"_renderOn_html_",
+smalltalk.method({
+selector: "renderOn:html:",
+fn: function (aBindingHelper,html){
+var self=this;
+smalltalk.send(aBindingHelper,"_renderBindingGroup_on_",[self,html]);
+return self}
+}),
+smalltalk.HLBindingGroup);
+
 
 
 smalltalk.addClass('HLKeyBinder', smalltalk.Object, ['modifierKey', 'active', 'helper', 'bindings', 'selectedBinding'], 'Helios-KeyBindings');
@@ -252,22 +306,48 @@ return self}
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_activationKey",
+smalltalk.method({
+selector: "activationKey",
+fn: function (){
+var self=this;
+return (32);
+}
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_applyBinding_",
 smalltalk.method({
 selector: "applyBinding:",
 fn: function (aBinding){
 var self=this;
-var $1;
-$1=smalltalk.send(aBinding,"_isBindingGroup",[]);
-if(smalltalk.assert($1)){
-self["@selectedBinding"]=aBinding;
-self["@selectedBinding"];
-smalltalk.send(smalltalk.send(self,"_helper",[]),"_refresh",[]);
-} else {
+smalltalk.send(aBinding,"_applyOn_",[self]);
+return self}
+}),
+smalltalk.HLKeyBinder);
+
+smalltalk.addMethod(
+"_applyBindingAction_",
+smalltalk.method({
+selector: "applyBindingAction:",
+fn: function (aBinding){
+var self=this;
 smalltalk.send(smalltalk.send(aBinding,"_callback",[]),"_value",[]);
 smalltalk.send(self,"_deactivate",[]);
-};
+return self}
+}),
+smalltalk.HLKeyBinder);
+
+smalltalk.addMethod(
+"_applyBindingGroup_",
+smalltalk.method({
+selector: "applyBindingGroup:",
+fn: function (aBinding){
+var self=this;
+self["@selectedBinding"]=aBinding;
+smalltalk.send(smalltalk.send(self,"_helper",[]),"_refresh",[]);
 return self}
 }),
 smalltalk.HLKeyBinder);
@@ -303,6 +383,17 @@ return self}
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_escapeKey",
+smalltalk.method({
+selector: "escapeKey",
+fn: function (){
+var self=this;
+return (27);
+}
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_flushBindings",
 smalltalk.method({
@@ -315,6 +406,29 @@ return self}
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_handleActiveKeyDown_",
+smalltalk.method({
+selector: "handleActiveKeyDown:",
+fn: function (event){
+var self=this;
+var $1,$2;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_escapeKey",[])]),"_or_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[(71)]),"_and_",[(function(){
+return smalltalk.send(event,"_ctrlKey",[]);
+})]);
+})]);
+if(smalltalk.assert($1)){
+smalltalk.send(self,"_deactivate",[]);
+smalltalk.send(event,"_preventDefault",[]);
+return false;
+};
+$2=smalltalk.send(self,"_handleBindingFor_",[event]);
+return $2;
+}
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_handleBindingFor_",
 smalltalk.method({
@@ -335,27 +449,20 @@ return self}
 smalltalk.HLKeyBinder);
 
 smalltalk.addMethod(
-"_handleBindingKey_",
-smalltalk.method({
-selector: "handleBindingKey:",
-fn: function (anInteger){
-var self=this;
-return self}
-}),
-smalltalk.HLKeyBinder);
-
-smalltalk.addMethod(
-"_handleKeyDown_",
+"_handleInactiveKeyDown_",
 smalltalk.method({
-selector: "handleKeyDown:",
+selector: "handleInactiveKeyDown:",
 fn: function (event){
 var self=this;
-var $1,$2;
-$1=smalltalk.send(self,"_isActive",[]);
+var $1,$3,$2;
+$1=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_activationKey",[])]);
 if(smalltalk.assert($1)){
-smalltalk.send(self,"_handleBindingKey_",[smalltalk.send(event,"_which",[])]);
+$3=smalltalk.send(self,"_systemIsMac",[]);
+if(smalltalk.assert($3)){
+$2=smalltalk.send(event,"_metaKey",[]);
 } else {
-$2=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_modifierKey",[])]);
+$2=smalltalk.send(event,"_ctrlKey",[]);
+};
 if(smalltalk.assert($2)){
 smalltalk.send(self,"_activate",[]);
 smalltalk.send(event,"_preventDefault",[]);
@@ -367,17 +474,20 @@ return self}
 smalltalk.HLKeyBinder);
 
 smalltalk.addMethod(
-"_handleKeyUp_",
+"_handleKeyDown_",
 smalltalk.method({
-selector: "handleKeyUp:",
+selector: "handleKeyDown:",
 fn: function (event){
 var self=this;
-var $1;
-$1=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_modifierKey",[])]);
-if(smalltalk.assert($1)){
-smalltalk.send(self,"_deactivate",[]);
+var $2,$1;
+$2=smalltalk.send(self,"_isActive",[]);
+if(smalltalk.assert($2)){
+$1=smalltalk.send(self,"_handleActiveKeyDown_",[event]);
+} else {
+$1=smalltalk.send(self,"_handleInactiveKeyDown_",[event]);
 };
-return self}
+return $1;
+}
 }),
 smalltalk.HLKeyBinder);
 
@@ -428,28 +538,6 @@ return $1;
 }),
 smalltalk.HLKeyBinder);
 
-smalltalk.addMethod(
-"_modifierKey",
-smalltalk.method({
-selector: "modifierKey",
-fn: function (){
-var self=this;
-var $2,$1;
-if(($receiver = self["@modifierKey"]) == nil || $receiver == undefined){
-$2=smalltalk.send(self["@modifierKey"],"__eq",[smalltalk.send(smalltalk.send(navigator,"_platform",[]),"_match_",["Mac"])]);
-if(smalltalk.assert($2)){
-$1=(91);
-} else {
-$1=(17);
-};
-} else {
-$1=self["@modifierKey"];
-};
-return $1;
-}
-}),
-smalltalk.HLKeyBinder);
-
 smalltalk.addMethod(
 "_selectedBinding",
 smalltalk.method({
@@ -476,13 +564,23 @@ var self=this;
 smalltalk.send(smalltalk.send(window,"_jQuery_",["body"]),"_keydown_",[(function(event){
 return smalltalk.send(self,"_handleKeyDown_",[event]);
 })]);
-smalltalk.send(smalltalk.send(window,"_jQuery_",["body"]),"_keyup_",[(function(event){
-return smalltalk.send(self,"_handleKeyUp_",[event]);
-})]);
 return self}
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_systemIsMac",
+smalltalk.method({
+selector: "systemIsMac",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(navigator,"_platform",[]),"_match_",["Mac"]);
+return $1;
+}
+}),
+smalltalk.HLKeyBinder);
+
 
 
 smalltalk.addClass('HLKeyBinderHelper', smalltalk.HLWidget, ['keyBinder'], 'Helios-KeyBindings');
@@ -492,7 +590,7 @@ smalltalk.method({
 selector: "hide",
 fn: function (){
 var self=this;
-smalltalk.send(smalltalk.send(window,"_jQuery_",[".key_helper"]),"_remove",[]);
+smalltalk.send(smalltalk.send(self["@rootDiv"],"_asJQuery",[]),"_remove",[]);
 return self}
 }),
 smalltalk.HLKeyBinderHelper);
@@ -530,13 +628,15 @@ return self}
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
-"_renderBindingsOn_",
+"_renderBindingGroup_on_",
 smalltalk.method({
-selector: "renderBindingsOn:",
-fn: function (html){
+selector: "renderBindingGroup:on:",
+fn: function (aBindingGroup,html){
 var self=this;
 var $1,$3,$4,$5,$6,$2;
-smalltalk.send(smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_bindings",[]),"_do_",[(function(each){
+smalltalk.send(smalltalk.send(smalltalk.send(aBindingGroup,"_bindings",[]),"_sorted_",[(function(a,b){
+return smalltalk.send(smalltalk.send(a,"_key",[]),"__lt",[smalltalk.send(b,"_key",[])]);
+})]),"_do_",[(function(each){
 $1=smalltalk.send(html,"_span",[]);
 smalltalk.send($1,"_class_",["command"]);
 $2=smalltalk.send($1,"_with_",[(function(){
@@ -544,9 +644,12 @@ $3=smalltalk.send(html,"_span",[]);
 smalltalk.send($3,"_class_",["label"]);
 $4=smalltalk.send($3,"_with_",[smalltalk.send(smalltalk.send(each,"_shortcut",[]),"_asLowercase",[])]);
 $4;
-$5=smalltalk.send(html,"_span",[]);
+$5=smalltalk.send(html,"_a",[]);
 smalltalk.send($5,"_class_",["action"]);
-$6=smalltalk.send($5,"_with_",[smalltalk.send(each,"_label",[])]);
+smalltalk.send($5,"_with_",[smalltalk.send(each,"_label",[])]);
+$6=smalltalk.send($5,"_onClick_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_keyBinder",[]),"_applyBinding_",[each]);
+})]);
 return $6;
 })]);
 return $2;
@@ -555,22 +658,55 @@ return self}
 }),
 smalltalk.HLKeyBinderHelper);
 
+smalltalk.addMethod(
+"_renderBindingOn_",
+smalltalk.method({
+selector: "renderBindingOn:",
+fn: function (html){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_renderOn_html_",[self,html]);
+return self}
+}),
+smalltalk.HLKeyBinderHelper);
+
 smalltalk.addMethod(
 "_renderContentOn_",
 smalltalk.method({
 selector: "renderContentOn:",
 fn: function (html){
 var self=this;
-var $1,$2;
+var $1,$3,$2;
 $1=smalltalk.send(html,"_div",[]);
 smalltalk.send($1,"_class_",["key_helper"]);
 $2=smalltalk.send($1,"_with_",[(function(){
-return smalltalk.send(self,"_renderBindingsOn_",[html]);
+smalltalk.send(self,"_renderSelectionOn_",[html]);
+$3=smalltalk.send(self,"_renderBindingOn_",[html]);
+return $3;
 })]);
 return self}
 }),
 smalltalk.HLKeyBinderHelper);
 
+smalltalk.addMethod(
+"_renderSelectionOn_",
+smalltalk.method({
+selector: "renderSelectionOn:",
+fn: function (html){
+var self=this;
+var $1,$4,$3,$2;
+$1=smalltalk.send(html,"_span",[]);
+smalltalk.send($1,"_class_",["selected"]);
+$4=smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_label",[]);
+if(($receiver = $4) == nil || $receiver == undefined){
+$3="Action";
+} else {
+$3=$4;
+};
+$2=smalltalk.send($1,"_with_",[$3]);
+return self}
+}),
+smalltalk.HLKeyBinderHelper);
+
 smalltalk.addMethod(
 "_selectedBinding",
 smalltalk.method({

+ 283 - 92
js/Helios-KeyBindings.js

@@ -1,5 +1,21 @@
 smalltalk.addPackage('Helios-KeyBindings', {});
 smalltalk.addClass('HLBinding', smalltalk.Object, ['key', 'label'], 'Helios-KeyBindings');
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+category: 'actions',
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(self,"_subclassResponsibility",[]);
+return self},
+args: ["aKeyBinder"],
+source: "applyOn: aKeyBinder\x0a\x09self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
+referencedClasses: []
+}),
+smalltalk.HLBinding);
+
 smalltalk.addMethod(
 "_isBindingAction",
 smalltalk.method({
@@ -96,6 +112,21 @@ referencedClasses: []
 }),
 smalltalk.HLBinding);
 
+smalltalk.addMethod(
+"_renderOn_html_",
+smalltalk.method({
+selector: "renderOn:html:",
+category: 'rendering',
+fn: function (aBindingHelper,html){
+var self=this;
+return self},
+args: ["aBindingHelper", "html"],
+source: "renderOn: aBindingHelper html: html",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HLBinding);
+
 smalltalk.addMethod(
 "_shortcut",
 smalltalk.method({
@@ -139,6 +170,22 @@ smalltalk.HLBinding.klass);
 
 
 smalltalk.addClass('HLBindingAction', smalltalk.HLBinding, ['callback'], 'Helios-KeyBindings');
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+category: 'actions',
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(aKeyBinder,"_applyBindingAction_",[self]);
+return self},
+args: ["aKeyBinder"],
+source: "applyOn: aKeyBinder\x0a\x09aKeyBinder applyBindingAction: self",
+messageSends: ["applyBindingAction:"],
+referencedClasses: []
+}),
+smalltalk.HLBindingAction);
+
 smalltalk.addMethod(
 "_callback",
 smalltalk.method({
@@ -244,6 +291,22 @@ referencedClasses: ["HLBindingGroup"]
 }),
 smalltalk.HLBindingGroup);
 
+smalltalk.addMethod(
+"_applyOn_",
+smalltalk.method({
+selector: "applyOn:",
+category: 'actions',
+fn: function (aKeyBinder){
+var self=this;
+smalltalk.send(aKeyBinder,"_applyBindingGroup_",[self]);
+return self},
+args: ["aKeyBinder"],
+source: "applyOn: aKeyBinder\x0a\x09aKeyBinder applyBindingGroup: self",
+messageSends: ["applyBindingGroup:"],
+referencedClasses: []
+}),
+smalltalk.HLBindingGroup);
+
 smalltalk.addMethod(
 "_at_",
 smalltalk.method({
@@ -267,9 +330,9 @@ referencedClasses: []
 smalltalk.HLBindingGroup);
 
 smalltalk.addMethod(
-"_atkey_",
+"_atKey_",
 smalltalk.method({
-selector: "atkey:",
+selector: "atKey:",
 category: 'accessing',
 fn: function (anInteger){
 var self=this;
@@ -282,7 +345,7 @@ return nil;
 return $1;
 },
 args: ["anInteger"],
-source: "atkey: anInteger\x0a\x09^ self bindings \x0a    \x09detect: [ :each | each key = anInteger ]\x0a      \x09ifNone: [ nil ]",
+source: "atKey: anInteger\x0a\x09^ self bindings \x0a    \x09detect: [ :each | each key = anInteger ]\x0a      \x09ifNone: [ nil ]",
 messageSends: ["detect:ifNone:", "=", "key", "bindings"],
 referencedClasses: []
 }),
@@ -327,6 +390,22 @@ referencedClasses: []
 }),
 smalltalk.HLBindingGroup);
 
+smalltalk.addMethod(
+"_renderOn_html_",
+smalltalk.method({
+selector: "renderOn:html:",
+category: 'rendering',
+fn: function (aBindingHelper,html){
+var self=this;
+smalltalk.send(aBindingHelper,"_renderBindingGroup_on_",[self,html]);
+return self},
+args: ["aBindingHelper", "html"],
+source: "renderOn: aBindingHelper html: html\x0a\x09aBindingHelper renderBindingGroup: self on: html",
+messageSends: ["renderBindingGroup:on:"],
+referencedClasses: []
+}),
+smalltalk.HLBindingGroup);
+
 
 
 smalltalk.addClass('HLKeyBinder', smalltalk.Object, ['modifierKey', 'active', 'helper', 'bindings', 'selectedBinding'], 'Helios-KeyBindings');
@@ -347,6 +426,22 @@ referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_activationKey",
+smalltalk.method({
+selector: "activationKey",
+category: 'accessing',
+fn: function (){
+var self=this;
+return (32);
+},
+args: [],
+source: "activationKey\x0a\x09\x22SPACE\x22\x0a\x09^ 32",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_applyBinding_",
 smalltalk.method({
@@ -354,20 +449,45 @@ selector: "applyBinding:",
 category: 'actions',
 fn: function (aBinding){
 var self=this;
-var $1;
-$1=smalltalk.send(aBinding,"_isBindingGroup",[]);
-if(smalltalk.assert($1)){
-self["@selectedBinding"]=aBinding;
-self["@selectedBinding"];
-smalltalk.send(smalltalk.send(self,"_helper",[]),"_refresh",[]);
-} else {
+smalltalk.send(aBinding,"_applyOn_",[self]);
+return self},
+args: ["aBinding"],
+source: "applyBinding: aBinding\x0a    aBinding applyOn: self",
+messageSends: ["applyOn:"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
+smalltalk.addMethod(
+"_applyBindingAction_",
+smalltalk.method({
+selector: "applyBindingAction:",
+category: 'actions',
+fn: function (aBinding){
+var self=this;
 smalltalk.send(smalltalk.send(aBinding,"_callback",[]),"_value",[]);
 smalltalk.send(self,"_deactivate",[]);
-};
 return self},
 args: ["aBinding"],
-source: "applyBinding: aBinding\x0a    aBinding isBindingGroup\x0a    \x09ifTrue: [\x0a\x09\x09\x09selectedBinding := aBinding.\x0a    \x09\x09self helper refresh ]\x0a        ifFalse: [ \x0a\x09\x09\x09aBinding callback value.\x0a\x09\x09\x09self deactivate ]",
-messageSends: ["ifTrue:ifFalse:", "refresh", "helper", "value", "callback", "deactivate", "isBindingGroup"],
+source: "applyBindingAction: aBinding\x0a    aBinding callback value.\x0a\x09self deactivate",
+messageSends: ["value", "callback", "deactivate"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
+smalltalk.addMethod(
+"_applyBindingGroup_",
+smalltalk.method({
+selector: "applyBindingGroup:",
+category: 'actions',
+fn: function (aBinding){
+var self=this;
+self["@selectedBinding"]=aBinding;
+smalltalk.send(smalltalk.send(self,"_helper",[]),"_refresh",[]);
+return self},
+args: ["aBinding"],
+source: "applyBindingGroup: aBinding\x0a    selectedBinding := aBinding.\x0a    self helper refresh",
+messageSends: ["refresh", "helper"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
@@ -413,6 +533,22 @@ referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_escapeKey",
+smalltalk.method({
+selector: "escapeKey",
+category: 'accessing',
+fn: function (){
+var self=this;
+return (27);
+},
+args: [],
+source: "escapeKey\x0a\x09\x22ESC\x22\x0a\x09^ 27",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_flushBindings",
 smalltalk.method({
@@ -430,6 +566,34 @@ referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
 
+smalltalk.addMethod(
+"_handleActiveKeyDown_",
+smalltalk.method({
+selector: "handleActiveKeyDown:",
+category: 'events',
+fn: function (event){
+var self=this;
+var $1,$2;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_escapeKey",[])]),"_or_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[(71)]),"_and_",[(function(){
+return smalltalk.send(event,"_ctrlKey",[]);
+})]);
+})]);
+if(smalltalk.assert($1)){
+smalltalk.send(self,"_deactivate",[]);
+smalltalk.send(event,"_preventDefault",[]);
+return false;
+};
+$2=smalltalk.send(self,"_handleBindingFor_",[event]);
+return $2;
+},
+args: ["event"],
+source: "handleActiveKeyDown: event\x0a\x0a\x09\x22ESC or ctrl+g deactivate the keyBinder\x22\x0a\x09(event which = self escapeKey or: [\x0a\x09\x09event which = 71 and: [ event ctrlKey ] ])\x0a        \x09ifTrue: [ \x0a            \x09self deactivate.\x0a\x09\x09\x09\x09event preventDefault.\x0a\x09\x09\x09\x09^ false ].\x0a            \x0a    \x22Handle the keybinding\x22\x0a    ^ self handleBindingFor: event",
+messageSends: ["ifTrue:", "deactivate", "preventDefault", "or:", "and:", "ctrlKey", "=", "which", "escapeKey", "handleBindingFor:"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
 smalltalk.addMethod(
 "_handleBindingFor_",
 smalltalk.method({
@@ -455,33 +619,21 @@ referencedClasses: []
 smalltalk.HLKeyBinder);
 
 smalltalk.addMethod(
-"_handleBindingKey_",
+"_handleInactiveKeyDown_",
 smalltalk.method({
-selector: "handleBindingKey:",
-category: 'events',
-fn: function (anInteger){
-var self=this;
-return self},
-args: ["anInteger"],
-source: "handleBindingKey: anInteger",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.HLKeyBinder);
-
-smalltalk.addMethod(
-"_handleKeyDown_",
-smalltalk.method({
-selector: "handleKeyDown:",
+selector: "handleInactiveKeyDown:",
 category: 'events',
 fn: function (event){
 var self=this;
-var $1,$2;
-$1=smalltalk.send(self,"_isActive",[]);
+var $1,$3,$2;
+$1=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_activationKey",[])]);
 if(smalltalk.assert($1)){
-smalltalk.send(self,"_handleBindingKey_",[smalltalk.send(event,"_which",[])]);
+$3=smalltalk.send(self,"_systemIsMac",[]);
+if(smalltalk.assert($3)){
+$2=smalltalk.send(event,"_metaKey",[]);
 } else {
-$2=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_modifierKey",[])]);
+$2=smalltalk.send(event,"_ctrlKey",[]);
+};
 if(smalltalk.assert($2)){
 smalltalk.send(self,"_activate",[]);
 smalltalk.send(event,"_preventDefault",[]);
@@ -490,28 +642,31 @@ return false;
 };
 return self},
 args: ["event"],
-source: "handleKeyDown: event\x0a\x09self isActive\x0a    \x09ifTrue: [ \x0a        \x09self handleBindingKey: event which ]\x0a      \x09ifFalse: [\x0a          \x09event which = self modifierKey ifTrue: [\x0a\x09\x09\x09\x09self activate. \x0a                event preventDefault. \x0a                ^ false ] ]",
-messageSends: ["ifTrue:ifFalse:", "handleBindingKey:", "which", "ifTrue:", "activate", "preventDefault", "=", "modifierKey", "isActive"],
+source: "handleInactiveKeyDown: event\x0a\x09event which = self activationKey ifTrue: [\x0a          (self systemIsMac\x0a                ifTrue: [ event metaKey ]\x0a                  ifFalse: [  event ctrlKey ])  ifTrue: [\x0a\x09\x09\x09\x09\x09self activate. \x0a               \x09\x09 event preventDefault. \x0a                \x09^ false ] ]",
+messageSends: ["ifTrue:", "activate", "preventDefault", "ifTrue:ifFalse:", "metaKey", "ctrlKey", "systemIsMac", "=", "activationKey", "which"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
 
 smalltalk.addMethod(
-"_handleKeyUp_",
+"_handleKeyDown_",
 smalltalk.method({
-selector: "handleKeyUp:",
+selector: "handleKeyDown:",
 category: 'events',
 fn: function (event){
 var self=this;
-var $1;
-$1=smalltalk.send(smalltalk.send(event,"_which",[]),"__eq",[smalltalk.send(self,"_modifierKey",[])]);
-if(smalltalk.assert($1)){
-smalltalk.send(self,"_deactivate",[]);
+var $2,$1;
+$2=smalltalk.send(self,"_isActive",[]);
+if(smalltalk.assert($2)){
+$1=smalltalk.send(self,"_handleActiveKeyDown_",[event]);
+} else {
+$1=smalltalk.send(self,"_handleInactiveKeyDown_",[event]);
 };
-return self},
+return $1;
+},
 args: ["event"],
-source: "handleKeyUp: event\x0a\x09event which = self modifierKey ifTrue: [\x0a      \x09self deactivate ]",
-messageSends: ["ifTrue:", "deactivate", "=", "modifierKey", "which"],
+source: "handleKeyDown: event\x0a\x09^ self isActive\x0a    \x09ifTrue: [ self handleActiveKeyDown: event ]\x0a      \x09ifFalse: [ self handleInactiveKeyDown: event ]",
+messageSends: ["ifTrue:ifFalse:", "handleActiveKeyDown:", "handleInactiveKeyDown:", "isActive"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
@@ -578,33 +733,6 @@ referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
 
-smalltalk.addMethod(
-"_modifierKey",
-smalltalk.method({
-selector: "modifierKey",
-category: 'accessing',
-fn: function (){
-var self=this;
-var $2,$1;
-if(($receiver = self["@modifierKey"]) == nil || $receiver == undefined){
-$2=smalltalk.send(self["@modifierKey"],"__eq",[smalltalk.send(smalltalk.send(navigator,"_platform",[]),"_match_",["Mac"])]);
-if(smalltalk.assert($2)){
-$1=(91);
-} else {
-$1=(17);
-};
-} else {
-$1=self["@modifierKey"];
-};
-return $1;
-},
-args: [],
-source: "modifierKey\x0a\x09^ modifierKey ifNil: [\x0a\x09\x09modifierKey = (navigator platform match: 'Mac')\x0a\x09\x09\x09ifTrue: [ 91 ]\x0a\x09\x09\x09ifFalse: [ 17 ] ]",
-messageSends: ["ifNil:", "ifTrue:ifFalse:", "=", "match:", "platform"],
-referencedClasses: []
-}),
-smalltalk.HLKeyBinder);
-
 smalltalk.addMethod(
 "_selectedBinding",
 smalltalk.method({
@@ -637,13 +765,28 @@ var self=this;
 smalltalk.send(smalltalk.send(window,"_jQuery_",["body"]),"_keydown_",[(function(event){
 return smalltalk.send(self,"_handleKeyDown_",[event]);
 })]);
-smalltalk.send(smalltalk.send(window,"_jQuery_",["body"]),"_keyup_",[(function(event){
-return smalltalk.send(self,"_handleKeyUp_",[event]);
-})]);
 return self},
 args: [],
-source: "setupEvents\x0a\x09(window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ].\x0a    (window jQuery: 'body') keyup: [ :event | self handleKeyUp: event ]",
-messageSends: ["keydown:", "handleKeyDown:", "jQuery:", "keyup:", "handleKeyUp:"],
+source: "setupEvents\x0a\x09(window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ]",
+messageSends: ["keydown:", "handleKeyDown:", "jQuery:"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder);
+
+smalltalk.addMethod(
+"_systemIsMac",
+smalltalk.method({
+selector: "systemIsMac",
+category: 'testing',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(navigator,"_platform",[]),"_match_",["Mac"]);
+return $1;
+},
+args: [],
+source: "systemIsMac\x0a\x09^ navigator platform match: 'Mac'",
+messageSends: ["match:", "platform"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinder);
@@ -658,11 +801,11 @@ selector: "hide",
 category: 'actions',
 fn: function (){
 var self=this;
-smalltalk.send(smalltalk.send(window,"_jQuery_",[".key_helper"]),"_remove",[]);
+smalltalk.send(smalltalk.send(self["@rootDiv"],"_asJQuery",[]),"_remove",[]);
 return self},
 args: [],
-source: "hide\x0a\x09(window jQuery: '.key_helper') remove",
-messageSends: ["remove", "jQuery:"],
+source: "hide\x0a\x09rootDiv asJQuery remove",
+messageSends: ["remove", "asJQuery"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
@@ -715,14 +858,16 @@ referencedClasses: []
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
-"_renderBindingsOn_",
+"_renderBindingGroup_on_",
 smalltalk.method({
-selector: "renderBindingsOn:",
+selector: "renderBindingGroup:on:",
 category: 'rendering',
-fn: function (html){
+fn: function (aBindingGroup,html){
 var self=this;
 var $1,$3,$4,$5,$6,$2;
-smalltalk.send(smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_bindings",[]),"_do_",[(function(each){
+smalltalk.send(smalltalk.send(smalltalk.send(aBindingGroup,"_bindings",[]),"_sorted_",[(function(a,b){
+return smalltalk.send(smalltalk.send(a,"_key",[]),"__lt",[smalltalk.send(b,"_key",[])]);
+})]),"_do_",[(function(each){
 $1=smalltalk.send(html,"_span",[]);
 smalltalk.send($1,"_class_",["command"]);
 $2=smalltalk.send($1,"_with_",[(function(){
@@ -730,17 +875,36 @@ $3=smalltalk.send(html,"_span",[]);
 smalltalk.send($3,"_class_",["label"]);
 $4=smalltalk.send($3,"_with_",[smalltalk.send(smalltalk.send(each,"_shortcut",[]),"_asLowercase",[])]);
 $4;
-$5=smalltalk.send(html,"_span",[]);
+$5=smalltalk.send(html,"_a",[]);
 smalltalk.send($5,"_class_",["action"]);
-$6=smalltalk.send($5,"_with_",[smalltalk.send(each,"_label",[])]);
+smalltalk.send($5,"_with_",[smalltalk.send(each,"_label",[])]);
+$6=smalltalk.send($5,"_onClick_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_keyBinder",[]),"_applyBinding_",[each]);
+})]);
 return $6;
 })]);
 return $2;
 })]);
 return self},
+args: ["aBindingGroup", "html"],
+source: "renderBindingGroup: aBindingGroup on: html\x0a\x09(aBindingGroup bindings \x0a    \x09sorted: [ :a :b | a key < b key ])\x0a        do: [ :each |\x0a\x09\x09\x09html span class: 'command'; with: [\x0a\x09\x09\x09\x09html span class: 'label'; with: each shortcut asLowercase.\x0a  \x09\x09\x09\x09html a \x0a                \x09class: 'action'; \x0a                    with: each label;\x0a  \x09\x09\x09\x09\x09onClick: [ self keyBinder applyBinding: each ] ] ]",
+messageSends: ["do:", "class:", "span", "with:", "asLowercase", "shortcut", "a", "label", "onClick:", "applyBinding:", "keyBinder", "sorted:", "<", "key", "bindings"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinderHelper);
+
+smalltalk.addMethod(
+"_renderBindingOn_",
+smalltalk.method({
+selector: "renderBindingOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_renderOn_html_",[self,html]);
+return self},
 args: ["html"],
-source: "renderBindingsOn: html\x0a\x09self selectedBinding bindings do: [ :each |\x0a\x09\x09html span class: 'command'; with: [\x0a\x09\x09\x09html span class: 'label'; with: each shortcut asLowercase.\x0a  \x09\x09\x09html span class: 'action'; with: each label ] ]",
-messageSends: ["do:", "class:", "span", "with:", "asLowercase", "shortcut", "label", "bindings", "selectedBinding"],
+source: "renderBindingOn: html\x0a\x09self selectedBinding renderOn: self html: html",
+messageSends: ["renderOn:html:", "selectedBinding"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
@@ -752,16 +916,43 @@ selector: "renderContentOn:",
 category: 'rendering',
 fn: function (html){
 var self=this;
-var $1,$2;
+var $1,$3,$2;
 $1=smalltalk.send(html,"_div",[]);
 smalltalk.send($1,"_class_",["key_helper"]);
 $2=smalltalk.send($1,"_with_",[(function(){
-return smalltalk.send(self,"_renderBindingsOn_",[html]);
+smalltalk.send(self,"_renderSelectionOn_",[html]);
+$3=smalltalk.send(self,"_renderBindingOn_",[html]);
+return $3;
 })]);
 return self},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html div class: 'key_helper'; with: [\x0a      \x09self renderBindingsOn: html ]",
-messageSends: ["class:", "div", "with:", "renderBindingsOn:"],
+source: "renderContentOn: html\x0a\x09html div class: 'key_helper'; with: [\x0a      \x09self \x0a        \x09renderSelectionOn:html;\x0a          \x09renderBindingOn: html ]",
+messageSends: ["class:", "div", "with:", "renderSelectionOn:", "renderBindingOn:"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinderHelper);
+
+smalltalk.addMethod(
+"_renderSelectionOn_",
+smalltalk.method({
+selector: "renderSelectionOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+var $1,$4,$3,$2;
+$1=smalltalk.send(html,"_span",[]);
+smalltalk.send($1,"_class_",["selected"]);
+$4=smalltalk.send(smalltalk.send(self,"_selectedBinding",[]),"_label",[]);
+if(($receiver = $4) == nil || $receiver == undefined){
+$3="Action";
+} else {
+$3=$4;
+};
+$2=smalltalk.send($1,"_with_",[$3]);
+return self},
+args: ["html"],
+source: "renderSelectionOn: html\x0a\x09\x09html span \x0a        \x09class: 'selected'; \x0a            with: (self selectedBinding label ifNil: [ 'Action' ])",
+messageSends: ["class:", "span", "with:", "ifNil:", "label", "selectedBinding"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);

+ 39 - 9
st/Helios-Browser.st

@@ -26,7 +26,8 @@ model: aModel
 registerBindingsOn: aBindingGroup
 	aBindingGroup 
     	addGroupKey: 66 labelled: 'Browse';
-        addGroupKey: 71 labelled: 'Go to'
+        addGroupKey: 71 labelled: 'Go to';
+        addGroupKey: 84 labelled: 'Toggle'
 ! !
 
 !HLBrowser methodsFor: 'rendering'!
@@ -158,6 +159,10 @@ iconForItem: aClass
 	^ aClass theNonMetaClass comment isEmpty
     	ifFalse: [ 'icon-none' ]
       	ifTrue: [ 'icon-question-sign' ]
+!
+
+showInstance
+	^ self model showInstance
 ! !
 
 !HLClassesListWidget methodsFor: 'actions'!
@@ -187,15 +192,26 @@ selectItem: aClass
 !
 
 showInstance: aBoolean
-	aBoolean = self browser showInstance ifFalse: [
-		self browser showInstance: aBoolean ]
+	self model showInstance: aBoolean
 ! !
 
 !HLClassesListWidget methodsFor: 'announcements'!
 
 subscribeTo: anAnnouncer
 	anAnnouncer on: HLPackageSelected do: [ :ann |
-    	self packageSelected: ann item ]
+    	self packageSelected: ann item ].
+    anAnnouncer on: HLShowInstanceToggled do: [ :ann |
+    	self refresh ]
+! !
+
+!HLClassesListWidget methodsFor: 'keybindings'!
+
+registerBindingsOn: aBindingGroup
+	(aBindingGroup at: 'Go to') 
+    	addActionKey: 67 labelled: 'Classes' callback: [ self focus ].
+    (aBindingGroup at: 'Toggle') 
+    	addActionKey: 73 labelled: 'Instance side' callback: [ self showInstance: true ];
+        addActionKey: 67 labelled: 'Class side' callback: [  self showInstance: false ]
 ! !
 
 !HLClassesListWidget methodsFor: 'rendering'!
@@ -208,10 +224,10 @@ renderButtonsOn: html
            	html button 
                 class: (String streamContents: [ :str |
                 	str nextPutAll: 'btn'.
-                    self model showInstance ifTrue: [ 
+                    self showInstance ifTrue: [ 
                     	str nextPutAll: ' active'] ]);
   				with: 'Instance';
-                onClick: [ self model showInstance: true ].
+                onClick: [ self showInstance: true ].
   			html button
   				class: (String streamContents: [ :str |
                 	str nextPutAll: 'btn'.
@@ -360,6 +376,13 @@ initialize
     self flushSelectorsCache
 ! !
 
+!HLMethodsListWidget methodsFor: 'keybindings'!
+
+registerBindingsOn: aBindingGroup
+	(aBindingGroup at: 'Go to') 
+    	addActionKey: 77 labelled: 'Methods' callback: [ self focus ]
+! !
+
 !HLMethodsListWidget methodsFor: 'rendering'!
 
 renderContentOn: html
@@ -413,14 +436,14 @@ selectItem: aPackage
 
 registerBindingsOn: aBindingGroup
 	(aBindingGroup at: 'Go to') 
-    	addActionKey: 67 labelled: 'Packages' callback: [ self focus ]
+    	addActionKey: 80 labelled: 'Packages' callback: [ self focus ]
 ! !
 
 !HLPackagesListWidget methodsFor: 'rendering'!
 
 renderButtonsOn: html
 
-	html span class: 'info'; with: 'Auto commit is'.
+	html span class: 'info'; with: 'Auto commit'.
 	html div 
         class: 'btn-group switch';
 		at: 'data-toggle' put: 'buttons-radio';
@@ -436,7 +459,7 @@ renderButtonsOn: html
                 
     html a 
          	class: 'btn';
-			with: 'Commit now'.
+			with: 'Commit'.
 ! !
 
 HLBrowserListWidget subclass: #HLProtocolsListWidget
@@ -482,6 +505,13 @@ subscribeTo: anAnnouncer
     	self classSelected: self model selectedClass ]
 ! !
 
+!HLProtocolsListWidget methodsFor: 'keybindings'!
+
+registerBindingsOn: aBindingGroup
+	(aBindingGroup at: 'Go to') 
+    	addActionKey: 84 labelled: 'Protocols' callback: [ self focus ]
+! !
+
 !HLProtocolsListWidget methodsFor: 'rendering'!
 
 renderContentOn: html

+ 3 - 2
st/Helios-Core.st

@@ -456,7 +456,7 @@ next
 
 next: aWidget
 	next := aWidget.
-    aWidget previous: self
+    aWidget previous = self ifFalse: [ aWidget previous: self ]
 !
 
 previous
@@ -464,7 +464,8 @@ previous
 !
 
 previous: aWidget
-	previous := aWidget
+	previous := aWidget.
+    aWidget next = self ifFalse: [ aWidget next: self ]
 ! !
 
 !HLNavigationListWidget methodsFor: 'actions'!

+ 105 - 38
st/Helios-KeyBindings.st

@@ -25,6 +25,17 @@ shortcut
 	^ String fromCharCode: self key
 ! !
 
+!HLBinding methodsFor: 'actions'!
+
+applyOn: aKeyBinder
+	self subclassResponsibility
+! !
+
+!HLBinding methodsFor: 'rendering'!
+
+renderOn: aBindingHelper html: html
+! !
+
 !HLBinding methodsFor: 'testing'!
 
 isBindingAction
@@ -58,6 +69,12 @@ callback: aBlock
 	callback := aBlock
 ! !
 
+!HLBindingAction methodsFor: 'actions'!
+
+applyOn: aKeyBinder
+	aKeyBinder applyBindingAction: self
+! !
+
 !HLBindingAction methodsFor: 'testing'!
 
 isBindingAction
@@ -90,7 +107,7 @@ at: aString
       	ifNone: [ nil ]
 !
 
-atkey: anInteger
+atKey: anInteger
 	^ self bindings 
     	detect: [ :each | each key = anInteger ]
       	ifNone: [ nil ]
@@ -100,6 +117,18 @@ bindings
 	^ bindings ifNil: [ bindings := OrderedCollection new ]
 ! !
 
+!HLBindingGroup methodsFor: 'actions'!
+
+applyOn: aKeyBinder
+	aKeyBinder applyBindingGroup: self
+! !
+
+!HLBindingGroup methodsFor: 'rendering'!
+
+renderOn: aBindingHelper html: html
+	aBindingHelper renderBindingGroup: self on: html
+! !
+
 !HLBindingGroup methodsFor: 'testing'!
 
 isBindingGroup
@@ -112,19 +141,22 @@ Object subclass: #HLKeyBinder
 
 !HLKeyBinder methodsFor: 'accessing'!
 
+activationKey
+	"SPACE"
+	^ 32
+!
+
 bindings
 	^ bindings ifNil: [ bindings := HLBindingGroup new ]
 !
 
-helper
-	^ helper ifNil: [ helper := HLKeyBinderHelper on: self ]
+escapeKey
+	"ESC"
+	^ 27
 !
 
-modifierKey
-	^ modifierKey ifNil: [
-		modifierKey = (navigator platform match: 'Mac')
-			ifTrue: [ 91 ]
-			ifFalse: [ 17 ] ]
+helper
+	^ helper ifNil: [ helper := HLKeyBinderHelper on: self ]
 !
 
 selectedBinding
@@ -139,13 +171,17 @@ activate
 !
 
 applyBinding: aBinding
-    aBinding isBindingGroup
-    	ifTrue: [
-			selectedBinding := aBinding.
-    		self helper refresh ]
-        ifFalse: [ 
-			aBinding callback value.
-			self deactivate ]
+    aBinding applyOn: self
+!
+
+applyBindingAction: aBinding
+    aBinding callback value.
+	self deactivate
+!
+
+applyBindingGroup: aBinding
+    selectedBinding := aBinding.
+    self helper refresh
 !
 
 deactivate
@@ -161,6 +197,20 @@ flushBindings
 
 !HLKeyBinder methodsFor: 'events'!
 
+handleActiveKeyDown: event
+
+	"ESC or ctrl+g deactivate the keyBinder"
+	(event which = self escapeKey or: [
+		event which = 71 and: [ event ctrlKey ] ])
+        	ifTrue: [ 
+            	self deactivate.
+				event preventDefault.
+				^ false ].
+            
+    "Handle the keybinding"
+    ^ self handleBindingFor: event
+!
+
 handleBindingFor: anEvent
 	| binding |
     binding := self selectedBinding atKey: anEvent which.
@@ -171,28 +221,24 @@ handleBindingFor: anEvent
 		^ false ]
 !
 
-handleBindingKey: anInteger
+handleInactiveKeyDown: event
+	event which = self activationKey ifTrue: [
+          (self systemIsMac
+                ifTrue: [ event metaKey ]
+                  ifFalse: [  event ctrlKey ])  ifTrue: [
+					self activate. 
+               		 event preventDefault. 
+                	^ false ] ]
 !
 
 handleKeyDown: event
-	self isActive
-    	ifTrue: [ 
-        	self handleBindingKey: event which ]
-      	ifFalse: [
-          	event which = self modifierKey ifTrue: [
-				self activate. 
-                event preventDefault. 
-                ^ false ] ]
-!
-
-handleKeyUp: event
-	event which = self modifierKey ifTrue: [
-      	self deactivate ]
+	^ self isActive
+    	ifTrue: [ self handleActiveKeyDown: event ]
+      	ifFalse: [ self handleInactiveKeyDown: event ]
 !
 
 setupEvents
-	(window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ].
-    (window jQuery: 'body') keyup: [ :event | self handleKeyUp: event ]
+	(window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ]
 ! !
 
 !HLKeyBinder methodsFor: 'initialization'!
@@ -206,6 +252,10 @@ initialize
 
 isActive
 	^ active ifNil: [ false ]
+!
+
+systemIsMac
+	^ navigator platform match: 'Mac'
 ! !
 
 HLWidget subclass: #HLKeyBinderHelper
@@ -229,7 +279,7 @@ selectedBinding
 !HLKeyBinderHelper methodsFor: 'actions'!
 
 hide
-	(window jQuery: '.key_helper') remove
+	rootDiv asJQuery remove
 !
 
 show
@@ -244,16 +294,33 @@ registerBindings
 
 !HLKeyBinderHelper methodsFor: 'rendering'!
 
-renderBindingsOn: html
-	self selectedBinding bindings do: [ :each |
-		html span class: 'command'; with: [
-			html span class: 'label'; with: each shortcut asLowercase.
-  			html span class: 'action'; with: each label ] ]
+renderBindingGroup: aBindingGroup on: html
+	(aBindingGroup bindings 
+    	sorted: [ :a :b | a key < b key ])
+        do: [ :each |
+			html span class: 'command'; with: [
+				html span class: 'label'; with: each shortcut asLowercase.
+  				html a 
+                	class: 'action'; 
+                    with: each label;
+  					onClick: [ self keyBinder applyBinding: each ] ] ]
+!
+
+renderBindingOn: html
+	self selectedBinding renderOn: self html: html
 !
 
 renderContentOn: html
 	html div class: 'key_helper'; with: [
-      	self renderBindingsOn: html ]
+      	self 
+        	renderSelectionOn:html;
+          	renderBindingOn: html ]
+!
+
+renderSelectionOn: html
+		html span 
+        	class: 'selected'; 
+            with: (self selectedBinding label ifNil: [ 'Action' ])
 ! !
 
 !HLKeyBinderHelper class methodsFor: 'instance creation'!