mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-22 00:37:36 -06:00
Support tab navigation in dialogs. Fixes #2898
This commit is contained in:
parent
3be22383b8
commit
aa1849c13a
@ -10,36 +10,51 @@ desired.˝
|
||||
|
||||
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+] | |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+Q | Open the Query Tool in the current database |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+V | View Data in the selected table/view |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+C | Open the context menu |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+N | Create an object |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+E | Edit object properties |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+D | Delete the object |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
| Alt+Shift+G | Direct debugging |
|
||||
+---------------------------+--------------------------------------------------------+
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shortcut for all platforms | 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 |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+] | Move tabbed panel forward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+Q | Open the Query Tool in the current database |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+V | View Data in the selected table/view |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+C | Open the context menu |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+N | Create an object |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+E | Edit object properties |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+D | Delete the object |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Alt+Shift+G | Direct debugging |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
|
||||
|
||||
**Dialog tab shortcuts**
|
||||
|
||||
Use the shortcuts below to navigate the tabsets on dialogs:
|
||||
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shortcut for all platforms | Function |
|
||||
+============================+=======================================================+
|
||||
| Control+Shift+[ | Dialog tab backward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Control+Shift+] | Dialog tab forward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
|
||||
|
||||
**SQL Editors**
|
||||
|
||||
|
@ -433,6 +433,36 @@ class BrowserModule(PgAdminModule):
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_forward',
|
||||
gettext('Dialog tab forward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_backward',
|
||||
gettext('Dialog tab backward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
"""
|
||||
Returns:
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* eslint-disable */
|
||||
define(
|
||||
['underscore', 'underscore.string', 'sources/pgadmin', 'jquery', 'mousetrap'],
|
||||
function(_, S, pgAdmin, $, Mousetrap) {
|
||||
define(['underscore', 'underscore.string', 'sources/pgadmin', 'jquery', 'mousetrap',
|
||||
'sources/utils', 'sources/dialog_tab_navigator'],
|
||||
function(_, S, pgAdmin, $, Mousetrap, commonUtils, dialogTabNavigator) {
|
||||
'use strict';
|
||||
|
||||
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
@ -12,27 +11,26 @@ function(_, S, pgAdmin, $, Mousetrap) {
|
||||
init: function() {
|
||||
Mousetrap.reset();
|
||||
if (pgBrowser.preferences_cache.length > 0) {
|
||||
var getShortcut = this.parseShortcutValue;
|
||||
this.keyboardShortcut = {
|
||||
'file_shortcut': getShortcut(pgBrowser.get_preference('browser', 'main_menu_file').value),
|
||||
'object_shortcut': getShortcut(pgBrowser.get_preference('browser', 'main_menu_object').value),
|
||||
'tools_shortcut': getShortcut(pgBrowser.get_preference('browser', 'main_menu_tools').value),
|
||||
'help_shortcut': getShortcut(pgBrowser.get_preference('browser', 'main_menu_help').value),
|
||||
'left_tree_shortcut': getShortcut(pgBrowser.get_preference('browser', 'browser_tree').value),
|
||||
'tabbed_panel_backward': getShortcut(pgBrowser.get_preference('browser', 'tabbed_panel_backward').value),
|
||||
'tabbed_panel_forward': getShortcut(pgBrowser.get_preference('browser', 'tabbed_panel_forward').value),
|
||||
'sub_menu_query_tool': getShortcut(pgBrowser.get_preference('browser', 'sub_menu_query_tool').value),
|
||||
'sub_menu_view_data': getShortcut(pgBrowser.get_preference('browser', 'sub_menu_view_data').value),
|
||||
'sub_menu_properties': getShortcut(pgBrowser.get_preference('browser', 'sub_menu_properties').value),
|
||||
'sub_menu_create': getShortcut(pgBrowser.get_preference('browser', 'sub_menu_create').value),
|
||||
'sub_menu_delete': getShortcut(pgBrowser.get_preference('browser', 'sub_menu_delete').value),
|
||||
'context_menu': getShortcut(pgBrowser.get_preference('browser', 'context_menu').value),
|
||||
'direct_debugging': getShortcut(pgBrowser.get_preference('browser', 'direct_debugging').value)
|
||||
'file_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_file').value),
|
||||
'object_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_object').value),
|
||||
'tools_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_tools').value),
|
||||
'help_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'main_menu_help').value),
|
||||
'left_tree_shortcut': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'browser_tree').value),
|
||||
'tabbed_panel_backward': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_backward').value),
|
||||
'tabbed_panel_forward': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_forward').value),
|
||||
'sub_menu_query_tool': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_query_tool').value),
|
||||
'sub_menu_view_data': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_view_data').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_delete': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_delete').value),
|
||||
'context_menu': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'context_menu').value),
|
||||
'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value),
|
||||
};
|
||||
this.shortcutMethods = {
|
||||
'bindMainMenu': {'shortcuts': [this.keyboardShortcut.file_shortcut,
|
||||
this.keyboardShortcut.object_shortcut, this.keyboardShortcut.tools_shortcut,
|
||||
this.keyboardShortcut.help_shortcut]}, // Main menu
|
||||
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
|
||||
@ -44,9 +42,9 @@ function(_, S, pgAdmin, $, Mousetrap) {
|
||||
'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object,
|
||||
'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object,
|
||||
'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
|
||||
};
|
||||
this.bindShortcuts();
|
||||
this.bindShortcuts();
|
||||
}
|
||||
},
|
||||
bindShortcuts: function() {
|
||||
@ -71,6 +69,20 @@ function(_, S, pgAdmin, $, Mousetrap) {
|
||||
attachShortcut: function(shortcut, callback, bindElem) {
|
||||
this._bindWithMousetrap(shortcut, callback, bindElem);
|
||||
},
|
||||
attachDialogTabNavigatorShortcut: function(dialogTabNavigator, shortcuts) {
|
||||
var callback = dialogTabNavigator.on_keyboard_event,
|
||||
domElem = dialogTabNavigator.dialog.el;
|
||||
|
||||
if (domElem) {
|
||||
Mousetrap(domElem).bind(shortcuts, function() {
|
||||
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);
|
||||
@ -211,18 +223,18 @@ function(_, S, pgAdmin, $, Mousetrap) {
|
||||
},
|
||||
bindContextMenu: function(e) {
|
||||
var tree = this.getTreeDetails(),
|
||||
e = window.event,
|
||||
left = $(e.srcElement).find('.aciTreeEntry').position().left + 70,
|
||||
top = $(e.srcElement).find('.aciTreeEntry').position().top + 70;
|
||||
left = $(e.srcElement).find('.aciTreeEntry').position().left + 70,
|
||||
top = $(e.srcElement).find('.aciTreeEntry').position().top + 70;
|
||||
e = window.event;
|
||||
|
||||
tree.t.blur(tree.i);
|
||||
$('#tree').blur();
|
||||
// Call context menu and set position
|
||||
var ctx = tree.i.children().contextMenu({x: left, y:top});
|
||||
tree.i.children().contextMenu({x: left, y:top});
|
||||
},
|
||||
bindDirectDebugging: function(e) {
|
||||
bindDirectDebugging: function() {
|
||||
var tree = this.getTreeDetails(),
|
||||
type = tree.t.itemData(tree.i)._type;
|
||||
type = tree.t.itemData(tree.i)._type;
|
||||
|
||||
if (!tree.d || (type != 'function' && type != 'procedure'))
|
||||
return;
|
||||
@ -232,26 +244,23 @@ function(_, S, pgAdmin, $, Mousetrap) {
|
||||
pgAdmin.Tools.Debugger.get_function_information(pgAdmin.Browser.Nodes[type]);
|
||||
}
|
||||
},
|
||||
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;
|
||||
},
|
||||
getTreeDetails: function() {
|
||||
var t = pgAdmin.Browser.tree,
|
||||
i = t.selected().length > 0 ? t.selected() : t.first(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
i = t.selected().length > 0 ? t.selected() : t.first(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
return {
|
||||
t: t,
|
||||
i: i,
|
||||
d: d
|
||||
}
|
||||
}
|
||||
d: d,
|
||||
};
|
||||
},
|
||||
getDialogTabNavigator: function(dialog) {
|
||||
var backward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_backward').value,
|
||||
forward_shortcut = pgBrowser.get_preference('browser', 'dialog_tab_forward').value;
|
||||
|
||||
return new dialogTabNavigator.dialogTabNavigator(dialog, backward_shortcut, forward_shortcut);
|
||||
},
|
||||
});
|
||||
|
||||
return pgAdmin.keyboardNavigation;
|
||||
|
@ -1,8 +1,9 @@
|
||||
define('pgadmin.browser.node', [
|
||||
'sources/gettext', 'jquery', 'underscore', 'underscore.string', 'sources/pgadmin',
|
||||
'pgadmin.browser.menu', 'backbone', 'pgadmin.alertifyjs', 'pgadmin.browser.datamodel',
|
||||
'backform', 'sources/browser/generate_url', 'pgadmin.browser.utils', 'pgadmin.backform',
|
||||
], function(gettext, $, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform, generateUrl) {
|
||||
'backform', 'sources/browser/generate_url', 'sources/utils', 'pgadmin.browser.utils',
|
||||
'pgadmin.backform',
|
||||
], function(gettext, $, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform, generateUrl, commonUtils) {
|
||||
|
||||
var wcDocker = window.wcDocker,
|
||||
keyCode = {
|
||||
@ -365,9 +366,8 @@ define('pgadmin.browser.node', [
|
||||
}
|
||||
|
||||
var setFocusOnEl = function() {
|
||||
setTimeout(function() {
|
||||
$(el).find('.tab-pane.active:first').find('input:first').focus();
|
||||
}, 500);
|
||||
var container = $(el).find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
};
|
||||
|
||||
if (!newModel.isNew()) {
|
||||
@ -394,6 +394,8 @@ define('pgadmin.browser.node', [
|
||||
view.render();
|
||||
setFocusOnEl();
|
||||
newModel.startNewSession();
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
},
|
||||
error: function(xhr, error, message) {
|
||||
var _label = that && item ?
|
||||
@ -430,8 +432,11 @@ define('pgadmin.browser.node', [
|
||||
view.render();
|
||||
setFocusOnEl();
|
||||
newModel.startNewSession();
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
define([
|
||||
'underscore', 'jquery', 'backbone', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'sources/gettext',
|
||||
], function(_, $, Backbone, pgAdmin, pgBrowser, gettext) {
|
||||
'sources/gettext', 'sources/utils',
|
||||
], function(_, $, Backbone, pgAdmin, pgBrowser, gettext, commonUtils) {
|
||||
|
||||
var wcDocker = window.wcDocker;
|
||||
|
||||
@ -157,7 +157,8 @@ define([
|
||||
this.currPage = this.collection.at(this.options.curr_page).toJSON();
|
||||
},
|
||||
render: function() {
|
||||
var data = this.currPage;
|
||||
var self = this,
|
||||
data = this.currPage;
|
||||
|
||||
/* Check Status of the buttons */
|
||||
this.options.disable_next = (this.options.disable_next ? true : this.evalASFunc(this.currPage.disable_next));
|
||||
@ -179,6 +180,11 @@ define([
|
||||
/* OnLoad Callback */
|
||||
this.onLoad();
|
||||
|
||||
setTimeout(function() {
|
||||
var container = $(self.el);
|
||||
commonUtils.findAndSetFocus(container);
|
||||
}, 100);
|
||||
|
||||
return this;
|
||||
},
|
||||
nextPage: function() {
|
||||
|
@ -500,12 +500,12 @@ define([
|
||||
template: {
|
||||
'header': _.template([
|
||||
'<li role="presentation" <%=disabled ? "disabled" : ""%>>',
|
||||
' <a data-toggle="tab" data-tab-index="<%=tabIndex%>" href="#<%=cId%>"',
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="<%=tabIndex%>" href="#<%=cId%>"',
|
||||
' id="<%=hId%>" aria-controls="<%=cId%>">',
|
||||
'<%=label%></a></li>',
|
||||
].join(' ')),
|
||||
'panel': _.template(
|
||||
'<div role="tabpanel" class="tab-pane <%=label%> pg-el-sm-12 pg-el-md-12 pg-el-lg-12 pg-el-xs-12 fade" id="<%=cId%>" aria-labelledby="<%=hId%>"></div>'
|
||||
'<div role="tabpanel" tabindex="-1" class="tab-pane <%=label%> pg-el-sm-12 pg-el-md-12 pg-el-lg-12 pg-el-xs-12 fade" id="<%=cId%>" aria-labelledby="<%=hId%>"></div>'
|
||||
),
|
||||
},
|
||||
render: function() {
|
||||
|
143
web/pgadmin/static/js/dialog_tab_navigator.js
Normal file
143
web/pgadmin/static/js/dialog_tab_navigator.js
Normal file
@ -0,0 +1,143 @@
|
||||
import $ from 'jquery';
|
||||
import Mousetrap from 'mousetrap';
|
||||
import { findAndSetFocus } from './utils';
|
||||
import { parseShortcutValue } from './utils';
|
||||
|
||||
class dialogTabNavigator {
|
||||
constructor(dialog, backwardShortcut, forwardShortcut) {
|
||||
|
||||
this.dialog = dialog;
|
||||
|
||||
this.tabSwitching = false;
|
||||
|
||||
this.tabs = this.dialog.$el.find('.nav-tabs');
|
||||
|
||||
if (this.tabs.length > 0 ) {
|
||||
this.tabs = this.tabs[0];
|
||||
}
|
||||
|
||||
this.dialogTabBackward = parseShortcutValue(backwardShortcut);
|
||||
this.dialogTabForward = parseShortcutValue(forwardShortcut);
|
||||
|
||||
Mousetrap(this.dialog.el).bind(this.dialogTabBackward, this.onKeyboardEvent.bind(this));
|
||||
Mousetrap(this.dialog.el).bind(this.dialogTabForward, this.onKeyboardEvent.bind(this));
|
||||
|
||||
}
|
||||
|
||||
onKeyboardEvent(event, shortcut) {
|
||||
var currentTabPane = this.dialog.$el
|
||||
.find('.tab-content:first > .tab-pane.active:first'),
|
||||
childTabData = this.isActivePaneHasChildTabs(currentTabPane);
|
||||
|
||||
if (this.tabSwitching) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.tabSwitching = true;
|
||||
|
||||
if(childTabData) {
|
||||
var res = this.navigate(shortcut, childTabData.childTab,
|
||||
childTabData.childTabPane);
|
||||
|
||||
if (!res) {
|
||||
this.navigate(shortcut, this.tabs, currentTabPane);
|
||||
}
|
||||
} else {
|
||||
this.navigate(shortcut, this.tabs, currentTabPane);
|
||||
}
|
||||
}
|
||||
|
||||
isActivePaneHasChildTabs(currentTabPane) {
|
||||
var childTab = currentTabPane.find('.nav-tabs:first'),
|
||||
childTabPane;
|
||||
|
||||
if (childTab.length > 0) {
|
||||
childTabPane = currentTabPane
|
||||
.find('.tab-content:first > .tab-pane.active:first');
|
||||
|
||||
return {
|
||||
'childTab': childTab,
|
||||
'childTabPane': childTabPane,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
navigate(shortcut, tabs, tab_pane) {
|
||||
if(shortcut == this.dialogTabBackward) {
|
||||
return this.navigateBackward(tabs, tab_pane);
|
||||
}else if (shortcut == this.dialogTabForward) {
|
||||
return this.navigateForward(tabs, tab_pane);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
navigateBackward(tabs, tab_pane) {
|
||||
var self = this,
|
||||
nextTabPane,
|
||||
innerTabContainer,
|
||||
prevtab = $(tabs).find('li.active').prev('li');
|
||||
|
||||
if (prevtab.length > 0) {
|
||||
prevtab.find('a').tab('show');
|
||||
|
||||
nextTabPane = tab_pane.prev();
|
||||
innerTabContainer = nextTabPane
|
||||
.find('.tab-content:first > .tab-pane.active:first');
|
||||
|
||||
if (innerTabContainer.length > 0) {
|
||||
findAndSetFocus(innerTabContainer);
|
||||
} else {
|
||||
findAndSetFocus(nextTabPane);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
self.tabSwitching = false;
|
||||
}, 200);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
this.tabSwitching = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
navigateForward(tabs, tab_pane) {
|
||||
var self = this,
|
||||
nextTabPane,
|
||||
innerTabContainer,
|
||||
nexttab = $(tabs).find('li.active').next('li');
|
||||
|
||||
if(nexttab.length > 0) {
|
||||
nexttab.find('a').tab('show');
|
||||
|
||||
nextTabPane = tab_pane.next();
|
||||
innerTabContainer = nextTabPane
|
||||
.find('.tab-content:first > .tab-pane.active:first');
|
||||
|
||||
if (innerTabContainer.length > 0) {
|
||||
findAndSetFocus(innerTabContainer);
|
||||
} else {
|
||||
findAndSetFocus(nextTabPane);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
self.tabSwitching = false;
|
||||
}, 200);
|
||||
|
||||
return true;
|
||||
}
|
||||
this.tabSwitching = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
detach() {
|
||||
Mousetrap(this.dialog.el).unbind(this.dialogTabBackward);
|
||||
Mousetrap(this.dialog.el).unbind(this.dialogTabForward);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dialogTabNavigator: dialogTabNavigator,
|
||||
};
|
38
web/pgadmin/static/js/utils.js
Normal file
38
web/pgadmin/static/js/utils.js
Normal file
@ -0,0 +1,38 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
export function parseShortcutValue(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;
|
||||
}
|
||||
|
||||
export function findAndSetFocus(container) {
|
||||
if (container.length == 0) {
|
||||
return;
|
||||
}
|
||||
setTimeout(function() {
|
||||
var first_el = container
|
||||
.find('button.fa-plus:first');
|
||||
|
||||
if (first_el.length == 0) {
|
||||
first_el = container
|
||||
.find('.pgadmin-controls:first>input:enabled,.CodeMirror-scroll');
|
||||
}
|
||||
|
||||
if(first_el.length > 0) {
|
||||
first_el[0].focus();
|
||||
} else {
|
||||
container[0].focus();
|
||||
}
|
||||
}, 200);
|
||||
}
|
@ -2,9 +2,10 @@
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'backbone', 'pgadmin.backgrid',
|
||||
'pgadmin.backform', 'pgadmin.browser',
|
||||
'pgadmin.backform', 'pgadmin.browser', 'sources/utils',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, alertify, Backbone, Backgrid, Backform, pgBrowser
|
||||
gettext, url_for, $, _, S, alertify, Backbone, Backgrid, Backform, pgBrowser,
|
||||
commonUtils
|
||||
) {
|
||||
|
||||
// if module is already initialized, refer to that.
|
||||
@ -696,6 +697,9 @@ define([
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
@ -940,6 +944,13 @@ define([
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
if(view) {
|
||||
view.$el.attr('tabindex', -1);
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
}
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
|
@ -89,8 +89,10 @@ define([
|
||||
cell: Backgrid.Extension.SelectRowCell.extend({
|
||||
render: function() {
|
||||
|
||||
// Use the Backform Control's render function
|
||||
Backgrid.Extension.SelectRowCell.prototype.render.apply(this, arguments);
|
||||
// Do not use parent's render function. It set's tabindex to -1 on
|
||||
// checkboxes.
|
||||
this.$el.empty().append('<input type="checkbox" />');
|
||||
this.delegateEvents();
|
||||
|
||||
var col = this.column.get('name');
|
||||
if (this.model && this.model.has(col)) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'underscore.string', 'pgadmin.alertifyjs',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'backbone', 'backgrid', 'backform',
|
||||
'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui',
|
||||
'sources/utils', 'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid, Backform
|
||||
gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
|
||||
Backform, commonUtils
|
||||
) {
|
||||
|
||||
pgAdmin = pgAdmin || window.pgAdmin || {};
|
||||
@ -652,6 +653,12 @@ define([
|
||||
// Give the dialog initial height & width
|
||||
this.elements.dialog.style.minHeight = '80%';
|
||||
this.elements.dialog.style.minWidth = '70%';
|
||||
|
||||
view.$el.attr('tabindex', -1);
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'sources/pgadmin', 'pgadmin.browser', 'backbone',
|
||||
'backgrid', 'backform',
|
||||
'backgrid', 'backform', 'sources/utils',
|
||||
'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.browser.node.ui',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
|
||||
Backform
|
||||
Backform, commonUtils
|
||||
) {
|
||||
|
||||
pgAdmin = pgAdmin || window.pgAdmin || {};
|
||||
@ -468,6 +468,10 @@ define([
|
||||
$(reindex_btn).addClass('active');
|
||||
}
|
||||
|
||||
view.$el.attr('tabindex', -1);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
},
|
||||
};
|
||||
|
@ -2,9 +2,10 @@
|
||||
define('tools.restore', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'pgadmin.browser',
|
||||
'pgadmin.backgrid', 'pgadmin.backform',
|
||||
'pgadmin.backgrid', 'pgadmin.backform', 'sources/utils',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, S, alertify, pgBrowser, Backgrid, Backform
|
||||
gettext, url_for, $, _, Backbone, S, alertify, pgBrowser, Backgrid, Backform,
|
||||
commonUtils
|
||||
) {
|
||||
|
||||
// if module is already initialized, refer to that.
|
||||
@ -572,6 +573,12 @@ define('tools.restore', [
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
view.$el.attr('tabindex', -1);
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
|
115
web/regression/javascript/dialog_tab_navigator_spec.js
Normal file
115
web/regression/javascript/dialog_tab_navigator_spec.js
Normal file
@ -0,0 +1,115 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
import dialogTabNavigator from 'sources/dialog_tab_navigator';
|
||||
import $ from 'jquery';
|
||||
import 'bootstrap';
|
||||
|
||||
describe('dialogTabNavigator', function () {
|
||||
let dialog, tabNavigator, backward_shortcut, forward_shortcut;
|
||||
|
||||
beforeEach(() => {
|
||||
let dialogHtml =$('<div tabindex="1" class="backform-tab" role="tabpanel">'+
|
||||
' <ul class="nav nav-tabs" role="tablist">'+
|
||||
' <li role="presentation" class="active">'+
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="1" href="#1" aria-controls="1"> General</a>'+
|
||||
' </li>'+
|
||||
' <li role="presentation">'+
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="5" href="#2" aria-controls="2"> Default Privileges</a>'+
|
||||
' </li>'+
|
||||
' <li role="presentation">'+
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="6" href="#3" aria-controls="3"> SQL</a>'+
|
||||
' </li>'+
|
||||
' </ul>'+
|
||||
' <ul class="tab-content">'+
|
||||
' <div role="tabpanel" tabindex="-1" class="tab-pane fade collapse in active" id="1">'+
|
||||
' </div>'+
|
||||
' <div role="tabpanel" tabindex="-1" class="tab-pane fade collapse" id="2">'+
|
||||
' <div class="inline-tab-panel" role="tabpanel">'+
|
||||
' <ul class="nav nav-tabs" role="tablist">'+
|
||||
' <li role="presentation" class="active">'+
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="601" href="#11" aria-controls="11"> Tables</a>'+
|
||||
' </li>'+
|
||||
' <li role="presentation">'+
|
||||
' <a data-toggle="tab" tabindex="-1" data-tab-index="602" href="#22" aria-controls="22"> Sequences</a>'+
|
||||
' </li>'+
|
||||
' </ul>'+
|
||||
' <ul class="tab-content">'+
|
||||
' <div role="tabpanel" tabindex="-1" class="tab-pane fade collapse in active" id="11" >'+
|
||||
' </div>'+
|
||||
' <div role="tabpanel" tabindex="-1" class="tab-pane fade collapse" id="22">'+
|
||||
' </div>'+
|
||||
' </ul>'+
|
||||
' </div>'+
|
||||
' </div>'+
|
||||
' <div role="tabpanel" tabindex="-1" class="tab-pane fade collapse" id="3">'+
|
||||
' </div>'+
|
||||
' </ul>'+
|
||||
'</div>');
|
||||
|
||||
dialog = {};
|
||||
|
||||
dialog.el = dialogHtml[0];
|
||||
dialog.$el = dialogHtml;
|
||||
|
||||
backward_shortcut = {
|
||||
'alt': false,
|
||||
'shift': true,
|
||||
'control': true,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
};
|
||||
|
||||
forward_shortcut = {
|
||||
'alt': false,
|
||||
'shift': true,
|
||||
'control': true,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
};
|
||||
|
||||
tabNavigator = new dialogTabNavigator.dialogTabNavigator(
|
||||
dialog, backward_shortcut, forward_shortcut);
|
||||
});
|
||||
|
||||
describe('navigate', function () {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(tabNavigator, 'navigateBackward').and.callThrough();
|
||||
|
||||
spyOn(tabNavigator, 'navigateForward').and.callThrough();
|
||||
});
|
||||
|
||||
it('navigate backward', function () {
|
||||
tabNavigator.onKeyboardEvent({}, 'shift+ctrl+[');
|
||||
|
||||
expect(tabNavigator.navigateBackward).toHaveBeenCalled();
|
||||
|
||||
expect(tabNavigator.navigateForward).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('navigate forward', function () {
|
||||
tabNavigator.onKeyboardEvent({}, 'shift+ctrl+]');
|
||||
|
||||
expect(tabNavigator.navigateForward).toHaveBeenCalled();
|
||||
|
||||
expect(tabNavigator.navigateBackward).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('should not navigate', function () {
|
||||
tabNavigator.onKeyboardEvent({}, 'shift+ctrl+a');
|
||||
|
||||
expect(tabNavigator.navigateForward).not.toHaveBeenCalled();
|
||||
|
||||
expect(tabNavigator.navigateBackward).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -126,6 +126,7 @@ var webpackShimConfig = {
|
||||
'pgadmin': path.join(__dirname, './pgadmin/static/js/pgadmin'),
|
||||
'translations': path.join(__dirname, './pgadmin/tools/templates/js/translations'),
|
||||
'sources/gettext': path.join(__dirname, './pgadmin/static/js/gettext'),
|
||||
'sources/utils': path.join(__dirname, './pgadmin/static/js/utils'),
|
||||
'babel-polyfill': path.join(__dirname, './node_modules/babel-polyfill/dist/polyfill'),
|
||||
|
||||
// Vendor JS
|
||||
|
Loading…
Reference in New Issue
Block a user