mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Revamp shortcuts handler (not tested yet)
This commit is contained in:
parent
31828b125f
commit
5e7f531c7f
21 changed files with 190 additions and 170 deletions
|
|
@ -13,10 +13,11 @@ module.exports = {
|
||||||
es6: true
|
es6: true
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
// RainLoop
|
// SnappyMail
|
||||||
'rainloopI18N': "readonly",
|
'rainloopI18N': "readonly",
|
||||||
'rainloopTEMPLATES': "readonly",
|
'rainloopTEMPLATES': "readonly",
|
||||||
'rl': "readonly",
|
'rl': "readonly",
|
||||||
|
'shortcuts': "readonly",
|
||||||
// '__APP_BOOT': "readonly",
|
// '__APP_BOOT': "readonly",
|
||||||
// deb/boot.js
|
// deb/boot.js
|
||||||
'progressJs': "readonly",
|
'progressJs': "readonly",
|
||||||
|
|
@ -31,8 +32,6 @@ module.exports = {
|
||||||
'hasher': "readonly",
|
'hasher': "readonly",
|
||||||
'signals': "readonly",
|
'signals': "readonly",
|
||||||
'Crossroads': "readonly",
|
'Crossroads': "readonly",
|
||||||
// vendors/keymaster
|
|
||||||
'key': "readonly",
|
|
||||||
// vendors/jua
|
// vendors/jua
|
||||||
'Jua': "readonly",
|
'Jua': "readonly",
|
||||||
// vendors/qr.js
|
// vendors/qr.js
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class AbstractApp {
|
||||||
$doc.addEventListener('keypress', fn);
|
$doc.addEventListener('keypress', fn);
|
||||||
$doc.addEventListener('click', fn);
|
$doc.addEventListener('click', fn);
|
||||||
|
|
||||||
key('esc, enter', KeyState.All, () => rl.Dropdowns.detectVisibility());
|
shortcuts.add(['escape','enter'], '', KeyState.All, () => rl.Dropdowns.detectVisibility());
|
||||||
}
|
}
|
||||||
|
|
||||||
remote() {
|
remote() {
|
||||||
|
|
|
||||||
|
|
@ -54,24 +54,12 @@ export const keyScope = ko.computed({
|
||||||
if (KeyState.Menu !== value) {
|
if (KeyState.Menu !== value) {
|
||||||
if (KeyState.Compose === value) {
|
if (KeyState.Compose === value) {
|
||||||
// disableKeyFilter
|
// disableKeyFilter
|
||||||
key.filter = () => useKeyboardShortcuts();
|
shortcuts.filter = () => useKeyboardShortcuts();
|
||||||
} else {
|
} else {
|
||||||
// restoreKeyFilter
|
// restoreKeyFilter
|
||||||
key.filter = (event) => {
|
shortcuts.filter = event => !(event.target.matches
|
||||||
if (useKeyboardShortcuts()) {
|
&& (event.target.matches('input,select,textarea')
|
||||||
const el = event.target,
|
|| event.target.closest('[contenteditable]')));
|
||||||
nodeName = el ? el.nodeName : '';
|
|
||||||
|
|
||||||
return !(
|
|
||||||
'INPUT' === nodeName ||
|
|
||||||
'SELECT' === nodeName ||
|
|
||||||
'TEXTAREA' === nodeName ||
|
|
||||||
(el && el.contentEditable)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keyScopeFake(value);
|
keyScopeFake(value);
|
||||||
|
|
@ -86,13 +74,13 @@ export const keyScope = ko.computed({
|
||||||
|
|
||||||
keyScopeReal.subscribe((value) => {
|
keyScopeReal.subscribe((value) => {
|
||||||
// console.log('keyScope=' + sValue); // DEBUG
|
// console.log('keyScope=' + sValue); // DEBUG
|
||||||
key.setScope(value);
|
shortcuts.setScope(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
dropdownVisibility.subscribe((value) => {
|
dropdownVisibility.subscribe((value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
keyScope(KeyState.Menu);
|
keyScope(KeyState.Menu);
|
||||||
} else if (KeyState.Menu === key.getScope()) {
|
} else if (KeyState.Menu === shortcuts.getScope()) {
|
||||||
keyScope(keyScopeFake());
|
keyScope(keyScopeFake());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ class Selector {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
key('enter', keyScope, () => {
|
shortcuts.add('enter', '', keyScope, () => {
|
||||||
const focused = this.focusedItem();
|
const focused = this.focusedItem();
|
||||||
if (focused && !focused.selected()) {
|
if (focused && !focused.selected()) {
|
||||||
this.actionClick(focused);
|
this.actionClick(focused);
|
||||||
|
|
@ -283,48 +283,16 @@ class Selector {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+up, command+up, ctrl+down, command+down', keyScope, () => false);
|
shortcuts.add('arrowup', 'meta', keyScope, () => false);
|
||||||
|
shortcuts.add('arrowdown', 'meta', keyScope, () => false);
|
||||||
|
|
||||||
key('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', keyScope, (event, handler) => {
|
shortcuts.add(['arrowup','arrowdown'], 'shift', keyScope, event => {
|
||||||
if (event && handler && handler.shortcut) {
|
this.newSelectPosition(event.key, true);
|
||||||
let eventKey;
|
return false;
|
||||||
switch (handler.shortcut) {
|
});
|
||||||
case 'up':
|
shortcuts.add(['arrowup','arrowdown','home','end','pageup','pagedown','insert','space'], '', keyScope, event => {
|
||||||
case 'shift+up':
|
this.newSelectPosition(event.key, false);
|
||||||
eventKey = 'ArrowUp';
|
|
||||||
break;
|
|
||||||
case 'down':
|
|
||||||
case 'shift+down':
|
|
||||||
eventKey = 'ArrowDown';
|
|
||||||
break;
|
|
||||||
case 'insert':
|
|
||||||
eventKey = 'Insert';
|
|
||||||
break;
|
|
||||||
case 'space':
|
|
||||||
eventKey = ' ';
|
|
||||||
break;
|
|
||||||
case 'home':
|
|
||||||
eventKey = 'Home';
|
|
||||||
break;
|
|
||||||
case 'end':
|
|
||||||
eventKey = 'End';
|
|
||||||
break;
|
|
||||||
case 'pageup':
|
|
||||||
eventKey = 'PageUp';
|
|
||||||
break;
|
|
||||||
case 'pagedown':
|
|
||||||
eventKey = 'PageDown';
|
|
||||||
break;
|
|
||||||
// no default
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventKey) {
|
|
||||||
this.newSelectPosition(eventKey, key.shift);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ class MenuSettingsAdminView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
key('up, down', KeyState.Settings, settingsMenuKeysHandler(dom.querySelectorAll('.b-admin-menu .e-item')));
|
shortcuts.add(['arrowup','arrowdown'], '', KeyState.Settings,
|
||||||
|
settingsMenuKeysHandler(dom.querySelectorAll('.b-admin-menu .e-item')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,8 @@ class AskPopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
key('tab, shift+tab, right, left', KeyState.PopupAsk, () => {
|
// shortcuts.add('tab', 'shift', KeyState.PopupAsk, () => {
|
||||||
|
shortcuts.add(['tab','arrowright','arrowleft'], '', KeyState.PopupAsk, () => {
|
||||||
let btn = this.querySelector('.buttonYes');
|
let btn = this.querySelector('.buttonYes');
|
||||||
if (btn.matches(':focus')) {
|
if (btn.matches(':focus')) {
|
||||||
btn = this.querySelector('.buttonNo');
|
btn = this.querySelector('.buttonNo');
|
||||||
|
|
@ -95,7 +96,7 @@ class AskPopupView extends AbstractViewNext {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('esc', KeyState.PopupAsk, () => {
|
shortcuts.add('escape', '', KeyState.PopupAsk, () => {
|
||||||
this.noClick();
|
this.noClick();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1114,9 +1114,10 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
this.initUploader();
|
this.initUploader();
|
||||||
|
|
||||||
key('ctrl+q, command+q, ctrl+w, command+w', KeyState.Compose, ()=>false);
|
shortcuts.add('q', 'meta', KeyState.Compose, ()=>false);
|
||||||
|
shortcuts.add('w', 'meta', KeyState.Compose, ()=>false);
|
||||||
|
|
||||||
key('`', KeyState.Compose, () => {
|
shortcuts.add('`', '', KeyState.Compose, () => {
|
||||||
if (this.oEditor && !this.oEditor.hasFocus() && !inFocus()) {
|
if (this.oEditor && !this.oEditor.hasFocus() && !inFocus()) {
|
||||||
this.identitiesDropdownTrigger(true);
|
this.identitiesDropdownTrigger(true);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1125,31 +1126,35 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+`', KeyState.Compose, () => {
|
shortcuts.add('`', 'ctrl', KeyState.Compose, () => {
|
||||||
this.identitiesDropdownTrigger(true);
|
this.identitiesDropdownTrigger(true);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('esc, ctrl+down, command+down', KeyState.Compose, () => {
|
shortcuts.add('escape', '', KeyState.Compose, () => {
|
||||||
|
this.skipCommand();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
shortcuts.add('arrowdown', 'meta', KeyState.Compose, () => {
|
||||||
this.skipCommand();
|
this.skipCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.allowFolders) {
|
if (this.allowFolders) {
|
||||||
key('ctrl+s, command+s', KeyState.Compose, () => {
|
shortcuts.add('s', 'meta', KeyState.Compose, () => {
|
||||||
this.saveCommand();
|
this.saveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.app('allowCtrlEnterOnCompose')) {
|
if (Settings.app('allowCtrlEnterOnCompose')) {
|
||||||
key('ctrl+enter, command+enter', KeyState.Compose, () => {
|
shortcuts.add('enter', 'meta', KeyState.Compose, () => {
|
||||||
this.sendCommand();
|
this.sendCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
key('shift+esc', KeyState.Compose, () => {
|
shortcuts.add('escape', 'shift', KeyState.Compose, () => {
|
||||||
if (this.modalVisibility()) {
|
if (this.modalVisibility()) {
|
||||||
this.tryToClosePopup();
|
this.tryToClosePopup();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,8 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
key('tab,shift+tab', KeyState.PopupComposeOpenPGP, () => {
|
// shortcuts.add(('tab', 'shift', KeyState.PopupComposeOpenPGP, () => {
|
||||||
|
shortcuts.add('tab', '', KeyState.PopupComposeOpenPGP, () => {
|
||||||
let btn = this.querySelector('.inputPassword');
|
let btn = this.querySelector('.inputPassword');
|
||||||
if (btn.matches(':focus')) {
|
if (btn.matches(':focus')) {
|
||||||
btn = this.querySelector('.buttonDo');
|
btn = this.querySelector('.buttonDo');
|
||||||
|
|
|
||||||
|
|
@ -606,12 +606,12 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
this.selector.init(dom.querySelector('.b-list-content'), KeyState.ContactList);
|
this.selector.init(dom.querySelector('.b-list-content'), KeyState.ContactList);
|
||||||
|
|
||||||
key('delete', KeyState.ContactList, () => {
|
shortcuts.add('delete', '', KeyState.ContactList, () => {
|
||||||
this.deleteCommand();
|
this.deleteCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('c, w', KeyState.ContactList, () => {
|
shortcuts.add(['c','w'], '', KeyState.ContactList, () => {
|
||||||
this.newMessageCommand();
|
this.newMessageCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ class KeyboardShortcutsHelpPopupView extends AbstractViewNext {
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
dom.querySelectorAll('a[data-toggle="tab"]').forEach(node => node.Tab || new BSN.Tab(node));
|
dom.querySelectorAll('a[data-toggle="tab"]').forEach(node => node.Tab || new BSN.Tab(node));
|
||||||
|
|
||||||
key(
|
// shortcuts.add('tab', 'shift',
|
||||||
'tab, shift+tab, left, right',
|
shortcuts.add(['tab','arrowleft','arrowright'], '',
|
||||||
KeyState.PopupKeyboardShortcutsHelp,
|
KeyState.PopupKeyboardShortcutsHelp,
|
||||||
((event, handler)=>{
|
((event, handler)=>{
|
||||||
if (event && handler) {
|
if (event && handler) {
|
||||||
|
|
@ -26,7 +26,7 @@ class KeyboardShortcutsHelpPopupView extends AbstractViewNext {
|
||||||
let next = 0;
|
let next = 0;
|
||||||
tabs.forEach((node, index) => {
|
tabs.forEach((node, index) => {
|
||||||
if (node.matches('.active')) {
|
if (node.matches('.active')) {
|
||||||
if (['tab','right'].includes(handler.shortcut)) {
|
if (['tab','arrowright'].includes(handler.shortcut)) {
|
||||||
next = index < last ? index+1 : 0;
|
next = index < last ? index+1 : 0;
|
||||||
} else {
|
} else {
|
||||||
next = index ? index-1 : last;
|
next = index ? index-1 : last;
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,8 @@ class MessageOpenPgpPopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild(oDom) {
|
onBuild(oDom) {
|
||||||
key('tab,shift+tab', KeyState.PopupMessageOpenPGP, () => {
|
// shortcuts.add('tab','shift', KeyState.PopupMessageOpenPGP, () => {
|
||||||
|
shortcuts.add('tab', '', KeyState.PopupMessageOpenPGP, () => {
|
||||||
let btn = this.querySelector('.inputPassword');
|
let btn = this.querySelector('.inputPassword');
|
||||||
if (btn.matches(':focus')) {
|
if (btn.matches(':focus')) {
|
||||||
btn = this.querySelector('.buttonDo');
|
btn = this.querySelector('.buttonDo');
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ class PluginPopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
key('esc', KeyState.All, () => {
|
shortcuts.add('escape', '', KeyState.All, () => {
|
||||||
if (this.modalVisibility()) {
|
if (this.modalVisibility()) {
|
||||||
this.tryToClosePopup();
|
this.tryToClosePopup();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class ViewOpenPgpKeyPopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
key('ctrl+a, command+a', KeyState.PopupViewOpenPGP, () => {
|
shortcuts.add('a', 'meta', KeyState.PopupViewOpenPGP, () => {
|
||||||
this.selectKey();
|
this.selectKey();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class AbstractSystemDropDownUserView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
key('`', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => {
|
shortcuts.add('`', '', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => {
|
||||||
if (this.viewModelVisibility()) {
|
if (this.viewModelVisibility()) {
|
||||||
MessageStore.messageFullScreenMode(false);
|
MessageStore.messageFullScreenMode(false);
|
||||||
this.accountMenuDropdownTrigger(true);
|
this.accountMenuDropdownTrigger(true);
|
||||||
|
|
@ -89,7 +89,7 @@ class AbstractSystemDropDownUserView extends AbstractViewNext {
|
||||||
});
|
});
|
||||||
|
|
||||||
// shortcuts help
|
// shortcuts help
|
||||||
key('shift+/', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => {
|
shortcuts.add('/', 'shift', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => {
|
||||||
if (this.viewModelVisibility()) {
|
if (this.viewModelVisibility()) {
|
||||||
showScreenPopup(require('View/Popup/KeyboardShortcutsHelp'));
|
showScreenPopup(require('View/Popup/KeyboardShortcutsHelp'));
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class FolderListMailBoxUserView extends AbstractViewNext {
|
||||||
el && fSelectFolder(el, event, false);
|
el && fSelectFolder(el, event, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
key('up, down', KeyState.FolderList, (event, handler) => {
|
shortcuts.add(['arrowup','arrowdown'], '', KeyState.FolderList, event => {
|
||||||
let items = [], index = 0;
|
let items = [], index = 0;
|
||||||
dom.querySelectorAll('.b-folders .e-item .e-link:not(.hidden)').forEach(node => {
|
dom.querySelectorAll('.b-folders .e-item .e-link:not(.hidden)').forEach(node => {
|
||||||
if (node.offsetHeight || node.getClientRects().length) {
|
if (node.offsetHeight || node.getClientRects().length) {
|
||||||
|
|
@ -133,7 +133,7 @@ class FolderListMailBoxUserView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (items.length) {
|
if (items.length) {
|
||||||
if (handler && 'up' === handler.shortcut) {
|
if ('ArrowUp' === event.key) {
|
||||||
index && --index;
|
index && --index;
|
||||||
} else if (index < items.length - 1) {
|
} else if (index < items.length - 1) {
|
||||||
++index;
|
++index;
|
||||||
|
|
@ -145,7 +145,7 @@ class FolderListMailBoxUserView extends AbstractViewNext {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('enter', KeyState.FolderList, () => {
|
shortcuts.add('enter', '', KeyState.FolderList, () => {
|
||||||
const item = qs('.b-folders .e-item .e-link:not(.hidden).focused');
|
const item = qs('.b-folders .e-item .e-link:not(.hidden).focused');
|
||||||
if (item) {
|
if (item) {
|
||||||
AppStore.focusedState(Focused.MessageList);
|
AppStore.focusedState(Focused.MessageList);
|
||||||
|
|
@ -155,7 +155,7 @@ class FolderListMailBoxUserView extends AbstractViewNext {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('space', KeyState.FolderList, () => {
|
shortcuts.add('space', '', KeyState.FolderList, () => {
|
||||||
const item = qs('.b-folders .e-item .e-link:not(.hidden).focused'),
|
const item = qs('.b-folders .e-item .e-link:not(.hidden).focused'),
|
||||||
folder = item && ko.dataFor(item);
|
folder = item && ko.dataFor(item);
|
||||||
if (folder) {
|
if (folder) {
|
||||||
|
|
@ -167,7 +167,8 @@ class FolderListMailBoxUserView extends AbstractViewNext {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('esc, tab, shift+tab, right', KeyState.FolderList, () => {
|
// shortcuts.add('tab', 'shift', KeyState.FolderList, () => {
|
||||||
|
shortcuts.add(['escape','tab','arrowright'], '', KeyState.FolderList, () => {
|
||||||
AppStore.focusedState(Focused.MessageList);
|
AppStore.focusedState(Focused.MessageList);
|
||||||
moveAction(false);
|
moveAction(false);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -742,7 +742,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
initShortcuts() {
|
initShortcuts() {
|
||||||
key('enter', KeyState.MessageList, () => {
|
shortcuts.add('enter', '', KeyState.MessageList, () => {
|
||||||
if (this.message() && this.useAutoSelect()) {
|
if (this.message() && this.useAutoSelect()) {
|
||||||
dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen'));
|
dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen'));
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -753,46 +753,40 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
if (Settings.capa(Capa.MessageListActions)) {
|
if (Settings.capa(Capa.MessageListActions)) {
|
||||||
// archive (zip)
|
// archive (zip)
|
||||||
key('z', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('z', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.archiveCommand();
|
this.archiveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
key('delete, shift+delete, shift+3', KeyState.MessageList, (event, handler) => {
|
shortcuts.add('delete', 'shift', KeyState.MessageList, () => {
|
||||||
if (event) {
|
MessageStore.messageListCheckedOrSelected().length && this.deleteWithoutMoveCommand();
|
||||||
if (MessageStore.messageListCheckedOrSelected().length) {
|
return false;
|
||||||
if (handler && 'shift+delete' === handler.shortcut) {
|
});
|
||||||
this.deleteWithoutMoveCommand();
|
// shortcuts.add('3', 'shift', KeyState.MessageList, () => {
|
||||||
} else {
|
shortcuts.add('delete', '', KeyState.MessageList, () => {
|
||||||
this.deleteCommand();
|
MessageStore.messageListCheckedOrSelected().length && this.deleteCommand();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.capa(Capa.Reload)) {
|
if (Settings.capa(Capa.Reload)) {
|
||||||
// check mail
|
// check mail
|
||||||
key('ctrl+r, command+r', [KeyState.FolderList, KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('r', 'meta', [KeyState.FolderList, KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.reloadCommand();
|
this.reloadCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// check all
|
// check all
|
||||||
key('ctrl+a, command+a', KeyState.MessageList, () => {
|
shortcuts.add('a', 'meta', KeyState.MessageList, () => {
|
||||||
this.checkAll(!(this.checkAll() && !this.isIncompleteChecked()));
|
this.checkAll(!(this.checkAll() && !this.isIncompleteChecked()));
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Settings.capa(Capa.Composer)) {
|
if (Settings.capa(Capa.Composer)) {
|
||||||
// write/compose (open compose popup)
|
// write/compose (open compose popup)
|
||||||
key('w,c', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add(['w','c'], '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
showScreenPopup(require('View/Popup/Compose'));
|
showScreenPopup(require('View/Popup/Compose'));
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
@ -800,13 +794,13 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
if (Settings.capa(Capa.MessageListActions)) {
|
if (Settings.capa(Capa.MessageListActions)) {
|
||||||
// important - star/flag messages
|
// important - star/flag messages
|
||||||
key('i', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('i', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.flagMessagesFast();
|
this.flagMessagesFast();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
key('t', [KeyState.MessageList], () => {
|
shortcuts.add('t', '', [KeyState.MessageList], () => {
|
||||||
let message = this.selectorMessageSelected();
|
let message = this.selectorMessageSelected();
|
||||||
if (!message) {
|
if (!message) {
|
||||||
message = this.selectorMessageFocused();
|
message = this.selectorMessageFocused();
|
||||||
|
|
@ -821,7 +815,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
if (Settings.capa(Capa.MessageListActions)) {
|
if (Settings.capa(Capa.MessageListActions)) {
|
||||||
// move
|
// move
|
||||||
key('m', KeyState.MessageList, () => {
|
shortcuts.add('m', '', KeyState.MessageList, () => {
|
||||||
if (this.newMoveToFolder()) {
|
if (this.newMoveToFolder()) {
|
||||||
this.moveNewCommand();
|
this.moveNewCommand();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -834,20 +828,20 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
if (Settings.capa(Capa.MessageListActions)) {
|
if (Settings.capa(Capa.MessageListActions)) {
|
||||||
// read
|
// read
|
||||||
key('q', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('q', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.seenMessagesFast(true);
|
this.seenMessagesFast(true);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// unread
|
// unread
|
||||||
key('u', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('u', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.seenMessagesFast(false);
|
this.seenMessagesFast(false);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.capa(Capa.Composer)) {
|
if (Settings.capa(Capa.Composer)) {
|
||||||
key('shift+f', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('f', 'shift', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.multyForwardCommand();
|
this.multyForwardCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
@ -855,14 +849,14 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
if (Settings.capa(Capa.Search)) {
|
if (Settings.capa(Capa.Search)) {
|
||||||
// search input focus
|
// search input focus
|
||||||
key('/', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('/', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.inputMessageListSearchFocus(true);
|
this.inputMessageListSearchFocus(true);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel search
|
// cancel search
|
||||||
key('esc', KeyState.MessageList, () => {
|
shortcuts.add('escape', '', KeyState.MessageList, () => {
|
||||||
if (this.messageListSearchDesc()) {
|
if (this.messageListSearchDesc()) {
|
||||||
this.cancelSearch();
|
this.cancelSearch();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -875,18 +869,21 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
||||||
});
|
});
|
||||||
|
|
||||||
// change focused state
|
// change focused state
|
||||||
key('tab, shift+tab, left, right', KeyState.MessageList, (event, handler) => {
|
shortcuts.add('tab', 'shift', KeyState.MessageList, () => {
|
||||||
if (event && handler && ('shift+tab' === handler.shortcut || 'left' === handler.shortcut)) {
|
|
||||||
AppStore.focusedState(Focused.FolderList);
|
AppStore.focusedState(Focused.FolderList);
|
||||||
} else if (this.message()) {
|
return false;
|
||||||
AppStore.focusedState(Focused.MessageView);
|
});
|
||||||
}
|
shortcuts.add('arrowleft', '', KeyState.MessageList, () => {
|
||||||
|
AppStore.focusedState(Focused.FolderList);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
shortcuts.add(['tab','arrowright'], '', KeyState.MessageList, () => {
|
||||||
|
this.message() && AppStore.focusedState(Focused.MessageView);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+left, command+left', KeyState.MessageView, ()=>false);
|
shortcuts.add('arrowleft', 'meta', KeyState.MessageView, ()=>false);
|
||||||
key('ctrl+right, command+right', KeyState.MessageView, ()=>false);
|
shortcuts.add('arrowright', 'meta', KeyState.MessageView, ()=>false);
|
||||||
}
|
}
|
||||||
|
|
||||||
prefetchNextTick() {
|
prefetchNextTick() {
|
||||||
|
|
|
||||||
|
|
@ -547,26 +547,25 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
||||||
|
|
||||||
initShortcuts() {
|
initShortcuts() {
|
||||||
// exit fullscreen, back
|
// exit fullscreen, back
|
||||||
key('esc, backspace', KeyState.MessageView, this.escShortcuts.bind(this));
|
shortcuts.add(['escape','backspace'], '', KeyState.MessageView, this.escShortcuts.bind(this));
|
||||||
|
|
||||||
// fullscreen
|
// fullscreen
|
||||||
key('enter', KeyState.MessageView, () => {
|
shortcuts.add('enter', '', KeyState.MessageView, () => {
|
||||||
this.toggleFullScreen();
|
this.toggleFullScreen();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// reply
|
// reply
|
||||||
key('r', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('r', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
if (MessageStore.message()) {
|
if (MessageStore.message()) {
|
||||||
this.replyCommand();
|
this.replyCommand();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// replaAll
|
// replaAll
|
||||||
key('a', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('a', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
if (MessageStore.message()) {
|
if (MessageStore.message()) {
|
||||||
this.replyAllCommand();
|
this.replyAllCommand();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -576,7 +575,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
||||||
});
|
});
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
key('f', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('f', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
if (MessageStore.message()) {
|
if (MessageStore.message()) {
|
||||||
this.forwardCommand();
|
this.forwardCommand();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -586,7 +585,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
||||||
});
|
});
|
||||||
|
|
||||||
// message information
|
// message information
|
||||||
key('ctrl+i, command+i', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('i', 'meta', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
if (MessageStore.message()) {
|
if (MessageStore.message()) {
|
||||||
this.showFullInfo(!this.showFullInfo());
|
this.showFullInfo(!this.showFullInfo());
|
||||||
}
|
}
|
||||||
|
|
@ -594,7 +593,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
||||||
});
|
});
|
||||||
|
|
||||||
// toggle message blockquotes
|
// toggle message blockquotes
|
||||||
key('b', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add('b', '', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
const message = MessageStore.message();
|
const message = MessageStore.message();
|
||||||
if (message && message.body) {
|
if (message && message.body) {
|
||||||
message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
|
message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
|
||||||
|
|
@ -603,62 +602,49 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+up, command+up, ctrl+left, command+left', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add(['arrowup','arrowleft'], 'meta', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.goUpCommand();
|
this.goUpCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+down, command+down, ctrl+right, command+right', [KeyState.MessageList, KeyState.MessageView], () => {
|
shortcuts.add(['arrowdown','arrowright'], 'meta', [KeyState.MessageList, KeyState.MessageView], () => {
|
||||||
this.goDownCommand();
|
this.goDownCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// print
|
// print
|
||||||
key('ctrl+p, command+p', [KeyState.MessageView, KeyState.MessageList], () => {
|
shortcuts.add('p', 'meta', [KeyState.MessageView, KeyState.MessageList], () => {
|
||||||
if (this.message()) {
|
if (this.message()) {
|
||||||
this.message().printMessage();
|
this.message().printMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
key('delete, shift+delete', KeyState.MessageView, (event, handler) => {
|
shortcuts.add('delete', '', KeyState.MessageView, () => {
|
||||||
if (event) {
|
|
||||||
if (handler && 'shift+delete' === handler.shortcut) {
|
|
||||||
this.deleteWithoutMoveCommand();
|
|
||||||
} else {
|
|
||||||
this.deleteCommand();
|
this.deleteCommand();
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
});
|
||||||
|
shortcuts.add('delete', 'shift', KeyState.MessageView, () => {
|
||||||
return true;
|
this.deleteWithoutMoveCommand();
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// change focused state
|
// change focused state
|
||||||
key('tab, shift+tab, left', KeyState.MessageView, (event, handler) => {
|
shortcuts.add('arrowleft', '', KeyState.MessageView, () => {
|
||||||
if (!this.fullScreenMode() && this.message() && Layout.NoPreview !== this.layout()) {
|
if (!this.fullScreenMode() && this.message() && Layout.NoPreview !== this.layout()) {
|
||||||
if (event && handler && 'left' === handler.shortcut) {
|
|
||||||
if (this.oMessageScrollerDom && 0 < this.oMessageScrollerDom.scrollLeft) {
|
if (this.oMessageScrollerDom && 0 < this.oMessageScrollerDom.scrollLeft) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppStore.focusedState(Focused.MessageList);
|
AppStore.focusedState(Focused.MessageList);
|
||||||
} else {
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// shortcuts.add('tab', 'shift', KeyState.MessageView, (event, handler) => {
|
||||||
|
shortcuts.add('tab', '', KeyState.MessageView, () => {
|
||||||
|
if (!this.fullScreenMode() && this.message() && Layout.NoPreview !== this.layout()) {
|
||||||
AppStore.focusedState(Focused.MessageList);
|
AppStore.focusedState(Focused.MessageList);
|
||||||
}
|
}
|
||||||
} else if (
|
|
||||||
this.message() &&
|
|
||||||
Layout.NoPreview === this.layout() &&
|
|
||||||
event &&
|
|
||||||
handler &&
|
|
||||||
'left' === handler.shortcut
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ class MenuSettingsUserView extends AbstractViewNext {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
key('up, down', KeyState.Settings, settingsMenuKeysHandler(dom.querySelectorAll('.b-settings-menu .e-item')));
|
shortcuts.add(['ArrowUp','ArrowDown'], '', KeyState.Settings,
|
||||||
|
settingsMenuKeysHandler(dom.querySelectorAll('.b-settings-menu .e-item')));
|
||||||
}
|
}
|
||||||
|
|
||||||
link(route) {
|
link(route) {
|
||||||
|
|
|
||||||
1
dev/prototype.js
vendored
1
dev/prototype.js
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
(w=>{
|
(w=>{
|
||||||
Array.isNotEmpty = array => Array.isArray(array) && array.length;
|
Array.isNotEmpty = array => Array.isArray(array) && array.length;
|
||||||
|
Array.prototype.unique((v, i, a) => a.indexOf(v) === i);
|
||||||
|
|
||||||
// Import momentjs locales function
|
// Import momentjs locales function
|
||||||
w.moment = {
|
w.moment = {
|
||||||
|
|
|
||||||
70
dev/shortcuts.js
Normal file
70
dev/shortcuts.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
(win => {
|
||||||
|
|
||||||
|
const
|
||||||
|
doc = document,
|
||||||
|
meta = /Mac OS X/.test(navigator.userAgent) ? 'meta' : 'ctrl',
|
||||||
|
actions = {},
|
||||||
|
toArray = v => Array.isArray(v) ? v : [v];
|
||||||
|
let
|
||||||
|
_scope = 'all';
|
||||||
|
|
||||||
|
doc.addEventListener('keydown', event => {
|
||||||
|
const key = (event.key||event.code||'').toLowerCase();
|
||||||
|
if (actions[key] && win.shortcuts.filter(event)) {
|
||||||
|
let modifiers = [];
|
||||||
|
event.altKey && modifiers.push('alt');
|
||||||
|
event.ctrlKey && modifiers.push('ctrl');
|
||||||
|
event.metaKey && modifiers.push('meta');
|
||||||
|
event.shiftKey && modifiers.push('shift');
|
||||||
|
modifiers = modifiers.join('+');
|
||||||
|
if (actions[key][modifiers]) {
|
||||||
|
// for each potential shortcut
|
||||||
|
actions[key][modifiers].forEach(cmd => {
|
||||||
|
// see if it's in the current scope
|
||||||
|
if (cmd.scope.includes(_scope) || cmd.scope == 'all') {
|
||||||
|
try {
|
||||||
|
// call the handler and stop the event if neccessary
|
||||||
|
if (cmd.method(event) === false) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
win.shortcuts = {
|
||||||
|
add: (keys, modifiers, scope, method) => {
|
||||||
|
if (method === undefined) {
|
||||||
|
method = scope;
|
||||||
|
scope = 'all';
|
||||||
|
}
|
||||||
|
toArray(keys).forEach(key => {
|
||||||
|
key = key.toLowerCase();
|
||||||
|
if (!actions[key]) {
|
||||||
|
actions[key] = {};
|
||||||
|
}
|
||||||
|
modifiers = toArray(modifiers)
|
||||||
|
.map(key => 'meta' == key ? meta : key)
|
||||||
|
.unique().sort().join('+');
|
||||||
|
if (!actions[key][modifiers]) {
|
||||||
|
actions[key][modifiers] = [];
|
||||||
|
}
|
||||||
|
actions[key][modifiers].push({scope:toArray(scope), method:method});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setScope: scope => _scope = scope || 'all',
|
||||||
|
getScope: () => _scope,
|
||||||
|
getMetaKey: () => meta,
|
||||||
|
// ignore keydown in any element that supports keyboard input
|
||||||
|
filter: event => !(event.target.matches
|
||||||
|
&& (event.target.matches('input,select,textarea') || event.target.closest('[contenteditable]')))
|
||||||
|
};
|
||||||
|
|
||||||
|
})(this);
|
||||||
|
|
@ -79,7 +79,7 @@ config.paths.js = {
|
||||||
'vendors/routes/hasher.min.js', // fixed
|
'vendors/routes/hasher.min.js', // fixed
|
||||||
'vendors/routes/crossroads.min.js', // fixed
|
'vendors/routes/crossroads.min.js', // fixed
|
||||||
'vendors/jua/jua.min.js', // custom
|
'vendors/jua/jua.min.js', // custom
|
||||||
'vendors/keymaster/keymaster.js', // custom (modified)
|
'dev/shortcuts.js',
|
||||||
'vendors/qr.js/qr.min.js', // fixed (license)
|
'vendors/qr.js/qr.min.js', // fixed (license)
|
||||||
'vendors/bootstrap/js/bootstrap.native.min.js', // fixed
|
'vendors/bootstrap/js/bootstrap.native.min.js', // fixed
|
||||||
'vendors/knockout/build/output/knockout-latest.js',
|
'vendors/knockout/build/output/knockout-latest.js',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue