Improved shortcuts handling

This commit is contained in:
the-djmaze 2022-02-25 17:02:08 +01:00
parent 65a3b9e4c7
commit 1d63683cf9
7 changed files with 28 additions and 50 deletions

View file

@ -3,8 +3,6 @@ import 'External/User/ko';
import { isArray, pString } from 'Common/Utils';
import { mailToHelper, setLayoutResizer } from 'Common/UtilsUser';
import { Scope } from 'Common/Enums';
import {
FolderType,
SetSystemFoldersNotification,
@ -90,7 +88,7 @@ class AppUser extends AbstractApp {
const fn = (ev=>$htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey)).debounce(500);
addEventsListener(doc, ['keydown','keyup'], fn);
shortcuts.add('escape,enter', '', Scope.All, () => rl.Dropdowns.detectVisibility());
shortcuts.add('escape,enter', '', () => rl.Dropdowns.detectVisibility());
}
reload() {

View file

@ -229,19 +229,6 @@ Object.assign(ko.bindingHandlers, {
init: (element, fValueAccessor) => fValueAccessor()(element)
},
onEsc: {
init: (element, fValueAccessor, fAllBindings, viewModel) => {
let fn = event => {
if ('Escape' == event.key) {
element.dispatchEvent(new Event('change'));
fValueAccessor().call(viewModel);
}
};
element.addEventListener('keyup', fn);
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keyup', fn));
}
},
registerBootstrapDropdown: {
init: element => {
rl.Dropdowns.register(element);

View file

@ -16,15 +16,11 @@ addObservablesTo(AppUserStore, {
});
AppUserStore.focusedState.subscribe(value => {
switch (value) {
case Scope.MessageList:
case Scope.MessageView:
case Scope.FolderList:
['FolderList','MessageList','MessageView'].forEach(name => {
if (name === value) {
keyScope(value);
ThemeStore.isMobile() && leftPanelDisabled(Scope.FolderList !== value);
break;
}
['FolderList','MessageList','MessageView'].forEach(name => {
}
let dom = elementById('V-Mail'+name);
dom && dom.classList.toggle('focused', name === value);
});

View file

@ -14,14 +14,23 @@ const
},
toArray = v => Array.isArray(v) ? v : v.split(/\s*,\s*/),
// ignore keydown in any element that supports keyboard input
filter = node => !(!node.closest || node.closest('input,select,textarea,[contenteditable]')),
exec = (event, cmd) => {
try {
// call the handler and stop the event if neccessary
if (!event.defaultPrevented && cmd(event) === false) {
event.preventDefault();
event.stopPropagation();
}
} catch (e) {
console.error(e);
}
},
shortcuts = {
on: () => doc.addEventListener('keydown', keydown),
off: () => doc.removeEventListener('keydown', keydown),
add: (keys, modifiers, scopes, method) => {
if (method === undefined) {
if (null == method) {
method = scopes;
scopes = 'all';
}
@ -54,25 +63,13 @@ const
keydown = event => {
let key = (event.key || '').toLowerCase().replace(' ','space'),
scopes = [];
scope[key] && scopes.push(scope[key]);
_scope !== 'all' && _scopes.all[key] && scopes.push(_scopes.all[key]);
if (scopes.length && filter(event.target)) {
target = event.target;
// ignore keydown in any element that supports keyboard input unless it's the Escape key
if ('escape' === key || !target.closest || !target.closest('input,select,textarea,[contenteditable]')) {
let modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+');
scopes.forEach(actions => {
// for each potential shortcut
actions[modifiers] && actions[modifiers].forEach(cmd => {
try {
// call the handler and stop the event if neccessary
if (!event.defaultPrevented && cmd(event) === false) {
event.preventDefault();
event.stopPropagation();
}
} catch (e) {
console.error(e);
}
});
});
scope[key] && scope[key][modifiers] && scope[key][modifiers].forEach(cmd => exec(event, cmd));
!event.defaultPrevented && _scope !== 'all' && _scopes.all[key] && _scopes.all[key][modifiers]
&& _scopes.all[key][modifiers].forEach(cmd => exec(event, cmd));
}
};

View file

@ -8,22 +8,22 @@
<div class="control-group">
<label data-i18n="GLOBAL/FROM"></label>
<input type="text" autofocus="" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: from, onEsc: closeCommand">
data-bind="value: from">
</div>
<div class="control-group">
<label data-i18n="GLOBAL/TO"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: to, onEsc: closeCommand">
data-bind="value: to">
</div>
<div class="control-group">
<label data-i18n="GLOBAL/SUBJECT"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: subject, onEsc: closeCommand">
data-bind="value: subject">
</div>
<div class="control-group">
<label data-i18n="SEARCH/LABEL_ADV_TEXT"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: text, onEsc: closeCommand">
data-bind="value: text">
</div>
</div>
<div class="span4">

View file

@ -44,7 +44,7 @@
</header>
<div class="modal-body">
<div class="b-list-toolbar">
<input type="search" class="e-search" placeholder="Search" autocorrect="off" autocapitalize="off" data-i18n="[placeholder]GLOBAL/SEARCH" data-bind="value: search">
<input type="search" class="e-search" placeholder="Search" autofocus="" autocorrect="off" autocapitalize="off" data-i18n="[placeholder]GLOBAL/SEARCH" data-bind="value: search">
</div>
<div class="b-list-content g-ui-user-select-none" data-bind="css: {'hideContactListCheckbox': !useCheckboxesInList()}">
<div class="content">

View file

@ -5,7 +5,7 @@
tooltipErrorTip: errorMsg"></span>
<input type="text"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: nameForEdit, visible: edited, hasfocus: edited, onEnter: function () { $root.folderEditOnEnter($data); }, onEsc: function () { $root.folderEditOnEsc($data); }">
data-bind="value: nameForEdit, visible: edited, hasfocus: edited, onEnter: function () { $root.folderEditOnEnter($data); }">
&nbsp;
<span class="folder-system-name" data-bind="text: manageFolderSystemName, visible: isSystemFolder"></span>
</td>