Support tab navigation in dialogs. Fixes #2898

This commit is contained in:
Harshal Dhumal 2018-02-27 11:18:36 +00:00 committed by Dave Page
parent 3be22383b8
commit aa1849c13a
15 changed files with 485 additions and 92 deletions

View File

@ -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**

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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() {

View File

@ -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() {

View 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,
};

View 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);
}

View File

@ -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') !== '') {

View 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)) {

View File

@ -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);
},
};
});

View File

@ -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));
},
};

View File

@ -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') !== '') {

View 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();
});
});
});

View File

@ -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