Add keyboard navigation options for the main browser windows. Fixes #2895

This commit is contained in:
Khushboo Vashi 2018-02-02 14:28:37 +01:00 committed by Dave Page
parent 2042f89ce0
commit 262d01bf01
16 changed files with 438 additions and 12 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@ -3,6 +3,7 @@ Keyboard Shortcuts
****************** ******************
Keyboard shortcuts are provided in pgAdmin to allow easy access to specific functions. Keyboard shortcuts are provided in pgAdmin to allow easy access to specific functions.
The shortcuts can be configured through File > Preferences dialogue as per the need.
**Desktop Runtime** **Desktop Runtime**
@ -27,6 +28,27 @@ When running in the Desktop Runtime, the following keyboard shortcuts are availa
| Ctrl+0 | Cmd+0 | Reset the zoom level | | Ctrl+0 | Cmd+0 | Reset the zoom level |
+--------------------------+----------------+---------------------------------------+ +--------------------------+----------------+---------------------------------------+
**Main Browser Window**
When using main browser window, the following keyboard shortcuts are available:
+---------------------------+--------------------------------------------------------+
| Shortcut for all platform | Function |
+===========================+========================================================+
| Alt+Shift+F | Open the File menu |
+---------------------------+--------------------------------------------------------+
| Alt+Shift+O | Open the Object menu |
+---------------------------+--------------------------------------------------------+
| Alt+Shift+L | Open the Tools menu |
+---------------------------+--------------------------------------------------------+
| Alt+Shift+H | Open the Help menu |
+---------------------------+--------------------------------------------------------+
| Alt+Shift+B | Focus the browser tree |
+---------------------------+--------------------------------------------------------+
| Alt+Shift+[ | Move tabbed panel backward/forward |
| Alt+Shift+] | |
+---------------------------+--------------------------------------------------------+
**SQL Editors** **SQL Editors**

View File

@ -20,6 +20,13 @@ Use the fields on the *Display* panel to specify general display preferences:
* When the *Show system objects* switch is set to *True*, the client will display system objects such as system schemas (for example, *pg_temp*) or system columns (for example, *xmin* or *ctid*) in the tree control. * When the *Show system objects* switch is set to *True*, the client will display system objects such as system schemas (for example, *pg_temp*) or system columns (for example, *xmin* or *ctid*) in the tree control.
Use the fields on the *Keyboard shortcuts* panel to configure shortcuts for the main window navigation:
.. image:: images/preferences_browser_keyboard_shortcuts.png
:alt: Preferences dialog browser keyboard shortcuts section
* The panel displays a list of keyboard shortcuts available for the main window; select the combination of the modifier keys along with the key to configure each shortcut.
Use the fields on the *Nodes* panel to select the object types that will be displayed in the *Browser* tree control: Use the fields on the *Nodes* panel to select the object types that will be displayed in the *Browser* tree control:
.. image:: images/preferences_browser_nodes.png .. image:: images/preferences_browser_nodes.png

View File

@ -37,3 +37,4 @@ BigNumber 3.0.1 MIT http://mikemcl.github.io/bignumb
Source Code Pro 1.1 SIL OFL https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700 Source Code Pro 1.1 SIL OFL https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700
Open Sans 2.0 AL https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600,700 Open Sans 2.0 AL https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600,700
Spectrum 1.8 MIT https://bgrins.github.io/spectrum/ Spectrum 1.8 MIT https://bgrins.github.io/spectrum/
Mousetrap 1.6.1 AL https://github.com/ccampbell/mousetrap

View File

@ -70,6 +70,7 @@
"jquery-contextmenu": "^2.5.0", "jquery-contextmenu": "^2.5.0",
"jquery-ui": "^1.12.1", "jquery-ui": "^1.12.1",
"moment": "^2.18.1", "moment": "^2.18.1",
"mousetrap": "^1.6.1",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react": "file:../web/pgadmin/static/vendor/react", "react": "file:../web/pgadmin/static/vendor/react",
"react-dom": "file:../web/pgadmin/static/vendor/react-dom", "react-dom": "file:../web/pgadmin/static/vendor/react-dom",

View File

@ -213,7 +213,117 @@ class BrowserModule(PgAdminModule):
gettext("Count rows if estimated less than"), 'integer', 2000, gettext("Count rows if estimated less than"), 'integer', 2000,
category_label=gettext('Properties') category_label=gettext('Properties')
) )
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',
'browser_tree',
gettext('Browser tree'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 66, 'char': 'b'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'tabbed_panel_backward',
gettext('Tabbed panel backward'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 91, 'char': '['}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'tabbed_panel_forward',
gettext('Tabbed panel forward'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 93, 'char': ']'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'main_menu_file',
gettext('File main menu'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 70, 'char': 'f'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'main_menu_object',
gettext('Object main menu'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 79, 'char': 'o'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'main_menu_tools',
gettext('Tools main menu'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 76, 'char': 'l'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'main_menu_help',
gettext('Help main menu'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 72, 'char': 'h'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
def get_exposed_url_endpoints(self): def get_exposed_url_endpoints(self):
""" """
Returns: Returns:

View File

@ -8,6 +8,7 @@ define('pgadmin.browser', [
'pgadmin.browser.error', 'pgadmin.browser.frame', 'pgadmin.browser.error', 'pgadmin.browser.frame',
'pgadmin.browser.node', 'pgadmin.browser.collection', 'pgadmin.browser.node', 'pgadmin.browser.collection',
'sources/codemirror/addon/fold/pgadmin-sqlfoldcode', 'sources/codemirror/addon/fold/pgadmin-sqlfoldcode',
'pgadmin.browser.keyboard',
], function( ], function(
gettext, url_for, require, $, _, S, Bootstrap, pgAdmin, Alertify, gettext, url_for, require, $, _, S, Bootstrap, pgAdmin, Alertify,
codemirror, checkNodeVisibility codemirror, checkNodeVisibility
@ -544,7 +545,7 @@ define('pgadmin.browser', [
menus[m.name] = new MenuItem({ menus[m.name] = new MenuItem({
name: m.name, label: m.label, module: m.module, name: m.name, label: m.label, module: m.module,
category: m.category, callback: m.callback, category: m.category, callback: m.callback,
priority: m.priority, data: m.data, url: m.url, priority: m.priority, data: m.data, url: m.url || '#',
target: m.target, icon: m.icon, target: m.target, icon: m.icon,
enable: (m.enable == '' ? true : (_.isString(m.enable) && enable: (m.enable == '' ? true : (_.isString(m.enable) &&
m.enable.toLowerCase() == 'false') ? m.enable.toLowerCase() == 'false') ?
@ -678,6 +679,7 @@ define('pgadmin.browser', [
url: url_for('preferences.get_all'), url: url_for('preferences.get_all'),
success: function(res) { success: function(res) {
self.preferences_cache = res; self.preferences_cache = res;
pgBrowser.keyboardNavigation.init();
}, },
error: function(xhr) { error: function(xhr) {
try { try {
@ -1958,8 +1960,8 @@ define('pgadmin.browser', [
pgAdmin.Browser.editor_shortcut_keys.Tab = 'insertSoftTab'; pgAdmin.Browser.editor_shortcut_keys.Tab = 'insertSoftTab';
} }
window.onbeforeunload = function(ev) { window.onbeforeunload = function() {
var e = ev || window.event, var e = window.event,
msg = S(gettext('Are you sure you wish to close the %s browser?')).sprintf(pgBrowser.utils.app_name).value(); msg = S(gettext('Are you sure you wish to close the %s browser?')).sprintf(pgBrowser.utils.app_name).value();
// For IE and Firefox prior to version 4 // For IE and Firefox prior to version 4
@ -1971,5 +1973,6 @@ define('pgadmin.browser', [
return msg; return msg;
}; };
return pgAdmin.Browser; return pgAdmin.Browser;
}); });

View File

@ -0,0 +1,159 @@
/* eslint-disable */
define(
['underscore', 'underscore.string', 'sources/pgadmin', 'jquery', 'mousetrap'],
function(_, S, pgAdmin, $, Mousetrap) {
'use strict';
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
pgBrowser.keyboardNavigation = pgBrowser.keyboardNavigation || {};
_.extend(pgBrowser.keyboardNavigation, {
init: function() {
Mousetrap.reset();
if (pgBrowser.preferences_cache.length > 0) {
this.keyboardShortcut = {
'file_shortcut': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_file').value),
'object_shortcut': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_object').value),
'tools_shortcut': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_tools').value),
'help_shortcut': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_help').value),
'left_tree_shortcut': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'browser_tree').value),
'tabbed_panel_backward': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_backward').value),
'tabbed_panel_forward': pgBrowser.keyboardNavigation.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_forward').value)
};
this.shortcutMethods = {
'bindMainMenu': {'shortcuts': [this.keyboardShortcut.file_shortcut,
this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut,
this.keyboardShortcut.help_shortcut]}, // Main menu
'bindRightPanel': {'shortcuts': [this.keyboardShortcut.tabbed_panel_backward, this.keyboardShortcut.tabbed_panel_forward]}, // Main window panels
'bindMainMenuLeft': {'shortcuts': 'left', 'bindElem': '.pg-navbar'}, // Main menu
'bindMainMenuRight': {'shortcuts': 'right', 'bindElem': '.pg-navbar'}, // Main menu
'bindMainMenuUpDown': {'shortcuts': ['up', 'down']}, // Main menu
'bindLeftTree': {'shortcuts': this.keyboardShortcut.left_tree_shortcut}, // Main menu
};
this.bindShortcuts();
}
},
bindShortcuts: function() {
var self = this;
_.each(self.shortcutMethods, function(keyCombo, callback) {
self._bindWithMousetrap(keyCombo.shortcuts, self[callback], keyCombo.bindElem);
});
},
_bindWithMousetrap: function(shortcuts, callback, bindElem) {
if (bindElem) {
var elem = document.querySelector(bindElem);
Mousetrap(elem).bind(shortcuts, function() {
callback.apply(this, arguments);
}.bind(elem));
} else {
Mousetrap.bind(shortcuts, function() {
callback.apply(this, arguments);
});
}
},
attachShortcut: function(shortcut, callback, bindElem) {
this._bindWithMousetrap(shortcut, callback, bindElem);
},
detachShortcut: function(shortcut, bindElem) {
if (bindElem) Mousetrap(bindElem).unbind(shortcut);
else Mousetrap.unbind(shortcut);
},
bindMainMenu: function(e, combo) {
var shortcut_obj = pgAdmin.Browser.keyboardNavigation.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 = pgAdmin.Browser.keyboardNavigation.keyboardShortcut;
_.each(pgAdmin.Browser.docker.findPanels(), function(panel, index){
if (panel.isVisible() && !activePanelFlag && panel._type != 'browser'){
activePanelId = index;
activePanelFlag = true;
}
});
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;
pgAdmin.Browser.docker.findPanels()[activePanel].focus();
setTimeout(function() {
if (document.activeElement instanceof HTMLIFrameElement) {
document.activeElement.blur();
}
}, 1000);
},
bindMainMenuLeft: function(e) {
var prevMenu;
if ($(e.target).hasClass('menu-link')) { // Menu items
prevMenu = $(e.target).parent().parent().parent().prev('.dropdown');
}
else if ($(e.target).parent().hasClass('dropdown-submenu')) { // Sub menu
$(e.target).parent().toggleClass('open');
return;
}
else { //Menu headers
prevMenu = $(e.target).parent().prev('.dropdown');
}
if (prevMenu.hasClass('hide')) prevMenu = prevMenu.prev('.dropdown'); // Skip hidden menus
prevMenu.find('a:first').dropdown('toggle');
},
bindMainMenuRight: function(e) {
var nextMenu;
if ($(e.target).hasClass('menu-link')) { // Menu items
nextMenu = $(e.target).parent().parent().parent().next('.dropdown');
}
else if ($(e.target).parent().hasClass('dropdown-submenu')) { // Sub menu
$(e.target).parent().toggleClass('open');
return;
}
else { //Menu headers
nextMenu = $(e.target).parent().next('.dropdown');
}
if (nextMenu.hasClass('hide')) nextMenu = nextMenu.next('.dropdown'); // Skip hidden menus
nextMenu.find('a:first').dropdown('toggle');
},
bindMainMenuUpDown: function(e, combo) {
// Handle Sub-menus
if (combo == 'up' && $(e.target).parent().prev().prev('.dropdown-submenu').length > 0) {
$(e.target).parent().prev().prev('.dropdown-submenu').find('a:first').focus();
} else {
if ($(e.target).parent().hasClass('dropdown-submenu')) {
$(e.target).parent().parent().parent().find('a:first').dropdown('toggle');
$(e.target).parent().parent().children().eq(2).find('a:first').focus();
}
}
},
bindLeftTree: function() {
var t = pgAdmin.Browser.tree,
item = t.selected().length > 0 ? t.selected() : t.first();
$('#tree').focus();
t.focus(item);
t.select(item);
},
parseShortcutValue: function(obj) {
var shortcut = "";
if (obj.alt) { shortcut += 'alt+'; }
if (obj.shift) { shortcut += 'shift+'; }
if (obj.control) { shortcut += 'ctrl+'; }
shortcut += String.fromCharCode(obj.key.key_code).toLowerCase();
return shortcut;
}
});
return pgAdmin.keyboardNavigation;
});

View File

@ -42,7 +42,8 @@ define(
if (!that.showTitle) if (!that.showTitle)
myPanel.title(false); myPanel.title(false);
else { else {
myPanel.title(title || that.title); var title_elem = '<a href="#" tabindex="0" class="panel-link-heading">' + (title || that.title) + '</a>';
myPanel.title(title_elem);
if (that.icon != '') if (that.icon != '')
myPanel.icon(that.icon); myPanel.icon(that.icon);
} }

View File

@ -131,37 +131,37 @@ window.onload = function(e){
</a> </a>
</div> </div>
<div class="collapse navbar-collapse" id="navbar-menu"> <div class="collapse navbar-collapse" id="navbar-menu" role="navigation">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li id="mnu_file" class="dropdown hide"> <li id="mnu_file" class="dropdown hide">
<a href="#" accesskey="f" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('File') }} <span class="caret"></span></a> _('File') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>
<li id="mnu_edit" class="dropdown hide"> <li id="mnu_edit" class="dropdown hide">
<a href="#" accesskey="e" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('Edit') }} <span class="caret"></span></a> _('Edit') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>
<li id="mnu_obj" class="dropdown "> <li id="mnu_obj" class="dropdown ">
<a href="#" accesskey="o" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('Object') }} <span class="caret"></span></a> _('Object') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>
<li id="mnu_management" class="dropdown hide"> <li id="mnu_management" class="dropdown hide">
<a href="#" accesskey="m" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('Management') }} <span class="caret"></span></a> _('Management') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>
<li id="mnu_tools" accesskey="t" class="dropdown hide"> <li id="mnu_tools" class="dropdown hide">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('Tools') }} <span class="caret"></span></a> _('Tools') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>
<li id="mnu_help" class="dropdown hide"> <li id="mnu_help" class="dropdown hide">
<a href="#" accesskey="h" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
_('Help') }} <span class="caret"></span></a> _('Help') }} <span class="caret"></span></a>
<ul class="dropdown-menu navbar-inverse" role="menu"></ul> <ul class="dropdown-menu navbar-inverse" role="menu"></ul>
</li> </li>

View File

@ -0,0 +1,95 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import os
import json
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from regression.feature_utils.base_feature_test import BaseFeatureTest
from selenium.webdriver.common.keys import Keys
class KeyboardShortcutFeatureTest(BaseFeatureTest):
"""
This feature test will test the keyboard short is working
properly.
"""
scenarios = [
("Test for keyboard shortcut", dict())
]
def before(self):
self.new_shortcuts = {
'mnu_file': {'shortcut': [Keys.ALT, Keys.SHIFT, 'i'], 'locator': 'File main menu'},
'mnu_obj': {'shortcut': [Keys.ALT, Keys.SHIFT, 'j'], 'locator': 'Object main menu'}
}
self.wait = WebDriverWait(self.page.driver, 10)
def runTest(self):
self._update_preferences()
# On updating keyboard shortcuts, preference cache is updated.
# There is no UI event through which we can identify that the cache is updated,
# So, added time.sleep()
time.sleep(1)
self._check_shortcuts()
def _check_shortcuts(self):
action = ActionChains(self.driver)
for s in self.new_shortcuts:
key_combo = self.new_shortcuts[s]['shortcut']
action.key_down(key_combo[0]).key_down(key_combo[1]).key_down(key_combo[2]).key_up(Keys.ALT).perform()
self.wait.until(EC.presence_of_element_located(
(By.XPATH, "//li[contains(@id, " + s + ") and contains(@class, 'open')]"))
)
is_open = 'open' in self.page.find_by_id(s).get_attribute('class')
assert is_open is True, "Keyboard shortcut change is unsuccessful."
def _update_preferences(self):
self.page.find_by_id("mnu_file").click()
self.page.find_by_id("mnu_preferences").click()
self.wait.until(EC.presence_of_element_located(
(By.XPATH, "//*[contains(string(), 'Show system objects?')]"))
)
self.page.find_by_css_selector(".ajs-dialog.pg-el-container .ajs-maximize").click()
browser = self.page.find_by_xpath(
"//*[contains(@class,'aciTreeLi') and contains(.,'Browser')]")
browser.find_element_by_xpath(
"//*[contains(@class,'aciTreeText') and contains(.,'Keyboard shortcuts')]") \
.click()
for s in self.new_shortcuts:
key = self.new_shortcuts[s]['shortcut'][2]
locator = self.new_shortcuts[s]['locator']
file_menu = self.page.find_by_xpath(
"//div[contains(@class,'pgadmin-control-group') and contains(.,'" + locator + "')]")
field = file_menu.find_element_by_name('key')
field.click()
field.send_keys(key)
# save and close the preference dialog.
self.page.find_by_xpath(
"//*[contains(@class,'pg-alertify-button') and contains(.,'OK')]").click()
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".ajs-modal")
)

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,8 @@ const EDIT_KEY = 71, // Key: G -> Grid values
F7_KEY = 118, F7_KEY = 118,
F8_KEY = 119, F8_KEY = 119,
PERIOD_KEY = 190, PERIOD_KEY = 190,
FWD_SLASH_KEY = 191; FWD_SLASH_KEY = 191,
ESC_KEY = 27;
function isMac() { function isMac() {
return window.navigator.platform.search('Mac') != -1; return window.navigator.platform.search('Mac') != -1;
@ -158,6 +159,8 @@ function keyboardShortcutsQueryTool(sqlEditorController, queryToolActions, event
panel_id = this.getInnerPanel( panel_id = this.getInnerPanel(
sqlEditorController.container, 'right' sqlEditorController.container, 'right'
); );
} else if (keyCode == ESC_KEY) {
queryToolActions.focusOut(sqlEditorController);
} }
return panel_id; return panel_id;
} }

View File

@ -96,6 +96,11 @@ let queryToolActions = {
{lineComment: '--'} {lineComment: '--'}
); );
}, },
focusOut: function() {
document.activeElement.blur();
window.top.document.activeElement.blur();
},
}; };
module.exports = queryToolActions; module.exports = queryToolActions;

View File

@ -143,6 +143,7 @@ var webpackShimConfig = {
'bignumber': path.join(__dirname, './node_modules/bignumber.js/bignumber'), 'bignumber': path.join(__dirname, './node_modules/bignumber.js/bignumber'),
'snap.svg': path.join(__dirname, './node_modules/snapsvg/dist/snap.svg'), 'snap.svg': path.join(__dirname, './node_modules/snapsvg/dist/snap.svg'),
'spectrum': path.join(__dirname, './node_modules/spectrum-colorpicker/spectrum'), 'spectrum': path.join(__dirname, './node_modules/spectrum-colorpicker/spectrum'),
'mousetrap': path.join(__dirname, './node_modules/mousetrap'),
// AciTree // AciTree
'jquery.acitree': path.join(__dirname, './node_modules/acitree/js/jquery.aciTree.min'), 'jquery.acitree': path.join(__dirname, './node_modules/acitree/js/jquery.aciTree.min'),
@ -259,6 +260,7 @@ var webpackShimConfig = {
'pgadmin.browser.frame': path.join(__dirname, './pgadmin/browser/static/js/frame'), 'pgadmin.browser.frame': path.join(__dirname, './pgadmin/browser/static/js/frame'),
'pgadmin.node.type': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type'), 'pgadmin.node.type': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type'),
'pgadmin.file_manager': path.join(__dirname, './pgadmin/misc/file_manager/static/js/file_manager'), 'pgadmin.file_manager': path.join(__dirname, './pgadmin/misc/file_manager/static/js/file_manager'),
'pgadmin.browser.keyboard': path.join(__dirname, './pgadmin/browser/static/js/keyboard'),
}, },
externals: [ externals: [
'pgadmin.user_management.current_user', 'pgadmin.user_management.current_user',

View File

@ -4895,6 +4895,10 @@ moment-timezone@^0.4.0:
version "2.18.1" version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
mousetrap@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.1.tgz#2a085f5c751294c75e7e81f6ec2545b29cbf42d9"
mozjpeg@^4.0.0: mozjpeg@^4.0.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/mozjpeg/-/mozjpeg-4.1.1.tgz#859030b24f689a53db9b40f0160d89195b88fd50" resolved "https://registry.yarnpkg.com/mozjpeg/-/mozjpeg-4.1.1.tgz#859030b24f689a53db9b40f0160d89195b88fd50"