diff --git a/client/src/views/modal.js b/client/src/views/modal.js
index f9950ad316..359c813653 100644
--- a/client/src/views/modal.js
+++ b/client/src/views/modal.js
@@ -375,10 +375,10 @@ define('views/modal', ['view'], function (Dep) {
setupFinal: function () {
if (this.shortcutKeys) {
this.events['keydown.modal-base'] = e => {
- let key = e.key.toLowerCase();
+ let key = e.code;
if (e.ctrlKey) {
- key = 'ctrl+' + key;
+ key = 'Control+' + key;
}
if (typeof this.shortcutKeys[key] === 'function') {
diff --git a/client/src/views/modals/detail.js b/client/src/views/modals/detail.js
index 3c7898cbcf..f3852056ac 100644
--- a/client/src/views/modals/detail.js
+++ b/client/src/views/modals/detail.js
@@ -67,7 +67,7 @@ define('views/modals/detail', ['views/modal', 'helpers/action-item-setup'], func
duplicateAction: false,
shortcutKeys: {
- 'e': function (e) {
+ 'KeyE': function (e) {
if (this.editDisabled) {
return;
}
@@ -82,7 +82,7 @@ define('views/modals/detail', ['views/modal', 'helpers/action-item-setup'], func
this.actionEdit()
.then(view => {
view.$el
- .find('.form-control:not([disabled])')
+ .find('.middle-tabs > button.active, .form-control, .form-control:not([disabled])')
.first()
.focus();
});
diff --git a/client/src/views/modals/edit.js b/client/src/views/modals/edit.js
index e4727736b5..492404af9b 100644
--- a/client/src/views/modals/edit.js
+++ b/client/src/views/modals/edit.js
@@ -58,6 +58,60 @@ define('views/modals/edit', ['views/modal'], function (Dep) {
bottomDisabled: false,
+ shortcutKeys: {
+ 'Control+Enter': function (e) {
+ if (this.saveDisabled) {
+ return;
+ }
+
+ if (this.buttonList.findIndex(item => item.name === 'save' && !item.hidden) === -1) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.actionSave();
+ },
+ 'Control+KeyS': function (e) {
+ if (this.saveDisabled) {
+ return;
+ }
+
+ if (this.buttonList.findIndex(item => item.name === 'save' && !item.hidden) === -1) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.actionSaveAndContinueEditing();
+ },
+ 'Escape': function (e) {
+ if (this.saveDisabled) {
+ return;
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ let focusedFieldView = this.getRecordView().getFocusedFieldView();
+
+ if (focusedFieldView) {
+ this.model.set(focusedFieldView.fetch());
+ }
+
+ if (this.getRecordView().isChanged) {
+ this.confirm(this.translate('confirmLeaveOutMessage', 'messages'))
+ .then(() => this.actionClose());
+
+ return;
+ }
+
+ this.actionClose();
+ },
+ },
+
setup: function () {
this.buttonList = [];
@@ -71,45 +125,6 @@ define('views/modals/edit', ['views/modal'], function (Dep) {
label: 'Save',
style: 'primary',
});
-
- this.events['keydown'] = (e) => {
- if (e.key === 'Enter' && e.ctrlKey) {
- e.stopPropagation();
-
- this.actionSave();
-
- return;
- }
-
- if ((e.key === 's' || e.key === 'S') && e.ctrlKey) {
- e.preventDefault();
- e.stopPropagation();
-
- this.actionSaveAndContinueEditing();
-
- return;
- }
-
- if (e.key === 'Escape') {
- e.stopPropagation();
- e.preventDefault();
-
- let focusedFieldView = this.getRecordView().getFocusedFieldView();
-
- if (focusedFieldView) {
- this.model.set(focusedFieldView.fetch());
- }
-
- if (this.getRecordView().isChanged) {
- this.confirm(this.translate('confirmLeaveOutMessage', 'messages'))
- .then(() => this.actionClose());
-
- return;
- }
-
- this.actionClose();
- }
- }
}
this.fullFormDisabled = this.options.fullFormDisabled || this.fullFormDisabled;
diff --git a/client/src/views/record/detail.js b/client/src/views/record/detail.js
index f70efe807c..b29e78560d 100644
--- a/client/src/views/record/detail.js
+++ b/client/src/views/record/detail.js
@@ -417,13 +417,16 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
* @type {?Object.}
*/
shortcutKeys: {
- 'ctrl+enter': function (e) {
+ 'Control+Enter': function (e) {
this.handleShortcutKeyCtrlEnter(e);
},
- 'ctrl+s': function (e) {
+ 'Control+KeyS': function (e) {
this.handleShortcutKeyCtrlS(e);
},
- 'escape': function (e) {
+ 'KeyE': function (e) {
+ this.handleShortcutKeyE(e);
+ },
+ 'Escape': function (e) {
this.handleShortcutKeyEscape(e);
},
},
@@ -496,6 +499,7 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
if (!this.lastSaveCancelReason || this.lastSaveCancelReason === 'notModified') {
this.setDetailMode();
+ this.focusOnFirstDiv();
$(window).scrollTop(0);
}
},
@@ -503,9 +507,14 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
actionCancelEdit: function () {
this.cancelEdit();
+ this.focusOnFirstDiv();
$(window).scrollTop(0);
},
+ focusOnFirstDiv: function () {
+ this.$el.find('> div').focus();
+ },
+
/**
* A `save-and-continue-editing` action.
*/
@@ -1891,10 +1900,10 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
if (this.shortcutKeys && this.options.shortcutKeysEnabled) {
// @todo Move to util (the same for the `views/modal`.).
this.events['keydown.record-detail'] = e => {
- let key = e.key.toLowerCase();
+ let key = e.code;
if (e.ctrlKey) {
- key = 'ctrl+' + key;
+ key = 'Control+' + key;
}
if (typeof this.shortcutKeys[key] === 'function') {
@@ -1916,6 +1925,8 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
this[methodName]();
};
+
+ this.once('after:render', () => this.focusOnFirstDiv());
}
},
@@ -3392,91 +3403,6 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
.find('.dropdown-edit-item-list-button');
},
- /**
- * @protected
- * @param {JQueryKeyEventObject} e
- */
- handleKeydownEvent: function (e) {
- if (!this.options.shortcutKeysEnabled) {
- return;
- }
-
- /*if (e.key === 'Enter' && e.ctrlKey) {
- if (this.inlineEditModeIsOn || this.buttonsDisabled || !this.shortcutEnterAction) {
- return;
- }
-
- if (this.mode !== this.MODE_EDIT) {
- return;
- }
-
- if (
- this.type === this.TYPE_DETAIL &&
- this.buttonEditList.findIndex(item => item.name === this.shortcutEnterAction) === -1
- ) {
- return;
- }
-
- if (
- this.type === this.TYPE_EDIT &&
- this.buttonList.findIndex(item => item.name === this.shortcutEnterAction) === -1
- ) {
- return;
- }
-
- e.stopPropagation();
-
- let methodName = 'action' + Espo.Utils.upperCaseFirst(this.shortcutEnterAction);
-
- this[methodName]();
-
- return;
- }*/
-
- /*if ((e.key === 's' || e.key === 'S') && e.ctrlKey) {
- if (this.inlineEditModeIsOn || this.buttonsDisabled) {
- return;
- }
-
- if (this.mode !== this.MODE_EDIT) {
- return;
- }
-
- if (!this.saveAndContinueEditingAction) {
- return;
- }
-
- e.preventDefault();
- e.stopPropagation();
-
- this.actionSaveAndContinueEditing();
-
- return;
- }*/
-
- if (e.key === 'Escape') {
- if (this.inlineEditModeIsOn || this.buttonsDisabled) {
- return;
- }
-
- if (this.type === this.TYPE_DETAIL && this.mode === this.MODE_EDIT) {
- e.stopPropagation();
-
- // Fetching a currently edited form element.
- this.model.set(this.fetch());
-
- if (this.isChanged) {
- this.confirm(this.translate('confirmLeaveOutMessage', 'messages'))
- .then(() => this.actionCancelEdit());
-
- return;
- }
-
- this.actionCancelEdit();
- }
- }
- },
-
/**
* @protected
* @param {JQueryKeyEventObject} e
@@ -3494,14 +3420,14 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
if (
this.type === this.TYPE_DETAIL &&
- this.buttonEditList.findIndex(item => item.name === action) === -1
+ this.buttonEditList.findIndex(item => item.name === action && !item.hidden) === -1
) {
return;
}
if (
this.type === this.TYPE_EDIT &&
- this.buttonList.findIndex(item => item.name === action) === -1
+ this.buttonList.findIndex(item => item.name === action && !item.hidden) === -1
) {
return;
}
@@ -3537,6 +3463,38 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
this.actionSaveAndContinueEditing();
},
+ /**
+ * @protected
+ * @param {JQueryKeyEventObject} e
+ */
+ handleShortcutKeyE: function (e) {
+ if (this.inlineEditModeIsOn || this.buttonsDisabled) {
+ return;
+ }
+
+ if (this.type !== this.TYPE_DETAIL || this.mode !== this.MODE_DETAIL) {
+ return;
+ }
+
+ if (this.buttonList.findIndex(item => item.name === 'edit' && !item.hidden) === -1) {
+ return;
+ }
+
+ $(e.currentTarget)
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.actionEdit();
+
+ if (!this.editModeDisabled) {
+ setTimeout(() => {
+ this.$el.find('.middle-tabs > button.active, .form-control:not([disabled])')
+ .first().focus();
+ }, 200);
+ }
+ },
+
/**
* @protected
* @param {JQueryKeyEventObject} e
diff --git a/frontend/less/espo/elements/record.less b/frontend/less/espo/elements/record.less
index 38ce19d7ee..250aa826ad 100644
--- a/frontend/less/espo/elements/record.less
+++ b/frontend/less/espo/elements/record.less
@@ -17,6 +17,10 @@
}
}
+.record > div[tabindex="-1"]:focus-visible {
+ outline: none;
+}
+
.modal-body {
.record .record-grid {
grid-column-gap: @padding-base-horizontal;