F5 key should work to refresh Browser tree. Fixes #3284

Refactoring by:  Joao Pedro De Almeida Pereira
pull/9/merge
Khushboo Vashi 2018-05-02 11:43:42 +05:30 committed by Akshay Joshi
parent c2122fbfb9
commit 732d8d903d
4 changed files with 383 additions and 261 deletions

View File

@ -291,3 +291,18 @@ def register_browser_preferences(self):
category_label=gettext('Keyboard shortcuts'), category_label=gettext('Keyboard shortcuts'),
fields=fields fields=fields
) )
self.preference.register(
'keyboard_shortcuts',
'sub_menu_refresh',
gettext('Refresh browser tree'),
'keyboardshortcut',
{
'alt': False,
'shift': False,
'control': False,
'key': {'key_code': 116, 'char': 'F5'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)

View File

@ -1,13 +1,15 @@
define(['underscore', 'underscore.string', 'sources/pgadmin', 'jquery', 'mousetrap', import _ from 'underscore';
'sources/utils', 'sources/dialog_tab_navigator'], import pgAdmin from '../../../static/js/pgadmin';
function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) { import $ from 'jquery';
'use strict'; import Mousetrap from 'mousetrap';
import * as commonUtils from '../../../static/js/utils';
import dialogTabNavigator from '../../../static/js/dialog_tab_navigator';
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
pgBrowser.keyboardNavigation = pgBrowser.keyboardNavigation || {}; pgBrowser.keyboardNavigation = pgBrowser.keyboardNavigation || {};
_.extend(pgBrowser.keyboardNavigation, { _.extend(pgBrowser.keyboardNavigation, {
init: function() { init: function() {
Mousetrap.reset(); Mousetrap.reset();
if (pgBrowser.preferences_cache.length > 0) { if (pgBrowser.preferences_cache.length > 0) {
@ -24,13 +26,16 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
'sub_menu_properties': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_properties').value), 'sub_menu_properties': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_properties').value),
'sub_menu_create': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_create').value), 'sub_menu_create': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_create').value),
'sub_menu_delete': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_delete').value), 'sub_menu_delete': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_delete').value),
'sub_menu_refresh': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_refresh').value),
'context_menu': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'context_menu').value), 'context_menu': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'context_menu').value),
'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value), 'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value),
}; };
this.shortcutMethods = { this.shortcutMethods = {
'bindMainMenu': {'shortcuts': [this.keyboardShortcut.file_shortcut, 'bindMainMenu': {
'shortcuts': [this.keyboardShortcut.file_shortcut,
this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut, this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut,
this.keyboardShortcut.help_shortcut]}, // Main menu this.keyboardShortcut.help_shortcut],
}, // Main menu
'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels 'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels
'bindMainMenuLeft': {'shortcuts': 'left', 'bindElem': '.pg-navbar'}, // Main menu 'bindMainMenuLeft': {'shortcuts': 'left', 'bindElem': '.pg-navbar'}, // Main menu
'bindMainMenuRight': {'shortcuts': 'right', 'bindElem': '.pg-navbar'}, // Main menu 'bindMainMenuRight': {'shortcuts': 'right', 'bindElem': '.pg-navbar'}, // Main menu
@ -41,6 +46,7 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
'bindSubMenuProperties': {'shortcuts': this.keyboardShortcut.sub_menu_properties}, // Sub menu - Edit Properties, 'bindSubMenuProperties': {'shortcuts': this.keyboardShortcut.sub_menu_properties}, // Sub menu - Edit Properties,
'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object, 'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object,
'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object, 'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object,
'bindSubMenuRefresh': {'shortcuts': this.keyboardShortcut.sub_menu_refresh, 'bindElem': '#tree'}, // Sub menu - Refresh object,
'bindContextMenu': {'shortcuts': this.keyboardShortcut.context_menu}, // Sub menu - Open context menu, 'bindContextMenu': {'shortcuts': this.keyboardShortcut.context_menu}, // Sub menu - Open context menu,
'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging 'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging
}; };
@ -48,132 +54,111 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
} }
}, },
bindShortcuts: function() { bindShortcuts: function() {
var self = this; const self = this;
_.each(self.shortcutMethods, function(keyCombo, callback) { _.each(self.shortcutMethods, (keyCombo, callback) => {
self._bindWithMousetrap(keyCombo.shortcuts, self[callback], keyCombo.bindElem); self._bindWithMousetrap(keyCombo.shortcuts, self[callback], keyCombo.bindElem);
}); });
}, },
_bindWithMousetrap: function(shortcuts, callback, bindElem) { _bindWithMousetrap: function(shortcuts, callback, bindElem) {
var self = this; const self = this;
if (bindElem) { if (bindElem) {
var elem = document.querySelector(bindElem); const elem = document.querySelector(bindElem);
Mousetrap(elem).bind(shortcuts, function() { Mousetrap(elem).bind(shortcuts, function() {
callback.apply(this, arguments); callback.apply(this, arguments);
}.bind(elem)); }.bind(elem));
} else { } else {
Mousetrap.bind(shortcuts, function() { Mousetrap.bind(shortcuts, function () {
callback.apply(self, arguments); callback.apply(self, arguments);
}); });
} }
}, },
attachShortcut: function(shortcut, callback, bindElem) { bindMainMenu: function(event, combo) {
this._bindWithMousetrap(shortcut, callback, bindElem); const shortcut_obj = this.keyboardShortcut;
if (combo === shortcut_obj.file_shortcut) $('#mnu_file a.dropdown-toggle').dropdown('toggle');
if (combo === shortcut_obj.object_shortcut) $('#mnu_obj a.dropdown-toggle').first().dropdown('toggle');
if (combo === shortcut_obj.tools_shortcut) $('#mnu_tools a.dropdown-toggle').dropdown('toggle');
if (combo === shortcut_obj.help_shortcut) $('#mnu_help a.dropdown-toggle').dropdown('toggle');
}, },
attachDialogTabNavigatorShortcut: function(dialogTabNavigator, shortcuts) { bindRightPanel: function(event, combo) {
var callback = dialogTabNavigator.on_keyboard_event, let allPanels = pgAdmin.Browser.docker.findPanels();
domElem = dialogTabNavigator.dialog.el; let activePanel = 0;
let nextPanel = allPanels.length;
let prevPanel = 1;
let activePanelId = 0;
let activePanelFlag = false;
let shortcut_obj = this.keyboardShortcut;
if (domElem) { _.each(pgAdmin.Browser.docker.findPanels(), (panel, index) => {
Mousetrap(domElem).bind(shortcuts, function() { if (panel.isVisible() && !activePanelFlag && panel._type !== 'browser') {
callback.apply(dialogTabNavigator, arguments);
}.bind(domElem));
} else {
Mousetrap.bind(shortcuts, function() {
callback.apply(dialogTabNavigator, arguments);
});
}
},
detachShortcut: function(shortcut, bindElem) {
if (bindElem) Mousetrap(bindElem).unbind(shortcut);
else Mousetrap.unbind(shortcut);
},
bindMainMenu: function(e, combo) {
var shortcut_obj = this.keyboardShortcut;
if (combo == shortcut_obj.file_shortcut) $('#mnu_file a.dropdown-toggle').dropdown('toggle');
if (combo == shortcut_obj.object_shortcut) $('#mnu_obj a.dropdown-toggle').first().dropdown('toggle');
if (combo == shortcut_obj.tools_shortcut) $('#mnu_tools a.dropdown-toggle').dropdown('toggle');
if (combo == shortcut_obj.help_shortcut) $('#mnu_help a.dropdown-toggle').dropdown('toggle');
},
bindRightPanel: function(e, combo) {
var allPanels = pgAdmin.Browser.docker.findPanels(),
activePanel = 0,
nextPanel = allPanels.length,
prevPanel = 1,
activePanelId = 0,
activePanelFlag = false,
shortcut_obj = this.keyboardShortcut;
_.each(pgAdmin.Browser.docker.findPanels(), function(panel, index){
if (panel.isVisible() && !activePanelFlag && panel._type != 'browser'){
activePanelId = index; activePanelId = index;
activePanelFlag = true; activePanelFlag = true;
} }
}); });
if (combo == shortcut_obj.tabbed_panel_backward) activePanel = (activePanelId > 0) ? activePanelId - 1 : prevPanel; if (combo === shortcut_obj.tabbed_panel_backward) activePanel = (activePanelId > 0) ? activePanelId - 1 : prevPanel;
else if (combo == shortcut_obj.tabbed_panel_forward) activePanel = (activePanelId < nextPanel) ? activePanelId + 1 : nextPanel; else if (combo === shortcut_obj.tabbed_panel_forward) activePanel = (activePanelId < nextPanel) ? activePanelId + 1 : nextPanel;
pgAdmin.Browser.docker.findPanels()[activePanel].focus(); pgAdmin.Browser.docker.findPanels()[activePanel].focus();
setTimeout(function() { setTimeout(() => {
if (document.activeElement instanceof HTMLIFrameElement) { if (document.activeElement instanceof HTMLIFrameElement) {
document.activeElement.blur(); document.activeElement.blur();
} }
}, 1000); }, 1000);
}, },
bindMainMenuLeft: function(e) { bindMainMenuLeft: function(event) {
var prevMenu; let prevMenu;
if ($(e.target).hasClass('menu-link')) { // Menu items if ($(event.target).hasClass('menu-link')) { // Menu items
prevMenu = $(e.target).parent().parent().parent().prev('.dropdown'); prevMenu = $(event.target).parent().parent().parent().prev('.dropdown');
} }
else if ($(e.target).parent().hasClass('dropdown-submenu')) { // Sub menu else if ($(event.target).parent().hasClass('dropdown-submenu')) { // Sub menu
$(e.target).parent().toggleClass('open'); $(event.target).parent().toggleClass('open');
return; return;
} }
else { //Menu headers else { //Menu headers
prevMenu = $(e.target).parent().prev('.dropdown'); prevMenu = $(event.target).parent().prev('.dropdown');
} }
if (prevMenu.hasClass('hide')) prevMenu = prevMenu.prev('.dropdown'); // Skip hidden menus if (prevMenu.hasClass('hide')) prevMenu = prevMenu.prev('.dropdown'); // Skip hidden menus
prevMenu.find('a:first').dropdown('toggle'); prevMenu.find('a:first').dropdown('toggle');
}, },
bindMainMenuRight: function(e) { bindMainMenuRight: function(event) {
var nextMenu; let nextMenu;
if ($(e.target).hasClass('menu-link')) { // Menu items if ($(event.target).hasClass('menu-link')) { // Menu items
nextMenu = $(e.target).parent().parent().parent().next('.dropdown'); nextMenu = $(event.target).parent().parent().parent().next('.dropdown');
} }
else if ($(e.target).parent().hasClass('dropdown-submenu')) { // Sub menu else if ($(event.target).parent().hasClass('dropdown-submenu')) { // Sub menu
$(e.target).parent().toggleClass('open'); $(event.target).parent().toggleClass('open');
return; return;
} }
else { //Menu headers else { //Menu headers
nextMenu = $(e.target).parent().next('.dropdown'); nextMenu = $(event.target).parent().next('.dropdown');
} }
if (nextMenu.hasClass('hide')) nextMenu = nextMenu.next('.dropdown'); // Skip hidden menus if (nextMenu.hasClass('hide')) nextMenu = nextMenu.next('.dropdown'); // Skip hidden menus
nextMenu.find('a:first').dropdown('toggle'); nextMenu.find('a:first').dropdown('toggle');
}, },
bindMainMenuUpDown: function(e, combo) { bindMainMenuUpDown: function(event, combo) {
// Handle Sub-menus // Handle Sub-menus
if (combo == 'up' && $(e.target).parent().prev().prev('.dropdown-submenu').length > 0) { if (combo === 'up' && $(event.target).parent().prev().prev('.dropdown-submenu').length > 0) {
$(e.target).parent().prev().prev('.dropdown-submenu').find('a:first').focus(); $(event.target).parent().prev().prev('.dropdown-submenu').find('a:first').focus();
} else { } else {
if ($(e.target).parent().hasClass('dropdown-submenu')) { if ($(event.target).parent().hasClass('dropdown-submenu')) {
$(e.target).parent().parent().parent().find('a:first').dropdown('toggle'); $(event.target).parent().parent().parent().find('a:first').dropdown('toggle');
$(e.target).parent().parent().children().eq(2).find('a:first').focus(); $(event.target).parent().parent().children().eq(2).find('a:first').focus();
} }
} }
}, },
bindLeftTree: function() { bindLeftTree: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
$('#tree').focus(); $('#tree').focus();
tree.t.focus(tree.i); tree.t.focus(tree.i);
tree.t.select(tree.i); tree.t.select(tree.i);
}, },
bindSubMenuQueryTool: function() { bindSubMenuQueryTool: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
if (!tree.d) if (!tree.d)
return; return;
@ -182,7 +167,7 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
pgAdmin.DataGrid.show_query_tool('', tree.i); pgAdmin.DataGrid.show_query_tool('', tree.i);
}, },
bindSubMenuViewData: function() { bindSubMenuViewData: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
if (!tree.d) if (!tree.d)
return; return;
@ -191,9 +176,9 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
pgAdmin.DataGrid.show_data_grid({'mnuid': 1}, tree.i); pgAdmin.DataGrid.show_data_grid({'mnuid': 1}, tree.i);
}, },
bindSubMenuProperties: function() { bindSubMenuProperties: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node == true) if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node === true)
return; return;
// Open properties dialog in edit mode // Open properties dialog in edit mode
@ -202,9 +187,9 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
); );
}, },
bindSubMenuCreate: function() { bindSubMenuCreate: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node == true) if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node === true)
return; return;
// Open properties dialog in edit mode // Open properties dialog in edit mode
@ -213,55 +198,60 @@ function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
); );
}, },
bindSubMenuDelete: function() { bindSubMenuDelete: function() {
var tree = this.getTreeDetails(); const tree = this.getTreeDetails();
if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node == true) if (!tree.d || pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type].collection_node === true)
return; return;
// Call delete object callback // Call delete object callback
pgAdmin.Browser.Node.callbacks.delete_obj.call(pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type]); pgAdmin.Browser.Node.callbacks.delete_obj.call(pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type]);
}, },
bindContextMenu: function(e) { bindSubMenuRefresh: function(event) {
var tree = this.getTreeDetails(), event.preventDefault();
left = $(e.srcElement).find('.aciTreeEntry').position().left + 70, const tree = pgBrowser.keyboardNavigation.getTreeDetails();
top = $(e.srcElement).find('.aciTreeEntry').position().top + 70;
e = window.event; // Call refresh object callback
pgAdmin.Browser.Node.callbacks.refresh.call(pgAdmin.Browser.Nodes[tree.t.itemData(tree.i)._type]);
},
bindContextMenu: function(event) {
const tree = this.getTreeDetails();
const left = $(event.srcElement).find('.aciTreeEntry').position().left + 70;
const top = $(event.srcElement).find('.aciTreeEntry').position().top + 70;
tree.t.blur(tree.i); tree.t.blur(tree.i);
$('#tree').blur(); $('#tree').blur();
// Call context menu and set position // Call context menu and set position
tree.i.children().contextMenu({x: left, y:top}); tree.i.children().contextMenu({x: left, y: top});
}, },
bindDirectDebugging: function() { bindDirectDebugging: function() {
var tree = this.getTreeDetails(), const tree = this.getTreeDetails();
type = tree.t.itemData(tree.i)._type; const type = tree.t.itemData(tree.i)._type;
if (!tree.d || (type != 'function' && type != 'procedure')) if (!tree.d || (type !== 'function' && type !== 'procedure'))
return; return;
if(pgAdmin.Tools.Debugger.can_debug(tree.d, tree.i, {'debug_type': 'direct'})) { if (pgAdmin.Tools.Debugger.can_debug(tree.d, tree.i, {'debug_type': 'direct'})) {
// Call debugger callback // Call debugger callback
pgAdmin.Tools.Debugger.get_function_information(pgAdmin.Browser.Nodes[type]); pgAdmin.Tools.Debugger.get_function_information(pgAdmin.Browser.Nodes[type]);
} }
}, },
getTreeDetails: function() { getTreeDetails: function() {
var t = pgAdmin.Browser.tree, const aciTree = pgAdmin.Browser.tree;
i = t.selected().length > 0 ? t.selected() : t.first(), const selectedTreeNode = aciTree.selected().length > 0 ? aciTree.selected() : aciTree.first();
d = i && i.length == 1 ? t.itemData(i) : undefined; const selectedTreeNodeData = selectedTreeNode && selectedTreeNode.length === 1 ? aciTree.itemData(selectedTreeNode) : undefined;
return { return {
t: t, t: aciTree,
i: i, i: selectedTreeNode,
d: d, d: selectedTreeNodeData,
}; };
}, },
getDialogTabNavigator: function(dialog) { getDialogTabNavigator: function(dialog) {
var backward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_backward').value, const backward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_backward').value;
forward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_forward').value; const forward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_forward').value;
return new dialogTabNavigator.dialogTabNavigator(dialog, backward_shortcut, forward_shortcut); return new dialogTabNavigator.dialogTabNavigator(dialog, backward_shortcut, forward_shortcut);
}, },
});
return pgAdmin.keyboardNavigation;
}); });
module.exports = pgAdmin.Browser.keyboardNavigation;

View File

@ -12,7 +12,7 @@ export function parseShortcutValue(obj) {
if (obj.alt) { shortcut += 'alt+'; } if (obj.alt) { shortcut += 'alt+'; }
if (obj.shift) { shortcut += 'shift+'; } if (obj.shift) { shortcut += 'shift+'; }
if (obj.control) { shortcut += 'ctrl+'; } if (obj.control) { shortcut += 'ctrl+'; }
shortcut += String.fromCharCode(obj.key.key_code).toLowerCase(); shortcut += obj.key.char.toLowerCase();
return shortcut; return shortcut;
} }

View File

@ -0,0 +1,117 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import { parseShortcutValue } from 'sources/utils';
describe('parseShortcutValue', function () {
describe('when short cut is F5', function () {
it('returns f5', function () {
expect(parseShortcutValue({
alt: false,
control: false,
shift: false,
key: {
char: 'F5',
key_code: 116,
},
})).toEqual('f5');
});
});
describe('when short cut is Alt+Shift+F5', function () {
it('returns alt+shift+f5', function () {
expect(parseShortcutValue({
alt: true,
control: false,
shift: true,
key: {
char: 'F5',
key_code: 116,
},
})).toEqual('alt+shift+f5');
});
});
describe('when short cut is Alt+Shift+t', function () {
it('returns alt+shift+t', function () {
expect(parseShortcutValue({
alt: true,
control: false,
shift: true,
key: {
char: 't',
key_code: 84,
},
})).toEqual('alt+shift+t');
});
});
describe('when short cut is Alt+Shift+Ctrl+t', function () {
it('returns alt+shift+ctrl+t', function () {
expect(parseShortcutValue({
alt: true,
control: true,
shift: true,
key: {
char: 't',
key_code: 84,
},
})).toEqual('alt+shift+ctrl+t');
});
});
describe('when short cut is Alt+Ctrl+t', function () {
it('returns alt+ctrl+t', function () {
expect(parseShortcutValue({
alt: true,
control: true,
shift: false,
key: {
char: 't',
key_code: 84,
},
})).toEqual('alt+ctrl+t');
});
});
describe('when short cut is Shift+Ctrl+L', function () {
it('returns shift+ctrl+l', function () {
expect(parseShortcutValue({
alt: false,
control: true,
shift: true,
key: {
char: 'L',
key_code: 76,
},
})).toEqual('shift+ctrl+l');
});
});
describe('when short cut is $', function () {
it('returns $', function () {
expect(parseShortcutValue({
alt: false,
control: false,
shift: false,
key: {
char: '$',
key_code: 52,
},
})).toEqual('$');
});
});
describe('when short cut is 4', function () {
it('returns 4', function () {
expect(parseShortcutValue({
alt: false,
control: false,
shift: false,
key: {
char: '4',
key_code: 52,
},
})).toEqual('4');
});
});
});