mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-27 00:36:52 -06:00
365 lines
12 KiB
JavaScript
365 lines
12 KiB
JavaScript
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
import $ from 'jquery';
|
|
import gettext from 'sources/gettext';
|
|
import { getMod } from 'sources/utils';
|
|
|
|
const PERIOD_KEY = 190,
|
|
FWD_SLASH_KEY = 191,
|
|
ESC_KEY = 27,
|
|
LEFT_KEY = 37,
|
|
UP_KEY = 38,
|
|
RIGHT_KEY = 39,
|
|
DOWN_KEY = 40,
|
|
K_KEY = 75;
|
|
|
|
function isMac() {
|
|
return window.navigator.platform.search('Mac') != -1;
|
|
}
|
|
|
|
function isKeyCtrlAlt(event) {
|
|
return event.ctrlKey || event.altKey;
|
|
}
|
|
|
|
function isKeyAltShift(event) {
|
|
return event.altKey || event.shiftKey;
|
|
}
|
|
|
|
function isKeyCtrlShift(event) {
|
|
return event.ctrlKey || event.shiftKey;
|
|
}
|
|
|
|
function isKeyCtrlAltShift(event) {
|
|
return event.ctrlKey || event.altKey || event.shiftKey;
|
|
}
|
|
|
|
function isAltShiftBoth(event) {
|
|
return event.altKey && event.shiftKey && !event.ctrlKey;
|
|
}
|
|
|
|
function isCtrlShiftBoth(event) {
|
|
return event.ctrlKey && event.shiftKey && !event.altKey;
|
|
}
|
|
|
|
function isCtrlAltBoth(event) {
|
|
return event.ctrlKey && event.altKey && !event.shiftKey;
|
|
}
|
|
|
|
/* Returns the key of shortcut */
|
|
function shortcut_key(shortcut) {
|
|
let key = '';
|
|
if(shortcut['key'] && shortcut['key']['char']) {
|
|
key = shortcut['key']['char'].toUpperCase();
|
|
}
|
|
return key;
|
|
}
|
|
|
|
/* Converts shortcut object to title representation
|
|
* Shortcut object is browser.get_preference().value
|
|
*/
|
|
function shortcut_title(title, shortcut) {
|
|
let text_representation = '';
|
|
|
|
if (typeof shortcut === 'undefined' || shortcut === null) {
|
|
return text_representation;
|
|
}
|
|
if(shortcut['alt']) {
|
|
text_representation = gettext('Alt') + '+';
|
|
}
|
|
if(shortcut['shift']) {
|
|
text_representation += gettext('Shift') + '+';
|
|
}
|
|
if(shortcut['control']) {
|
|
text_representation += gettext('Ctrl') + '+';
|
|
}
|
|
text_representation += shortcut_key(shortcut);
|
|
|
|
return `${title} (${text_representation})`;
|
|
}
|
|
|
|
/* Returns the key char of shortcut
|
|
* shortcut object is browser.get_preference().value
|
|
*/
|
|
function shortcut_accesskey_title(title, shortcut) {
|
|
return `${title} (` + gettext('accesskey') + ` + ${shortcut_key(shortcut)})`;
|
|
}
|
|
|
|
|
|
function _stopEventPropagation(event) {
|
|
event.cancelBubble = true;
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
event.stopImmediatePropagation();
|
|
}
|
|
|
|
/* Function use to validate shortcut keys */
|
|
function validateShortcutKeys(user_defined_shortcut, event) {
|
|
if(!user_defined_shortcut) {
|
|
return false;
|
|
}
|
|
|
|
let keyCode = event.which || event.keyCode;
|
|
return user_defined_shortcut.alt == event.altKey &&
|
|
user_defined_shortcut.shift == event.shiftKey &&
|
|
user_defined_shortcut.control == event.ctrlKey &&
|
|
user_defined_shortcut.key.key_code == keyCode;
|
|
}
|
|
|
|
// Finds the desired panel on which user wants to navigate to
|
|
function focusDockerPanel(docker, op) {
|
|
if(!docker) {
|
|
return;
|
|
}
|
|
|
|
// If no frame in focus, focus the first one
|
|
if(!docker._focusFrame) {
|
|
if(docker._frameList.length == 0 && docker._frameList[0]._panelList.length == 0) {
|
|
return;
|
|
}
|
|
docker._frameList[0]._panelList[docker._frameList[0]._curTab].focus();
|
|
}
|
|
|
|
let focus_frame = docker._focusFrame,
|
|
focus_id = 0,
|
|
flash = false;
|
|
|
|
// Mod is used to cycle the op
|
|
if (op == 'switch') {
|
|
let i, total_frames = docker._frameList.length;
|
|
|
|
for(i = 0; i < total_frames; i++) {
|
|
if(focus_frame === docker._frameList[i]) break;
|
|
}
|
|
focus_frame = docker._frameList[getMod(i+1,total_frames)];
|
|
focus_id = focus_frame._curTab;
|
|
flash = true;
|
|
} else if (op == 'left') {
|
|
focus_id = getMod(focus_frame._curTab-1, focus_frame._panelList.length);
|
|
} else if (op == 'right') {
|
|
focus_id = getMod(focus_frame._curTab+1, focus_frame._panelList.length);
|
|
}
|
|
|
|
let focus_panel = focus_frame._panelList[focus_id];
|
|
|
|
focus_panel.$container.find('*[tabindex]:not([tabindex="-1"])').trigger('focus');
|
|
focus_panel.focus(flash);
|
|
return focus_panel._type;
|
|
}
|
|
|
|
/* Debugger: Keyboard Shortcuts handling */
|
|
function keyboardShortcutsDebugger($el, event, preferences, docker) {
|
|
let panel_type = '', panel_content, $input;
|
|
|
|
if(this.validateShortcutKeys(preferences.edit_grid_values, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_content = $el.find(
|
|
'div.wcPanelTabContent:not(".wcPanelTabContentHidden")'
|
|
);
|
|
if(panel_content.length) {
|
|
$input = $(panel_content).find('td.editable:first');
|
|
if($input.length)
|
|
$input.trigger('click');
|
|
}
|
|
} else if(this.validateShortcutKeys(preferences.move_next, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'right');
|
|
} else if(this.validateShortcutKeys(preferences.move_previous, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'left');
|
|
} else if(this.validateShortcutKeys(preferences.switch_panel, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'switch');
|
|
}
|
|
return panel_type;
|
|
}
|
|
|
|
/* Query tool: Keyboard Shortcuts handling */
|
|
function keyboardShortcutsQueryTool(
|
|
sqlEditorController, queryToolActions, event, docker
|
|
) {
|
|
if (sqlEditorController.isQueryRunning()) {
|
|
return;
|
|
}
|
|
let keyCode = event.which || event.keyCode, panel_type = '';
|
|
let executeKeys = sqlEditorController.preferences.execute_query;
|
|
let explainKeys = sqlEditorController.preferences.explain_query;
|
|
let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query;
|
|
let downloadCsvKeys = sqlEditorController.preferences.download_results;
|
|
let nextTabKeys = sqlEditorController.preferences.move_next;
|
|
let previousTabKeys = sqlEditorController.preferences.move_previous;
|
|
let switchPanelKeys = sqlEditorController.preferences.switch_panel;
|
|
let toggleCaseKeys = sqlEditorController.preferences.toggle_case;
|
|
let commitKeys = sqlEditorController.preferences.commit_transaction;
|
|
let rollbackKeys = sqlEditorController.preferences.rollback_transaction;
|
|
let saveDataKeys = sqlEditorController.preferences.save_data;
|
|
let queryToolKeys = sqlEditorController.preferences.show_query_tool;
|
|
|
|
if (this.validateShortcutKeys(executeKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.executeQuery(sqlEditorController);
|
|
} else if (this.validateShortcutKeys(explainKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.explain(sqlEditorController);
|
|
} else if (this.validateShortcutKeys(explainAnalyzeKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.explainAnalyze(sqlEditorController);
|
|
} else if (this.validateShortcutKeys(downloadCsvKeys, event)) {
|
|
if(!sqlEditorController.is_save_results_to_file_disabled) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.download(sqlEditorController);
|
|
}
|
|
} else if (this.validateShortcutKeys(toggleCaseKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.toggleCaseOfSelectedText(sqlEditorController);
|
|
} else if (this.validateShortcutKeys(commitKeys, event)) {
|
|
// If transaction buttons are disabled then no need to execute commit.
|
|
if (!sqlEditorController.is_transaction_buttons_disabled) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.executeCommit(sqlEditorController);
|
|
}
|
|
} else if (this.validateShortcutKeys(rollbackKeys, event)) {
|
|
// If transaction buttons are disabled then no need to execute rollback.
|
|
if (!sqlEditorController.is_transaction_buttons_disabled) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.executeRollback(sqlEditorController);
|
|
}
|
|
} else if (this.validateShortcutKeys(saveDataKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.saveDataChanges(sqlEditorController);
|
|
} else if (this.validateShortcutKeys(queryToolKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.openQueryTool(sqlEditorController);
|
|
} else if ((
|
|
(this.isMac() && event.metaKey) ||
|
|
(!this.isMac() && event.ctrlKey)
|
|
) && !event.altKey && event.shiftKey && keyCode === FWD_SLASH_KEY) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.commentBlockCode(sqlEditorController);
|
|
} else if ((
|
|
(this.isMac() && !this.isKeyCtrlAltShift(event) && event.metaKey) ||
|
|
(!this.isMac() && !this.isKeyAltShift(event) && event.ctrlKey)
|
|
) && keyCode === FWD_SLASH_KEY) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.commentLineCode(sqlEditorController);
|
|
} else if ((
|
|
(this.isMac() && !this.isKeyCtrlAltShift(event) && event.metaKey) ||
|
|
(!this.isMac() && !this.isKeyAltShift(event) && event.ctrlKey)
|
|
) && keyCode === PERIOD_KEY) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.uncommentLineCode(sqlEditorController);
|
|
} else if ((
|
|
(this.isMac() && event.metaKey) ||
|
|
(!this.isMac() && event.ctrlKey)
|
|
) && !event.altKey && event.shiftKey && keyCode === K_KEY) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.formatSql(sqlEditorController);
|
|
} else if (keyCode == ESC_KEY) {
|
|
queryToolActions.focusOut(sqlEditorController);
|
|
/*Apply only for sub-dropdown*/
|
|
if($(event.target).hasClass('dropdown-item')
|
|
&& $(event.target).closest('.dropdown-submenu').length > 0) {
|
|
$(event.target).closest('.dropdown-submenu').find('.dropdown-menu').removeClass('show');
|
|
}
|
|
} else if(this.validateShortcutKeys(nextTabKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'right');
|
|
} else if(this.validateShortcutKeys(previousTabKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'left');
|
|
} else if(this.validateShortcutKeys(switchPanelKeys, event)) {
|
|
this._stopEventPropagation(event);
|
|
panel_type = focusDockerPanel(docker, 'switch');
|
|
} else if(keyCode === UP_KEY || keyCode === DOWN_KEY) {
|
|
/*Apply only for dropdown*/
|
|
if($(event.target).closest('.dropdown-menu').length > 0) {
|
|
this._stopEventPropagation(event);
|
|
let currLi = $(event.target).closest('li');
|
|
/*close all the submenus on movement*/
|
|
$(event.target).closest('.dropdown-menu').find('.show').removeClass('show');
|
|
|
|
if(keyCode === UP_KEY) {
|
|
currLi = currLi.prev();
|
|
}
|
|
else if(keyCode === DOWN_KEY){
|
|
currLi = currLi.next();
|
|
}
|
|
|
|
/*do not focus on divider, disabled and d-none */
|
|
while(currLi.hasClass('dropdown-divider')
|
|
|| currLi.hasClass('d-none')
|
|
|| currLi.find('.dropdown-item').first().hasClass('disabled')) {
|
|
if(keyCode === UP_KEY) {
|
|
currLi = currLi.prev();
|
|
}
|
|
else if(keyCode === DOWN_KEY){
|
|
currLi = currLi.next();
|
|
}
|
|
}
|
|
currLi.find('.dropdown-item').trigger('focus');
|
|
}
|
|
} else if(keyCode === LEFT_KEY || keyCode === RIGHT_KEY) {
|
|
/*Apply only for dropdown*/
|
|
if($(event.target).closest('.dropdown-menu').length > 0) {
|
|
this._stopEventPropagation(event);
|
|
let currLi = $(event.target).closest('li');
|
|
|
|
if(keyCode === RIGHT_KEY) {
|
|
/*open submenu if any*/
|
|
if(currLi.hasClass('dropdown-submenu')){
|
|
currLi.find('.dropdown-menu').addClass('show');
|
|
currLi.find('.dropdown-menu .dropdown-item').first().trigger('focus');
|
|
}
|
|
} else if(keyCode === LEFT_KEY) {
|
|
/*close submenu*/
|
|
let currMenu = currLi.closest('.dropdown-menu');
|
|
if(currMenu.closest('.dropdown-submenu').length > 0) {
|
|
currMenu.removeClass('show');
|
|
currLi = currMenu.closest('.dropdown-submenu');
|
|
currLi.find('.dropdown-item').trigger('focus');
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Macros
|
|
let macroId = this.validateMacros(sqlEditorController, event);
|
|
|
|
if (macroId !== false) {
|
|
this._stopEventPropagation(event);
|
|
queryToolActions.executeMacro(sqlEditorController, macroId);
|
|
}
|
|
}
|
|
|
|
return panel_type;
|
|
}
|
|
|
|
function validateMacros(sqlEditorController, event) {
|
|
let keyCode = event.which || event.keyCode;
|
|
|
|
let macro = sqlEditorController.macros.filter(mc =>
|
|
mc.alt == event.altKey &&
|
|
mc.control == event.ctrlKey &&
|
|
mc.key_code == keyCode);
|
|
|
|
if (macro.length == 1) {
|
|
return macro[0].id;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export {
|
|
keyboardShortcutsDebugger as processEventDebugger,
|
|
keyboardShortcutsQueryTool as processEventQueryTool,
|
|
focusDockerPanel, validateShortcutKeys, validateMacros,
|
|
_stopEventPropagation, isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
|
|
isKeyCtrlAltShift, isAltShiftBoth, isCtrlShiftBoth, isCtrlAltBoth,
|
|
shortcut_key, shortcut_title, shortcut_accesskey_title,
|
|
};
|