Configurable shortcuts in the Debugger. Fixes #2901

This commit is contained in:
Murtuza Zabuawala
2018-02-09 12:43:27 +00:00
committed by Dave Page
parent 258b064963
commit 942ac733a4
8 changed files with 341 additions and 59 deletions

View File

@@ -73,6 +73,172 @@ class DebuggerModule(PgAdminModule):
'will be opened in a new browser tab.')
)
# Shortcut configuration for Accesskey
accesskey_fields = [
{
'name': 'key',
'type': 'keyCode',
'label': gettext('Key')
}
]
shortcut_fields = [
{
'name': 'alt',
'type': 'checkbox',
'label': gettext('Alt/Option')
},
{
'name': 'shift',
'type': 'checkbox',
'label': gettext('Shift')
},
{
'name': 'control',
'type': 'checkbox',
'label': gettext('Ctrl')
},
{
'name': 'key',
'type': 'keyCode',
'label': gettext('Key')
}
]
self.preference.register(
'keyboard_shortcuts', 'btn_start',
gettext('Accesskey (Continue/Start)'), 'keyboardshortcut',
{
'key': {
'key_code': 67,
'char': 'c'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_stop',
gettext('Accesskey (Stop)'), 'keyboardshortcut',
{
'key': {
'key_code': 83,
'char': 's'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_step_into',
gettext('Accesskey (Step into)'), 'keyboardshortcut',
{
'key': {
'key_code': 73,
'char': 'i'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_step_over',
gettext('Accesskey (Step over)'), 'keyboardshortcut',
{
'key': {
'key_code': 79,
'char': 'o'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_toggle_breakpoint',
gettext('Accesskey (Toggle breakpoint)'), 'keyboardshortcut',
{
'key': {
'key_code': 84,
'char': 't'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_clear_breakpoints',
gettext('Accesskey (Clear all breakpoints)'), 'keyboardshortcut',
{
'key': {
'key_code': 88,
'char': 'x'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts',
'edit_grid_values',
gettext('Edit grid values'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 81,
'char': 'q'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts',
'move_previous',
gettext('Previous tab'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 37,
'char': 'ArrowLeft'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts',
'move_next',
gettext('Next tab'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 39,
'char': 'ArrowRight'
}
},
category_label=gettext('Keyboard shortcuts'),
fields=shortcut_fields
)
def get_exposed_url_endpoints(self):
"""
Returns the list of URLs exposed to the client.
@@ -159,6 +325,33 @@ def update_session_function_transaction(trans_id, data):
session['functionData'] = function_data
def get_shortcuts_for_accesskey():
"""
This function will fetch and return accesskey shortcuts for debugger
toolbar buttons
Returns:
Dict of shortcut keys
"""
# Fetch debugger preferences
dp = Preferences.module('debugger')
btn_start = dp.preference('btn_start').get()
btn_stop = dp.preference('btn_stop').get()
btn_step_into = dp.preference('btn_step_into').get()
btn_step_over = dp.preference('btn_step_over').get()
btn_toggle_breakpoint = dp.preference('btn_toggle_breakpoint').get()
btn_clear_breakpoints = dp.preference('btn_clear_breakpoints').get()
return {
'start': btn_start.get('key').get('char'),
'stop': btn_stop.get('key').get('char'),
'step_into': btn_step_into.get('key').get('char'),
'step_over': btn_step_over.get('key').get('char'),
'toggle_breakpoint': btn_toggle_breakpoint.get('key').get('char'),
'clear_breakpoints': btn_clear_breakpoints.get('key').get('char')
}
@blueprint.route(
'/init/<node_type>/<int:sid>/<int:did>/<int:scid>/<int:fid>',
methods=['GET'], endpoint='init_for_function'
@@ -411,6 +604,8 @@ def direct_new(trans_id):
# 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,
@@ -420,7 +615,8 @@ def direct_new(trans_id):
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')]
stylesheets=[url_for('debugger.static', filename='css/debugger.css')],
accesskey=get_shortcuts_for_accesskey()
)

View File

@@ -625,9 +625,8 @@ define([
Restart: function(trans_id) {
var self = this,
baseUrl = url_for('debugger.restart', {
'trans_id': trans_id,
});
baseUrl = url_for('debugger.restart', {'trans_id': trans_id});
self.enable('stop', false);
self.enable('step_over', false);
self.enable('step_into', false);
@@ -636,7 +635,11 @@ define([
self.enable('continue', false);
// Clear msg tab
pgTools.DirectDebug.messages_panel.$container.find('.messages').html('');
pgTools.DirectDebug
.messages_panel
.$container
.find('.messages')
.html('');
$.ajax({
url: baseUrl,
@@ -1161,7 +1164,9 @@ define([
model: DebuggerVariablesModel,
});
VariablesCollection.prototype.on('change', self.deposit_parameter_value, self);
VariablesCollection.prototype.on(
'change', self.deposit_parameter_value, self
);
var gridCols = [{
name: 'name',
@@ -1205,14 +1210,19 @@ define([
className: 'backgrid table-bordered',
});
variable_grid.collection.on(
'backgrid:edited', () => {
pgTools.DirectDebug.editor.focus();
}
);
variable_grid.render();
// Render the variables grid into local variables panel
pgTools.DirectDebug.local_variables_panel
.$container
.find('.local_variables')
.append(variable_grid.el);
.$container
.find('.local_variables')
.append(variable_grid.el);
},
AddParameters: function(result) {
@@ -1237,7 +1247,9 @@ define([
model: DebuggerParametersModel,
});
self.ParametersCollection.prototype.on('change', self.deposit_parameter_value, self);
ParametersCollection.prototype.on(
'change', self.deposit_parameter_value, self
);
var paramGridCols = [{
name: 'name',
@@ -1281,12 +1293,20 @@ define([
className: 'backgrid table-bordered',
});
param_grid.collection.on(
'backgrid:edited', () => {
pgTools.DirectDebug.editor.focus();
}
);
param_grid.render();
// Render the parameters grid into parameter panel
pgTools.DirectDebug.parameters_panel.$container.find('.parameters').append(param_grid.el);
pgTools.DirectDebug.parameters_panel
.$container
.find('.parameters')
.append(param_grid.el);
},
deposit_parameter_value: function(model) {
var self = this;
@@ -1476,7 +1496,45 @@ define([
},
keyAction: function (event) {
var $el = this.$el, panel_id, actual_panel;
panel_id = keyboardShortcuts.processEventDebugger($el, event);
// If already fetched earlier then don't do it again
if(_.size(pgTools.DirectDebug.debugger_keyboard_shortcuts) == 0) {
// Fetch keyboard shortcut keys
var edit_grid_shortcut_perf, next_panel_perf, previous_panel_perf;
edit_grid_shortcut_perf = window.top.pgAdmin.Browser.get_preference(
'debugger', 'edit_grid_values'
);
next_panel_perf = window.top.pgAdmin.Browser.get_preference(
'debugger', 'move_next'
);
previous_panel_perf = window.top.pgAdmin.Browser.get_preference(
'debugger', 'move_previous'
);
// If debugger opened in new Tab then window.top won't be available
if(!edit_grid_shortcut_perf || !next_panel_perf || !previous_panel_perf) {
edit_grid_shortcut_perf = window.opener.pgAdmin.Browser.get_preference(
'debugger', 'edit_grid_values'
);
next_panel_perf = window.opener.pgAdmin.Browser.get_preference(
'debugger', 'move_next'
);
previous_panel_perf = window.opener.pgAdmin.Browser.get_preference(
'debugger', 'move_previous'
);
}
pgTools.DirectDebug.debugger_keyboard_shortcuts = {
'edit_grid_keys': edit_grid_shortcut_perf.value,
'next_panel_keys': next_panel_perf.value,
'previous_panel_keys': previous_panel_perf.value,
};
}
panel_id = keyboardShortcuts.processEventDebugger(
$el, event, pgTools.DirectDebug.debugger_keyboard_shortcuts
);
// Panel navigation
if(!_.isUndefined(panel_id) && !_.isNull(panel_id)) {
actual_panel = panel_id + 1;
@@ -1513,6 +1571,7 @@ define([
this.debug_restarted = false;
this.is_user_aborted_debugging = false;
this.is_polling_required = true; // Flag to stop unwanted ajax calls
this.debugger_keyboard_shortcuts = {};
this.docker = new wcDocker(
'#container', {
@@ -1748,7 +1807,7 @@ define([
// To show the line-number and set breakpoint marker details by user.
self.editor = CodeMirror.fromTextArea(
code_editor_area.get(0), {
tabindex: 0,
tabindex: -1,
lineNumbers: true,
foldOptions: {
widget: '\u2026',
@@ -1775,6 +1834,14 @@ define([
matchBrackets: pgAdmin.Browser.editor_options.brace_matching,
});
// Useful for keyboard navigation, when user presses escape key we will
// defocus from the codemirror editor allow user to navigate further
CodeMirror.on(self.editor, 'keydown', function(cm,event) {
if(event.keyCode==27){
document.activeElement.blur();
}
});
// On loading the docker, register the callbacks
var onLoad = function() {
self.docker.finishLoading(100);

View File

@@ -41,19 +41,19 @@ try {
<div class="btn-group" role="group" aria-label="">
<button type="button" class="btn btn-default btn-step-into"
title="{{ _('Step into') }}"
accesskey="i"
accesskey="{{ accesskey.step_into }}"
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"
accesskey="{{ accesskey.step_over }}"
tabindex="0">
<i class="fa fa-outdent"></i>
</button>
<button type="button" class="btn btn-default btn-continue"
title="{{ _('Continue/Start') }}"
accesskey="c"
accesskey="{{ accesskey.toggle_breakpoint }}"
tabindex="0">
<i class="fa fa-play-circle"></i>
</button>
@@ -61,20 +61,20 @@ try {
<div class="btn-group" role="group" aria-label="">
<button type="button" class="btn btn-default btn-toggle-breakpoint"
title="{{ _('Toggle breakpoint') }}"
accesskey="t"
accesskey="{{ accesskey.toggle_breakpoint }}"
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"
accesskey="{{ accesskey.clear_breakpoints }}"
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"
accesskey="{{ accesskey.stop }}"
title="{{ _('Stop') }}"
tabindex="0">
<i class="fa fa-stop-circle"></i>