mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-07 00:17:03 +03:00
Improved keyboard shortcuts handling
This commit is contained in:
parent
5f21fcc100
commit
2a6a1ff799
7 changed files with 58 additions and 77 deletions
2
dev/External/SquireUI.js
vendored
2
dev/External/SquireUI.js
vendored
|
|
@ -9,7 +9,7 @@ const
|
||||||
|
|
||||||
i18n = (str, def) => rl.i18n(str) || def,
|
i18n = (str, def) => rl.i18n(str) || def,
|
||||||
|
|
||||||
ctrlKey = shortcuts.getMetaKey().replace('meta','⌘') + ' + ',
|
ctrlKey = shortcuts.getMetaKey() + ' + ',
|
||||||
|
|
||||||
tpl = doc.createElement('template'),
|
tpl = doc.createElement('template'),
|
||||||
clr = doc.createElement('input'),
|
clr = doc.createElement('input'),
|
||||||
|
|
|
||||||
|
|
@ -1213,8 +1213,8 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
shortcuts.add('q', 'meta', Scope.Compose, ()=>false);
|
shortcuts.add('q', 'meta', Scope.Compose, ()=>false);
|
||||||
shortcuts.add('w', 'meta', Scope.Compose, ()=>false);
|
shortcuts.add('w', 'meta', Scope.Compose, ()=>false);
|
||||||
|
|
||||||
shortcuts.add('m,contextmenu', '', Scope.Compose, e => this.popupMenu(e));
|
shortcuts.add('contextmenu', '', Scope.Compose, e => this.popupMenu(e));
|
||||||
shortcuts.add('m', 'ctrl', Scope.Compose, e => this.popupMenu(e));
|
shortcuts.add('m', 'meta', Scope.Compose, e => this.popupMenu(e));
|
||||||
|
|
||||||
shortcuts.add('escape,close', '', Scope.Compose, () => {
|
shortcuts.add('escape,close', '', Scope.Compose, () => {
|
||||||
this.skipCommand();
|
this.skipCommand();
|
||||||
|
|
@ -1229,7 +1229,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
this.saveCommand();
|
this.saveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
shortcuts.add('save', Scope.Compose, () => {
|
shortcuts.add('save', '', Scope.Compose, () => {
|
||||||
this.saveCommand();
|
this.saveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ import { Scope } from 'Common/Enums';
|
||||||
|
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
|
||||||
class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
export class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('KeyboardShortcutsHelp');
|
super('KeyboardShortcutsHelp');
|
||||||
|
this.metaKey = shortcuts.getMetaKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
|
|
@ -49,5 +50,3 @@ class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { KeyboardShortcutsHelpPopupView, KeyboardShortcutsHelpPopupView as default };
|
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,8 @@ class PluginPopupView extends AbstractViewPopup {
|
||||||
shortcuts.add('escape', '', Scope.All, () => {
|
shortcuts.add('escape', '', Scope.All, () => {
|
||||||
if (this.modalVisibility()) {
|
if (this.modalVisibility()) {
|
||||||
this.tryToClosePopup();
|
this.tryToClosePopup();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
dev/bootstrap.js
vendored
21
dev/bootstrap.js
vendored
|
|
@ -5,27 +5,6 @@ import { root } from 'Common/Links';
|
||||||
|
|
||||||
export default App => {
|
export default App => {
|
||||||
|
|
||||||
addEventListener('keydown', event => {
|
|
||||||
event = event || window.event;
|
|
||||||
if (event && event.ctrlKey && !event.shiftKey && !event.altKey) {
|
|
||||||
if ('S' == event.key) {
|
|
||||||
event.preventDefault();
|
|
||||||
} else if ('A' == event.key) {
|
|
||||||
const sender = event.target;
|
|
||||||
if (
|
|
||||||
sender &&
|
|
||||||
('true' === '' + sender.contentEditable || (sender.matches && sender.matches('INPUT,TEXTAREA')))
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelection().removeAllRanges();
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addEventListener('click', ()=>rl.Dropdowns.detectVisibility());
|
addEventListener('click', ()=>rl.Dropdowns.detectVisibility());
|
||||||
|
|
||||||
rl.app = App;
|
rl.app = App;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,63 @@
|
||||||
|
|
||||||
(win => {
|
(win => {
|
||||||
|
|
||||||
|
let
|
||||||
|
scope = {},
|
||||||
|
_scope = 'all';
|
||||||
|
|
||||||
const
|
const
|
||||||
doc = document,
|
doc = document,
|
||||||
|
// On Mac we use ⌘ else the Ctrl key
|
||||||
meta = /Mac OS X/.test(navigator.userAgent) ? 'meta' : 'ctrl',
|
meta = /Mac OS X/.test(navigator.userAgent) ? 'meta' : 'ctrl',
|
||||||
_scopes = {
|
_scopes = {
|
||||||
all: {}
|
all: {}
|
||||||
},
|
},
|
||||||
toArray = v => Array.isArray(v) ? v : v.split(/\s*,\s*/),
|
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]')),
|
||||||
|
|
||||||
|
shortcuts = {
|
||||||
|
on: () => doc.addEventListener('keydown', keydown),
|
||||||
|
off: () => doc.removeEventListener('keydown', keydown),
|
||||||
|
add: (keys, modifiers, scopes, method) => {
|
||||||
|
if (method === undefined) {
|
||||||
|
method = scopes;
|
||||||
|
scopes = 'all';
|
||||||
|
}
|
||||||
|
toArray(scopes).forEach(scope => {
|
||||||
|
if (!_scopes[scope]) {
|
||||||
|
_scopes[scope] = {};
|
||||||
|
}
|
||||||
|
toArray(keys).forEach(key => {
|
||||||
|
key = key.toLowerCase();
|
||||||
|
if (!_scopes[scope][key]) {
|
||||||
|
_scopes[scope][key] = {};
|
||||||
|
}
|
||||||
|
modifiers = toArray(modifiers)
|
||||||
|
.map(key => 'meta' == key ? meta : key)
|
||||||
|
.unique().sort().join('+');
|
||||||
|
if (!_scopes[scope][key][modifiers]) {
|
||||||
|
_scopes[scope][key][modifiers] = [];
|
||||||
|
}
|
||||||
|
_scopes[scope][key][modifiers].push(method);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setScope: value => {
|
||||||
|
_scope = value || 'all';
|
||||||
|
scope = _scopes[_scope] || {};
|
||||||
|
},
|
||||||
|
getScope: () => _scope,
|
||||||
|
getMetaKey: () => 'meta' === meta ? '⌘' : 'Ctrl'
|
||||||
|
},
|
||||||
|
|
||||||
keydown = event => {
|
keydown = event => {
|
||||||
let key = (event.key || '').toLowerCase().replace(' ','space'),
|
let key = (event.key || '').toLowerCase().replace(' ','space'),
|
||||||
scopes = [];
|
scopes = [];
|
||||||
scope[key] && scopes.push(scope[key]);
|
scope[key] && scopes.push(scope[key]);
|
||||||
_scope !== 'all' && _scopes.all[key] && scopes.push(_scopes.all[key]);
|
_scope !== 'all' && _scopes.all[key] && scopes.push(_scopes.all[key]);
|
||||||
if (scopes.length && win.shortcuts.filter(event.target)) {
|
if (scopes.length && filter(event.target)) {
|
||||||
let modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+');
|
let modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+');
|
||||||
scopes.forEach(actions => {
|
scopes.forEach(actions => {
|
||||||
// for each potential shortcut
|
// for each potential shortcut
|
||||||
|
|
@ -33,47 +76,8 @@ const
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let
|
win.shortcuts = shortcuts;
|
||||||
scope = {},
|
|
||||||
_scope = 'all';
|
|
||||||
|
|
||||||
win.shortcuts = {
|
shortcuts.on();
|
||||||
on: () => doc.addEventListener('keydown', keydown),
|
|
||||||
off: () => doc.removeEventListener('keydown', keydown),
|
|
||||||
add: (keys, modifiers, scopes, method) => {
|
|
||||||
if (method === undefined) {
|
|
||||||
method = scopes;
|
|
||||||
scopes = 'all';
|
|
||||||
}
|
|
||||||
toArray(scopes).forEach(scope => {
|
|
||||||
if (!_scopes[scope]) {
|
|
||||||
_scopes[scope] = {};
|
|
||||||
}
|
|
||||||
toArray(keys).forEach(key => {
|
|
||||||
key = key.toLowerCase();
|
|
||||||
if (!_scopes[scope][key]) {
|
|
||||||
_scopes[scope][key] = {};
|
|
||||||
}
|
|
||||||
modifiers = toArray(modifiers)
|
|
||||||
.map(key => 'meta' == key ? meta : key)
|
|
||||||
.unique().sort().join('+');
|
|
||||||
if (!_scopes[scope][key][modifiers]) {
|
|
||||||
_scopes[scope][key][modifiers] = [];
|
|
||||||
}
|
|
||||||
_scopes[scope][key][modifiers].push(method);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setScope: value => {
|
|
||||||
_scope = value || 'all';
|
|
||||||
scope = _scopes[_scope] || {};
|
|
||||||
},
|
|
||||||
getScope: () => _scope,
|
|
||||||
getMetaKey: () => meta,
|
|
||||||
// ignore keydown in any element that supports keyboard input
|
|
||||||
filter: node => !(!node.closest || node.closest('input,select,textarea,[contenteditable]'))
|
|
||||||
};
|
|
||||||
|
|
||||||
win.shortcuts.on();
|
|
||||||
|
|
||||||
})(this);
|
})(this);
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td class="fontastic">☑</td><td data-i18n="SHORTCUTS_HELP/LABEL_CHECK_ALL"></td><td>Ctrl + A, ⌘ + A</td></tr>
|
<tr><td class="fontastic">☑</td><td data-i18n="SHORTCUTS_HELP/LABEL_CHECK_ALL"></td><td><!-- ko text: metaKey --><!-- /ko --> + A</td></tr>
|
||||||
<tr><td class="icon-archive"></td><td data-i18n="GLOBAL/TO_ARCHIVE"></td><td>Z</td></tr>
|
<tr><td class="icon-archive"></td><td data-i18n="GLOBAL/TO_ARCHIVE"></td><td>Z</td></tr>
|
||||||
<tr><td class="fontastic">🗑</td><td data-i18n="SHORTCUTS_HELP/LABEL_DELETE"></td><td>Delete, Shift + Delete</td></tr>
|
<tr><td class="fontastic">🗑</td><td data-i18n="SHORTCUTS_HELP/LABEL_DELETE"></td><td>Delete, Shift + Delete</td></tr>
|
||||||
<tr><td></td><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_THREAD"></td><td>T</td></tr>
|
<tr><td></td><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_THREAD"></td><td>T</td></tr>
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_TOGGLE"></td><td>Enter, Open</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_TOGGLE"></td><td>Enter, Open</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_BLOCKQUOTES_TOGGLE"></td><td>B</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_BLOCKQUOTES_TOGGLE"></td><td>B</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_PRINT"></td><td>Ctrl + P, ⌘ + P</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_PRINT"></td><td><!-- ko text: metaKey --><!-- /ko --> + P</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_EXIT_FULLSCREEN"></td><td>Esc, Close</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_EXIT_FULLSCREEN"></td><td>Esc, Close</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_MESSAGE"></td><td>Esc, Close</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_MESSAGE"></td><td>Esc, Close</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_LIST"></td><td>Shift + Tab, Esc</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_LIST"></td><td>Shift + Tab, Esc</td></tr>
|
||||||
|
|
@ -73,9 +73,9 @@
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_COMPOSE_POPUP"></td><td>W, C, New</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_COMPOSE_POPUP"></td><td>W, C, New</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_IDENTITIES_DROPDOWN"></td><td>M, Menu, Ctrl + M, ⌘ + M</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_OPEN_IDENTITIES_DROPDOWN"></td><td>Menu, <!-- ko text: metaKey --><!-- /ko --> + M</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SAVE_MESSAGE"></td><td>Ctrl + S, ⌘ + S, Save</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SAVE_MESSAGE"></td><td><!-- ko text: metaKey --><!-- /ko --> + S, Save</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SEND_MESSAGE"></td><td>Send, Ctrl + Enter, ⌘ + Enter</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_SEND_MESSAGE"></td><td>Send, <!-- ko text: metaKey --><!-- /ko --> + Enter</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_MINIMIZE_COMPOSE_POPUP"></td><td>Esc, Close</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_MINIMIZE_COMPOSE_POPUP"></td><td>Esc, Close</td></tr>
|
||||||
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_COMPOSE"></td><td>Shift + Esc, Shift + Close</td></tr>
|
<tr><td data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_COMPOSE"></td><td>Shift + Esc, Shift + Close</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue