Hi,

PFA patch to add keyboard navigation in Debugger module via
Tab/Shift-Tab key.
RM#2897

Also fixed the issue where user was not able to update values in variable's
panel while debugging.
RM#2981

Currrently we have execution related shortcuts using accesskey,
Shortcuts (Execution related)
----------------------------------
<accesskey> + i  = Step in
<accesskey> + o = Step over
<accesskey> + c = Continue/Restart
<accesskey> + t = Toggle breakpoint
<accesskey> + x = Clear all breakpoints
<accesskey> + s = Stop

Shortcuts (Panel navigation related)
----------------------------------
Alt + Shift + Right Arrow
Alt + Shift + Left Arrow

Edit/Enter values in Grid (Parameter & Local variables panel's)
-------------------------------------------------------------
Alt + Shift + g

Please review.

*Note:* As of now inner panel's are not getting focused on Tab/Shift-Tab
keys but once RM#2895 <https://redmine.postgresql.org/issues/2895> patch
gets committed it will start working automatically as it's inherited code
which will add tabindex tag automatically on each newly created wcDocker
panel.

--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js 
b/web/pgadmin/static/js/keyboard_shortcuts.js
new file mode 100644
index 0000000..c4a1c5c
--- /dev/null
+++ b/web/pgadmin/static/js/keyboard_shortcuts.js
@@ -0,0 +1,114 @@
+const EDIT_KEY = 71,  // Key: G -> Grid values
+  LEFT_ARROW_KEY = 37,
+  RIGHT_ARROW_KEY = 39;
+
+function isMac() {
+  return window.navigator.platform.search('Mac') != -1;
+}
+
+function isKeyCtrlAlt(event) {
+  return event.ctrlKey || event.altKey;
+}
+
+function isKeyAltShift(event) {
+  return event.altKey || event.shiftKey;
+}
+
+function isKeyCtrlShift(event) {
+  return event.ctrlKey || event.shiftKey;
+}
+
+function isKeyCtrlAltShift(event) {
+  return event.ctrlKey || event.altKey || event.shiftKey;
+}
+
+function isAltShiftBoth(event) {
+  return event.altKey && event.shiftKey && !event.ctrlKey;
+}
+
+function isCtrlShiftBoth(event) {
+  return event.ctrlKey && event.shiftKey && !event.altKey;
+}
+
+function isCtrlAltBoth(event) {
+  return event.ctrlKey && event.altKey && !event.shiftKey;
+}
+
+function _stopEventPropagation(event) {
+  event.cancelBubble = true;
+  event.preventDefault();
+  event.stopPropagation();
+  event.stopImmediatePropagation();
+}
+
+/* Debugger: Keyboard Shortcuts handling */
+function keyboardShortcutsDebugger(debuggerController, trans_id, $el, event) {
+  let keyCode = event.which || event.keyCode;
+
+  // To handle debugger's internal tab navigation like Parameters/Messages...
+  if (this.isAltShiftBoth(event)) {
+    // Get the active wcDocker panel from DOM element
+    let panel_id;
+    switch(keyCode) {
+      case LEFT_ARROW_KEY:
+          this._stopEventPropagation(event);
+          panel_id = this.getInnerPanel($el, 'left');
+          break;
+      case RIGHT_ARROW_KEY:
+          this._stopEventPropagation(event);
+          panel_id = this.getInnerPanel($el, 'right');
+          break;
+      case EDIT_KEY:
+          this._stopEventPropagation(event);
+          let panel_content = $el.find(
+            'div.wcPanelTabContent:not(".wcPanelTabContentHidden")'
+          );
+          if(panel_content.length) {
+            let $input = $(panel_content).find('td.editable:first');
+            if($input.length)
+              $input.click();
+          }
+          break;
+    }
+    // Actual panel starts with 1 in wcDocker
+    return panel_id;
+  }
+}
+
+// Finds the desired panel on which user wants to navigate to
+function getInnerPanel($el, direction) {
+  let total_panels = $el.find('.wcPanelTab');
+  // If no panels found OR if single panel
+  if (!total_panels.length || total_panels.length == 1)
+    return;
+
+  let active_panel = $(total_panels).filter('.wcPanelTabActive'),
+    id = parseInt($(active_panel).attr('id')),
+    fist_panel = 0,
+    last_panel = total_panels.length - 1;
+
+  // Find desired panel
+  if (direction == 'left') {
+    if(id > fist_panel)
+      id--;
+  } else {
+    if (id < last_panel)
+      id++;
+  }
+  return id;
+}
+
+module.exports = {
+  processEventDebugger: keyboardShortcutsDebugger,
+  getInnerPanel: getInnerPanel,
+  // misc functions
+  _stopEventPropagation: _stopEventPropagation,
+  isMac: isMac,
+  isKeyCtrlAlt: isKeyCtrlAlt,
+  isKeyAltShift: isKeyAltShift,
+  isKeyCtrlShift: isKeyCtrlShift,
+  isKeyCtrlAltShift: isKeyCtrlAltShift,
+  isAltShiftBoth: isAltShiftBoth,
+  isCtrlShiftBoth: isCtrlShiftBoth,
+  isCtrlAltBoth: isCtrlAltBoth,
+};
diff --git a/web/pgadmin/tools/debugger/__init__.py 
b/web/pgadmin/tools/debugger/__init__.py
index a173c8e..099adb4 100644
--- a/web/pgadmin/tools/debugger/__init__.py
+++ b/web/pgadmin/tools/debugger/__init__.py
@@ -17,6 +17,8 @@ import random
 from flask import url_for, Response, render_template, request, session, 
current_app
 from flask_babel import gettext
 from flask_security import login_required
+from werkzeug.useragents import UserAgent
+
 from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import bad_request
 from pgadmin.utils.ajax import make_json_response, \
@@ -346,6 +348,9 @@ def direct_new(trans_id):
     if "linux" in _platform:
         is_linux_platform = True
 
+    # We need client OS information to render correct Keyboard shortcuts
+    user_agent = UserAgent(request.headers.get('User-Agent'))
+
     return render_template(
         "debugger/direct.html",
         _=gettext,
@@ -354,6 +359,7 @@ def direct_new(trans_id):
         debug_type=debug_type,
         is_desktop_mode=current_app.PGADMIN_RUNTIME,
         is_linux=is_linux_platform,
+        client_platform=user_agent.platform,
         stylesheets=[url_for('debugger.static', filename='css/debugger.css')]
     )
 
diff --git a/web/pgadmin/tools/debugger/static/js/debugger_ui.js 
b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
index 3a35ceb..f9049d8 100644
--- a/web/pgadmin/tools/debugger/static/js/debugger_ui.js
+++ b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
@@ -132,7 +132,8 @@ define([
             // Variables to store the data sent from sqlite database
             var func_args_data = this.func_args_data = [];
 
-            // As we are not getting pgBrowser.tree when we debug again so 
tree info will be updated from the server data
+            // As we are not getting pgBrowser.tree when we debug again
+            // so tree info will be updated from the server data
             if (restart_debug == 0) {
               var t = pgBrowser.tree,
                 i = t.selected(),
@@ -501,7 +502,8 @@ define([
               }
             }
 
-            // Check if the arguments already available in the sqlite database 
then we should use the existing arguments
+            // Check if the arguments already available in the sqlite database
+            // then we should use the existing arguments
             if (func_args_data.length == 0) {
               this.debuggerInputArgsColl =
                 new DebuggerInputArgCollections(my_obj);
@@ -537,12 +539,12 @@ define([
           setup: function() {
             return {
               buttons: [{
-                text: 'Debug',
+                text: gettext('Debug'),
                 key: 13,
                 className: 'btn btn-primary',
               },
               {
-                text: 'Cancel',
+                text: gettext('Cancel'),
                 key: 27,
                 className: 'btn btn-primary',
               },
@@ -563,13 +565,14 @@ define([
           },
           // Callback functions when click on the buttons of the Alertify 
dialogs
           callback: function(e) {
-            if (e.button.text === 'Debug') {
+            if (e.button.text === gettext('Debug')) {
 
               // Initialize the target once the debug button is clicked and
               // create asynchronous connection and unique transaction ID
               var self = this;
 
-              // If the debugging is started again then treeInfo is already 
stored in this.data so we can use the same.
+              // If the debugging is started again then treeInfo is already
+              // stored in this.data so we can use the same.
               if (self.restart_debug == 0) {
                 var t = pgBrowser.tree,
                   i = t.selected(),
@@ -791,7 +794,8 @@ define([
                   },
                 });
               } else {
-                // If the debugging is started again then we should only set 
the arguments and start the listener again
+                // If the debugging is started again then we should only set 
the
+                // arguments and start the listener again
                 baseUrl = url_for('debugger.start_listener', {
                   'trans_id': self.data.trans_id,
                 });
@@ -838,7 +842,7 @@ define([
               return true;
             }
 
-            if (e.button.text === 'Cancel') {
+            if (e.button.text === gettext('Cancel')) {
               //close the dialog...
               return false;
             }
@@ -853,8 +857,8 @@ define([
             );
 
             /*
-             If we already have data available in sqlite database then we 
should enable the debug button otherwise
-             disable the debug button.
+             If we already have data available in sqlite database then we 
should
+             enable the debug button otherwise disable the debug button.
             */
             if (this.func_args_data.length == 0) {
               this.__internal.buttons[0].element.disabled = true;
@@ -875,7 +879,8 @@ define([
 
                   for (var i = 0; i < this.collection.length; i++) {
 
-                    // TODO: Need to check the "NULL" and "Expression" column 
value to enable/disable the "Debug" button
+                    // TODO: Need to check the "NULL" and "Expression" column 
value to
+                    // enable/disable the "Debug" button
                     if (this.collection.models[i].get('value') == '' ||
                       this.collection.models[i].get('value') == null ||
                       this.collection.models[i].get('value') == undefined) {
@@ -899,9 +904,11 @@ define([
       });
     }
 
-    Alertify.debuggerInputArgsDialog('Debugger', args, 
restart_debug).resizeTo('60%', '60%');
+    Alertify.debuggerInputArgsDialog(
+      gettext('Debugger'), args, restart_debug
+    ).resizeTo('60%', '60%');
 
   };
 
   return res;
-});
\ No newline at end of file
+});
diff --git a/web/pgadmin/tools/debugger/static/js/direct.js 
b/web/pgadmin/tools/debugger/static/js/direct.js
index d0dbad7..0796d54 100644
--- a/web/pgadmin/tools/debugger/static/js/direct.js
+++ b/web/pgadmin/tools/debugger/static/js/direct.js
@@ -2,10 +2,10 @@ define([
   'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
   'pgadmin.alertifyjs', 'sources/pgadmin', 'pgadmin.browser', 'backbone',
   'pgadmin.backgrid', 'pgadmin.backform', 'sources/../bundle/codemirror',
-  'pgadmin.tools.debugger.ui', 'wcdocker',
+  'pgadmin.tools.debugger.ui', 'sources/keyboard_shortcuts', 'wcdocker'
 ], function(
   gettext, url_for, $, _, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
-  Backform, codemirror, debug_function_again
+  Backform, codemirror, debug_function_again, keyboardShortcuts
 ) {
 
   var CodeMirror = codemirror.default,
@@ -31,7 +31,8 @@ define([
 
       /*
         Function to set the breakpoint and send the line no. which is set to 
server
-        trans_id :- Unique Transaction ID, line_no - line no. to set the 
breakpoint, set_type = 0 - clear , 1 - set
+        trans_id :- Unique Transaction ID, line_no - line no. to set the 
breakpoint,
+        set_type = 0 - clear , 1 - set
       */
       set_breakpoint: function(trans_id, line_no, set_type) {
         // Make ajax call to set/clear the break point by user
@@ -57,7 +58,8 @@ define([
         });
       },
 
-      // Function to get the latest breakpoint information and update the 
gutters of codemirror
+      // Function to get the latest breakpoint information and update the
+      // gutters of codemirror
       UpdateBreakpoint: function(trans_id) {
         var self = this;
 
@@ -223,7 +225,8 @@ define([
               // Call function to create and update local variables
               self.AddLocalVariables(res.data.result);
               self.AddParameters(res.data.result);
-              // If debug function is restarted then again start listener to 
read the updated messages.
+              // If debug function is restarted then again start listener to
+              // read the updated messages.
               if (pgTools.DirectDebug.debug_restarted) {
                 if (pgTools.DirectDebug.debug_type) {
                   self.poll_end_execution_result(trans_id);
@@ -281,8 +284,8 @@ define([
       },
 
       /*
-        poll the actual result after user has executed the "continue", 
"step-into", "step-over" actions and get the
-        other updated information from the server.
+        poll the actual result after user has executed the "continue", 
"step-into",
+        "step-over" actions and get the other updated information from the 
server.
       */
       poll_result: function(trans_id) {
         var self = this;
@@ -299,8 +302,9 @@ define([
           poll_timeout;
 
         /*
-          During the execution we should poll the result in minimum seconds 
but once the execution is completed
-          and wait for the another debugging session then we should decrease 
the polling frequency.
+          During the execution we should poll the result in minimum seconds but
+          once the execution is completed and wait for the another debugging
+          session then we should decrease the polling frequency.
         */
         if (pgTools.DirectDebug.polling_timeout_idle) {
           // Poll the result after 1 second
@@ -333,8 +337,13 @@ define([
                       pgTools.DirectDebug.docker.finishLoading(50);
                       
pgTools.DirectDebug.editor.setValue(res.data.result[0].src);
                       self.UpdateBreakpoint(trans_id);
-                      
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
-                      
pgTools.DirectDebug.editor.addLineClass((res.data.result[0].linenumber - 2), 
'wrap', 'CodeMirror-activeline-background');
+                      pgTools.DirectDebug.editor.removeLineClass(
+                        self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                      );
+                      pgTools.DirectDebug.editor.addLineClass(
+                        (res.data.result[0].linenumber - 2),
+                        'wrap', 'CodeMirror-activeline-background'
+                      );
                       self.active_line_no = (res.data.result[0].linenumber - 
2);
 
                       // Update the stack, local variables and parameters 
information
@@ -343,7 +352,9 @@ define([
                     } else if (!pgTools.DirectDebug.debug_type && 
!pgTools.DirectDebug.first_time_indirect_debug) {
                       pgTools.DirectDebug.docker.finishLoading(50);
                       if (self.active_line_no != undefined) {
-                        
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
+                        pgTools.DirectDebug.editor.removeLineClass(
+                          self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                        );
                       }
                       self.clear_all_breakpoint(trans_id);
                       self.execute_query(trans_id);
@@ -358,8 +369,13 @@ define([
                         self.UpdateBreakpoint(trans_id);
                       }
 
-                      
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
-                      
pgTools.DirectDebug.editor.addLineClass((res.data.result[0].linenumber - 2), 
'wrap', 'CodeMirror-activeline-background');
+                      pgTools.DirectDebug.editor.removeLineClass(
+                        self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                      );
+                      pgTools.DirectDebug.editor.addLineClass(
+                        (res.data.result[0].linenumber - 2),
+                        'wrap', 'CodeMirror-activeline-background'
+                      );
                       self.active_line_no = (res.data.result[0].linenumber - 
2);
 
                       // Update the stack, local variables and parameters 
information
@@ -378,7 +394,9 @@ define([
                   pgTools.DirectDebug.polling_timeout_idle = true;
                   // If status is Busy then poll the result by recursive call 
to the poll function
                   if (!pgTools.DirectDebug.debug_type) {
-                    pgTools.DirectDebug.docker.startLoading(gettext('Waiting 
for another session to invoke the target...'));
+                    pgTools.DirectDebug.docker.startLoading(
+                      gettext('Waiting for another session to invoke the 
target...')
+                    );
 
                     // As we are waiting for another session to invoke the 
target,disable all the buttons
                     self.enable('stop', false);
@@ -429,8 +447,9 @@ define([
       },
 
       /*
-        For the direct debugging, we need to check weather the functions 
execution is completed or not. After completion
-        of the debugging, we will stop polling the result  until new execution 
starts.
+        For the direct debugging, we need to check weather the functions 
execution
+        is completed or not. After completion of the debugging, we will stop 
polling
+        the result  until new execution starts.
       */
       poll_end_execution_result: function(trans_id) {
         var self = this;
@@ -470,10 +489,13 @@ define([
                 if (res.data.status === 'Success') {
                   if (res.data.result == undefined) {
                     /*
-                     "result" is undefined only in case of EDB procedure. As 
Once the EDB procedure execution is completed
-                     then we are not getting any result so we need ignore the 
result.
+                     "result" is undefined only in case of EDB procedure.
+                     As Once the EDB procedure execution is completed then we 
are
+                     not getting any result so we need ignore the result.
                     */
-                    
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
+                    pgTools.DirectDebug.editor.removeLineClass(
+                      self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                    );
                     pgTools.DirectDebug.direct_execution_completed = true;
                     pgTools.DirectDebug.polling_timeout_idle = true;
 
@@ -488,7 +510,8 @@ define([
                     // remove progress cursor
                     $('.debugger-container').removeClass('show_progress');
 
-                    // Execution completed so disable the buttons other than 
"Continue/Start" button because user can still
+                    // Execution completed so disable the buttons other than
+                    // "Continue/Start" button because user can still
                     // start the same execution again.
                     self.enable('stop', false);
                     self.enable('step_over', false);
@@ -501,7 +524,9 @@ define([
                   } else {
                     // Call function to create and update local variables ....
                     if (res.data.result != null) {
-                      
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
+                      pgTools.DirectDebug.editor.removeLineClass(
+                        self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                      );
                       self.AddResults(res.data.col_info, res.data.result);
                       pgTools.DirectDebug.results_panel.focus();
                       pgTools.DirectDebug.direct_execution_completed = true;
@@ -518,7 +543,8 @@ define([
                       // remove progress cursor
                       $('.debugger-container').removeClass('show_progress');
 
-                      // Execution completed so disable the buttons other than 
"Continue/Start" button because user can still
+                      // Execution completed so disable the buttons other than
+                      // "Continue/Start" button because user can still
                       // start the same execution again.
                       self.enable('stop', false);
                       self.enable('step_over', false);
@@ -532,7 +558,8 @@ define([
                     }
                   }
                 } else if (res.data.status === 'Busy') {
-                  // If status is Busy then poll the result by recursive call 
to the poll function
+                  // If status is Busy then poll the result by recursive call 
to
+                  // the poll function
                   self.poll_end_execution_result(trans_id);
                   // Update the message tab of the debugger
                   if (res.data.status_message) {
@@ -545,9 +572,12 @@ define([
                   );
                 } else if (res.data.status === 'ERROR') {
                   pgTools.DirectDebug.direct_execution_completed = true;
-                  
pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 'wrap', 
'CodeMirror-activeline-background');
+                  pgTools.DirectDebug.editor.removeLineClass(
+                    self.active_line_no, 'wrap', 
'CodeMirror-activeline-background'
+                  );
 
-                  //Set the Alertify message to inform the user that execution 
is completed with error.
+                  //Set the Alertify message to inform the user that execution 
is
+                  // completed with error.
                   if (!pgTools.DirectDebug.is_user_aborted_debugging) {
                     Alertify.error(res.info, 3);
                   }
@@ -625,14 +655,16 @@ define([
             }
 
             /*
-             Need to check if restart debugging really require to open the 
input dialog ?
-             If yes then we will get the previous arguments from database and 
populate the input dialog
-             If no then we should directly start the listener.
+             Need to check if restart debugging really require to open the 
input
+             dialog? If yes then we will get the previous arguments from 
database
+             and populate the input dialog, If no then we should directly 
start the
+             listener.
             */
             if (res.data.result.require_input) {
               debug_function_again(res.data.result, restart_dbg);
             } else {
-              // Debugging of void function is started again so we need to 
start the listener again
+              // Debugging of void function is started again so we need to 
start
+              // the listener again
               var baseUrl = url_for('debugger.start_listener', {
                 'trans_id': trans_id,
               });
@@ -803,7 +835,9 @@ define([
           success: function(res) {
             if (res.data.status) {
               // Call function to create and update local variables ....
-              pgTools.DirectDebug.editor.removeLineClass(self.active_line_no, 
'wrap', 'CodeMirror-activeline-background');
+              pgTools.DirectDebug.editor.removeLineClass(
+                self.active_line_no, 'wrap', 'CodeMirror-activeline-background'
+              );
               pgTools.DirectDebug.direct_execution_completed = true;
               pgTools.DirectDebug.is_user_aborted_debugging = true;
 
@@ -1099,8 +1133,10 @@ define([
         result_grid.render();
 
         // Render the result grid into result panel
-        
pgTools.DirectDebug.results_panel.$container.find('.debug_results').append(result_grid.el);
-
+        pgTools.DirectDebug.results_panel
+          .$container
+          .find('.debug_results')
+          .append(result_grid.el);
       },
 
       AddLocalVariables: function(result) {
@@ -1120,11 +1156,13 @@ define([
           },
         });
 
-        // Collection which contains the model for function informations.
+        // Collection which contains the model for function information.
         var VariablesCollection = Backbone.Collection.extend({
           model: DebuggerVariablesModel,
         });
 
+        VariablesCollection.prototype.on('change', 
self.deposit_parameter_value, self);
+
         var gridCols = [{
           name: 'name',
           label: gettext('Name'),
@@ -1170,7 +1208,10 @@ define([
         variable_grid.render();
 
         // Render the variables grid into local variables panel
-        
pgTools.DirectDebug.local_variables_panel.$container.find('.local_variables').append(variable_grid.el);
+        pgTools.DirectDebug.local_variables_panel
+          .$container
+          .find('.local_variables')
+          .append(variable_grid.el);
 
       },
 
@@ -1331,7 +1372,7 @@ define([
     controller about the click and controller will take the action for the 
specified button click.
   */
   var DebuggerToolbarView = Backbone.View.extend({
-    el: '#btn-toolbar',
+    el: '.dubugger_main_container',
     initialize: function() {
       controller.on('pgDebugger:button:state:stop', this.enable_stop, this);
       controller.on('pgDebugger:button:state:step_over', 
this.enable_step_over, this);
@@ -1347,6 +1388,7 @@ define([
       'click .btn-continue': 'on_continue',
       'click .btn-step-over': 'on_step_over',
       'click .btn-step-into': 'on_step_into',
+      'keydown': 'keyAction',
     },
     enable_stop: function(enable) {
       var $btn = this.$el.find('.btn-stop');
@@ -1414,7 +1456,6 @@ define([
         $btn.attr('disabled', 'disabled');
       }
     },
-
     on_stop: function() {
       controller.Stop(pgTools.DirectDebug.trans_id);
     },
@@ -1433,19 +1474,35 @@ define([
     on_step_into: function() {
       controller.Step_into(pgTools.DirectDebug.trans_id);
     },
+    keyAction: function (event) {
+      debugger;
+      var trans_id = pgTools.DirectDebug.trans_id,
+        $el = this.$el,
+        $input, panel_id, actual_panel, panel_content;
+
+      panel_id = keyboardShortcuts.processEventDebugger(
+        controller, trans_id, $el, event
+      );
+
+      // Panel navigation
+      if(!_.isUndefined(panel_id) && !_.isNull(panel_id)) {
+        actual_panel = panel_id + 1;
+        pgTools.DirectDebug.docker.findPanels()[actual_panel].focus();
+      }
+    },
   });
 
 
   /*
-    Function is responsible to create the new wcDocker instance for debugger 
and initialize the debugger panel inside
-    the docker instance.
+    Function is responsible to create the new wcDocker instance for debugger 
and
+    initialize the debugger panel inside the docker instance.
   */
   var DirectDebug = function() {};
 
   _.extend(DirectDebug.prototype, {
-    init: function(trans_id, debug_type) { /* We should get the transaction id 
from the server during initialization here */
+    /* We should get the transaction id from the server during initialization 
here */
+    init: function(trans_id, debug_type) {
       // We do not want to initialize the module multiple times.
-
       var self = this;
       _.bindAll(pgTools.DirectDebug, 'messages');
 
@@ -1524,7 +1581,8 @@ define([
         this.intializePanels();
     },
 
-    // Read the messages of the database server and get the port ID and attach 
the executer to that port.
+    // Read the messages of the database server and get the port ID and attach
+    // the executer to that port.
     messages: function(trans_id) {
       var self = this;
       // Make ajax call to listen the database message
@@ -1615,7 +1673,7 @@ define([
             height: '100%',
             isCloseable: false,
             isPrivate: true,
-            content: '<div id ="parameters" class="parameters"></div>',
+            content: '<div id ="parameters" class="parameters" 
tabindex="0"></div>',
           });
 
           // Create the Local variables panel to display the local variables 
of the function.
@@ -1626,7 +1684,7 @@ define([
             height: '100%',
             isCloseable: false,
             isPrivate: true,
-            content: '<div id ="local_variables" 
class="local_variables"></div>',
+            content: '<div id ="local_variables" class="local_variables" 
tabindex="0"></div>',
           });
 
           // Create the messages panel to display the message returned from 
the database server
@@ -1637,7 +1695,7 @@ define([
             height: '100%',
             isCloseable: false,
             isPrivate: true,
-            content: '<div id="messages" class="messages"></div>',
+            content: '<div id="messages" class="messages" tabindex="0"></div>',
           });
 
           // Create the result panel to display the result after debugging the 
function
@@ -1648,7 +1706,7 @@ define([
             height: '100%',
             isCloseable: false,
             isPrivate: true,
-            content: '<div id="debug_results" class="debug_results"></div>',
+            content: '<div id="debug_results" class="debug_results" 
tabindex="0"></div>',
           });
 
           // Create the stack pane panel to display the debugging stack 
information.
@@ -1659,7 +1717,7 @@ define([
             height: '100%',
             isCloseable: false,
             isPrivate: true,
-            content: '<div id="stack_pane" class="stack_pane"></div>',
+            content: '<div id="stack_pane" class="stack_pane" 
tabindex="0"></div>',
           });
 
           // Load all the created panels
@@ -1671,34 +1729,50 @@ define([
         });
 
       self.code_editor_panel = self.docker.addPanel('code', wcDocker.DOCK.TOP);
-
       self.parameters_panel = self.docker.addPanel(
-        'parameters', wcDocker.DOCK.BOTTOM, self.code_editor_panel);
-      self.local_variables_panel = self.docker.addPanel('local_variables', 
wcDocker.DOCK.STACKED, self.parameters_panel, {
+        'parameters', wcDocker.DOCK.BOTTOM, self.code_editor_panel
+      );
+      self.local_variables_panel = self.docker.addPanel(
+        'local_variables',
+        wcDocker.DOCK.STACKED,
+        self.parameters_panel, {
         tabOrientation: wcDocker.TAB.TOP,
       });
-      self.messages_panel = self.docker.addPanel('messages', 
wcDocker.DOCK.STACKED, self.parameters_panel);
+      self.messages_panel = self.docker.addPanel(
+        'messages', wcDocker.DOCK.STACKED, self.parameters_panel
+      );
       self.results_panel = self.docker.addPanel(
-        'results', wcDocker.DOCK.STACKED, self.parameters_panel);
+        'results', wcDocker.DOCK.STACKED, self.parameters_panel
+      );
       self.stack_pane_panel = self.docker.addPanel(
-        'stack_pane', wcDocker.DOCK.STACKED, self.parameters_panel);
+        'stack_pane', wcDocker.DOCK.STACKED, self.parameters_panel
+      );
 
-      var editor_pane = $('<div id="stack_editor_pane" 
class="full-container-pane info"></div>');
-      var code_editor_area = $('<textarea 
id="debugger-editor-textarea"></textarea>').append(editor_pane);
+      var editor_pane = $('<div id="stack_editor_pane" ' +
+        'class="full-container-pane info"></div>');
+      var code_editor_area = $('<textarea id="debugger-editor-textarea">' +
+        '</textarea>').append(editor_pane);
       self.code_editor_panel.layout().addItem(code_editor_area);
 
       // To show the line-number and set breakpoint marker details by user.
       self.editor = CodeMirror.fromTextArea(
         code_editor_area.get(0), {
+          tabindex: 0,
           lineNumbers: true,
           foldOptions: {
             widget: '\u2026',
           },
           foldGutter: {
-            rangeFinder: 
CodeMirror.fold.combine(CodeMirror.pgadminBeginRangeFinder, 
CodeMirror.pgadminIfRangeFinder,
-              CodeMirror.pgadminLoopRangeFinder, 
CodeMirror.pgadminCaseRangeFinder),
+            rangeFinder: CodeMirror.fold.combine(
+              CodeMirror.pgadminBeginRangeFinder,
+              CodeMirror.pgadminIfRangeFinder,
+              CodeMirror.pgadminLoopRangeFinder,
+              CodeMirror.pgadminCaseRangeFinder
+            ),
           },
-          gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 
'breakpoints'],
+          gutters: [
+            'CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'breakpoints'
+          ],
           mode: 'text/x-pgsql',
           readOnly: true,
           extraKeys: pgAdmin.Browser.editor_shortcut_keys,
@@ -1741,7 +1815,7 @@ define([
             panel.title(title);
           panel.closeable(false);
           panel.layout().addItem(
-            $('<div>', {
+            $('<div tabindex="0">', {
               'class': 'pg-debugger-panel',
             })
           );
diff --git a/web/pgadmin/tools/debugger/templates/debugger/direct.html 
b/web/pgadmin/tools/debugger/templates/debugger/direct.html
index 29bb729..0e24d49 100644
--- a/web/pgadmin/tools/debugger/templates/debugger/direct.html
+++ b/web/pgadmin/tools/debugger/templates/debugger/direct.html
@@ -35,44 +35,57 @@ try {
     .debugger-container .wcLoadingIcon.fa-pulse{-webkit-animation: none;}
 </style>
 {% endif %}
-<nav class="navbar-inverse navbar-fixed-top">
-    <div id="btn-toolbar" class="btn-toolbar pg-prop-btn-group bg-gray-2 
border-gray-3" role="toolbar" aria-label="">
-        <div class="btn-group" role="group" aria-label="">
-            <button type="button" class="btn btn-default btn-step-into" 
title="{{ _('Step into') }}"
-                    tabindex="1">
-                <i class="fa fa-indent"></i>
-            </button>
-            <button type="button" class="btn btn-default btn-step-over" 
title="{{ _('Step over') }}"
-                    tabindex="2">
-                <i class="fa fa-outdent"></i>
-            </button>
-            <button type="button" class="btn btn-default btn-continue" 
title="{{ _('Continue/Start') }}"
-                    tabindex="3">
-                <i class="fa fa-play-circle"></i>
-            </button>
+<div class="dubugger_main_container" tabindex="0">
+    <nav class="navbar-inverse navbar-fixed-top">
+        <div id="btn-toolbar" class="btn-toolbar pg-prop-btn-group bg-gray-2 
border-gray-3" role="toolbar" aria-label="">
+            <div class="btn-group" role="group" aria-label="">
+                <button type="button" class="btn btn-default btn-step-into"
+                        title="{{ _('Step into') }}"
+                        accesskey="i"
+                        tabindex="0" autofocus="autofocus">
+                    <i class="fa fa-indent"></i>
+                </button>
+                <button type="button" class="btn btn-default btn-step-over"
+                        title="{{ _('Step over') }}"
+                        accesskey="o"
+                        tabindex="0">
+                    <i class="fa fa-outdent"></i>
+                </button>
+                <button type="button" class="btn btn-default btn-continue"
+                        title="{{ _('Continue/Start') }}"
+                        accesskey="c"
+                        tabindex="0">
+                    <i class="fa fa-play-circle"></i>
+                </button>
+            </div>
+            <div class="btn-group" role="group" aria-label="">
+                <button type="button" class="btn btn-default 
btn-toggle-breakpoint"
+                        title="{{ _('Toggle breakpoint ') }}"
+                        accesskey="t"
+                        tabindex="0">
+                    <i class="fa fa-circle"></i>
+                </button>
+                <button type="button" class="btn btn-default 
btn-clear-breakpoint"
+                        title="{{ _('Clear all breakpoints ') }}"
+                        accesskey="x"
+                        tabindex="0">
+                    <i class="fa fa-ban"></i>
+                </button>
+            </div>
+            <div class="btn-group" role="group" aria-label="">
+                <button type="button" class="btn btn-default btn-stop"
+                        accesskey="s"
+                        title="{{ _('Stop ') }}"
+                        tabindex="0">
+                    <i class="fa fa-stop-circle"></i>
+                </button>
+            </div>
         </div>
-        <div class="btn-group" role="group" aria-label="">
-            <button type="button" class="btn btn-default 
btn-toggle-breakpoint" title="{{ _('Toggle breakpoint') }}"
-                    tabindex="4">
-                <i class="fa fa-circle"></i>
-            </button>
-            <button type="button" class="btn btn-default btn-clear-breakpoint" 
title="{{ _('Clear all breakpoints') }}"
-                    tabindex="5">
-                <i class="fa fa-ban"></i>
-            </button>
-        </div>
-        <div class="btn-group" role="group" aria-label="">
-            <button type="button" class="btn btn-default btn-stop" title="{{ 
_('Stop') }}"
-                    tabindex="6">
-                <i class="fa fa-stop-circle"></i>
-            </button>
-        </div>
-    </div>
-</nav>
-<div id="container" class="debugger-container"></div>
+    </nav>
+    <div id="container" class="debugger-container" tabindex="0"></div>
+</div>
 {% endblock %}
 
-
 {% block css_link %}
 {% for stylesheet in stylesheets %}
 <link type="text/css" rel="stylesheet" href="{{ stylesheet }}"/>

Reply via email to