Replace babel command decorators with proper knockout command decorators

This commit is contained in:
djmaze 2021-02-19 12:09:20 +01:00
parent b6d8fa5b3f
commit 540b12ed26
27 changed files with 181 additions and 132 deletions

View file

@ -114,23 +114,23 @@ RainLoop 1.15 vs SnappyMail
|js/* |RainLoop |Snappy |
|--------------- |--------: |--------: |
|admin.js |2.158.025 | 114.168 |
|app.js |4.215.733 | 529.069 |
|admin.js |2.158.025 | 110.918 |
|app.js |4.215.733 | 519.708 |
|boot.js | 672.433 | 4.726 |
|libs.js | 647.679 | 227.341 |
|libs.js | 647.679 | 227.110 |
|polyfills.js | 325.908 | 0 |
|serviceworker.js | 0 | 285 |
|TOTAL |8.019.778 | 875.589 |
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|admin.min.js | 255.514 | 57.878 | 73.899 | 16.598 | 60.674 | 14.745 |
|app.min.js | 516.000 | 257.954 |140.430 | 74.500 |110.657 | 62.522 |
|admin.min.js | 255.514 | 56.127 | 73.899 | 16.069 | 60.674 | 14.274 |
|app.min.js | 516.000 | 253.025 |140.430 | 73.063 |110.657 | 61.430 |
|boot.min.js | 66.456 | 2.525 | 22.553 | 1.391 | 20.043 | 1.201 |
|libs.min.js | 574.626 | 119.938 |177.280 | 43.997 |151.855 | 39.158 |
|libs.min.js | 574.626 | 119.817 |177.280 | 43.974 |151.855 | 39.127 |
|polyfills.min.js | 32.608 | 0 | 11.315 | 0 | 10.072 | 0 |
|TOTAL |1.445.204 | 438.295 |425.477 |136.486 |353.301 |117.626 |
|TOTAL (no admin) |1.189.690 | 380.417 |351.061 |119.888 |292.627 |102.881 |
|TOTAL |1.445.204 | 431.494 |425.477 |134.497 |353.301 |116.032 |
|TOTAL (no admin) |1.189.690 | 375.474 |351.061 |118.428 |292.627 |101.758 |
For a user its around 65% smaller and faster than traditional RainLoop.

15
dev/External/ko.js vendored
View file

@ -86,23 +86,10 @@ ko.bindingHandlers.command = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => {
const command = fValueAccessor();
if (!command || !command.isCommand) {
if (!command || !command.enabled || !command.canExecute) {
throw new Error('Value should be a command');
}
if (!command.enabled) {
command.enabled = ko.observable(true);
}
if (!command.canExecute) {
const __realCanExecute = command.__realCanExecute;
if (isFunction(__realCanExecute)) {
command.canExecute = ko.computed(() => command.enabled() && __realCanExecute.call(viewModel, viewModel));
} else {
command.canExecute = ko.computed(() => command.enabled() && !!__realCanExecute);
}
}
element.classList.add('command');
ko.bindingHandlers['FORM'==element.nodeName ? 'submit' : 'click'].init(
element,

View file

@ -320,32 +320,27 @@ export function startScreens(screensClasses) {
setTimeout(() => $htmlCL.add('rl-started-delay'), 200);
}
/**
* @param {Function} canExecute
* @returns {Function}
*/
function commandDecorator(canExecute = true) {
return (target, key, descriptor) => {
if (!key || !key.match(/Command$/)) {
throw new Error(`name "${key}" should end with Command suffix`);
}
const value = descriptor.value || descriptor.initializer(),
normCanExecute = typeof canExecute === 'function' ? canExecute : () => !!canExecute;
descriptor.value = function(...args) {
if (normCanExecute.call(this, this)) {
value.apply(this, args);
function decorateKoCommands(thisArg, commands) {
Object.entries(commands).forEach(([key, canExecute]) => {
let command = thisArg[key],
fn = function(...args) {
if (fn.enabled() && canExecute.call(thisArg, thisArg)) {
command.apply(thisArg, args);
}
return false;
};
descriptor.value.__realCanExecute = normCanExecute;
descriptor.value.isCommand = true;
// fn.__realCanExecute = canExecute;
// fn.isCommand = true;
return descriptor;
};
fn.enabled = ko.observable(true);
fn.canExecute = (typeof canExecute === 'function')
? ko.computed(() => fn.enabled() && canExecute.call(thisArg, thisArg))
: ko.computed(() => fn.enabled() && !!canExecute);
thisArg[key] = fn;
});
}
/**
@ -370,7 +365,6 @@ function settingsMenuKeysHandler(items) {
}
export {
commandDecorator,
commandDecorator as command,
decorateKoCommands,
settingsMenuKeysHandler
};

View file

@ -4,7 +4,7 @@ import { settingsSaveHelperSimpleFunction, defaultOptionsAfterRender } from 'Com
import { SaveSettingsStep, StorageResultType } from 'Common/Enums';
import Remote from 'Remote/Admin/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
const settingsGet = rl.settings.get;
@ -74,9 +74,12 @@ export class ContactsAdminSettings {
this.contactsType(settingsGet('ContactsPdoType'));
this.onTestContactsResponse = this.onTestContactsResponse.bind(this);
decorateKoCommands(this, {
testContactsCommand: self => self.pdoDsn() && self.pdoUser()
});
}
@command((self) => self.pdoDsn() && self.pdoUser())
testContactsCommand() {
this.testContactsSuccess(false);
this.testContactsError(false);

View file

@ -7,7 +7,7 @@ import { CapaAdminStore } from 'Stores/Admin/Capa';
import Remote from 'Remote/Admin/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
const settingsGet = rl.settings.get;
@ -75,9 +75,12 @@ export class SecurityAdminSettings {
});
this.onNewAdminPasswordResponse = this.onNewAdminPasswordResponse.bind(this);
decorateKoCommands(this, {
saveNewAdminPasswordCommand: self => self.adminLogin().trim() && self.adminPassword()
});
}
@command((self) => self.adminLogin().trim() && self.adminPassword())
saveNewAdminPasswordCommand() {
if (!this.adminLogin().trim()) {
this.adminLoginError(true);

View file

@ -5,7 +5,7 @@ import { getNotification } from 'Common/Translator';
import Remote from 'Remote/Admin/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewCenter } from 'Knoin/AbstractViews';
class LoginAdminView extends AbstractViewCenter {
@ -38,9 +38,12 @@ class LoginAdminView extends AbstractViewCenter {
passwordError: v => this.formError(!!v)
});
decorateKoCommands(this, {
submitCommand: self => !self.submitRequest()
});
}
@command((self) => !self.submitRequest())
submitCommand() {
this.loginError(false);
this.passwordError(false);

View file

@ -3,7 +3,7 @@ import { getNotification } from 'Common/Translator';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class AccountPopupView extends AbstractViewPopup {
@ -29,9 +29,12 @@ class AccountPopupView extends AbstractViewPopup {
this.email.subscribe(() => this.emailError(false));
this.password.subscribe(() => this.passwordError(false));
decorateKoCommands(this, {
addAccountCommand: self => !self.submitRequest()
});
}
@command((self) => !self.submitRequest())
addAccountCommand() {
this.emailError(!this.email().trim());
this.passwordError(!this.password().trim());

View file

@ -1,6 +1,6 @@
import PgpStore from 'Stores/User/Pgp';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class AddOpenPgpKeyPopupView extends AbstractViewPopup {
@ -17,9 +17,12 @@ class AddOpenPgpKeyPopupView extends AbstractViewPopup {
this.keyError(false);
this.keyErrorMessage('');
});
decorateKoCommands(this, {
addOpenPgpKeyCommand: 1
});
}
@command()
addOpenPgpKeyCommand() {
// eslint-disable-next-line max-len
const reg = /[-]{3,6}BEGIN[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[-]{3,6}[\s\S]+?[-]{3,6}END[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[-]{3,6}/gi,

View file

@ -4,7 +4,7 @@ import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import MessageStore from 'Stores/User/Message';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class AdvancedSearchPopupView extends AbstractViewPopup {
@ -38,9 +38,12 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
{ id: 365, name: i18n(prefix + 'YEAR') }
];
});
decorateKoCommands(this, {
searchCommand: 1
});
}
@command()
searchCommand() {
const search = this.buildSearchString();
if (search) {

View file

@ -37,7 +37,7 @@ import Remote from 'Remote/User/Fetch';
import { ComposeAttachmentModel } from 'Model/ComposeAttachment';
import { command, isPopupVisible, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin';
import { decorateKoCommands, isPopupVisible, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
@ -332,6 +332,14 @@ class ComposePopupView extends AbstractViewPopup {
this.saveCommand();
}
}, 120000);
decorateKoCommands(this, {
sendCommand: self => self.canBeSentOrSaved(),
saveCommand: self => self.canBeSentOrSaved(),
deleteCommand: self => self.isDraftFolderMessage(),
skipCommand: self => self.canBeSentOrSaved(),
contactsCommand: self => self.allowContacts
});
}
getMessageRequestParams(sSaveFolder)
@ -359,7 +367,6 @@ class ComposePopupView extends AbstractViewPopup {
};
}
@command((self) => self.canBeSentOrSaved())
sendCommand() {
let sSentFolder = FolderStore.sentFolder();
@ -429,7 +436,6 @@ class ComposePopupView extends AbstractViewPopup {
}
}
@command((self) => self.canBeSentOrSaved())
saveCommand() {
if (!this.allowFolders) {
return false;
@ -454,7 +460,6 @@ class ComposePopupView extends AbstractViewPopup {
return true;
}
@command((self) => self.isDraftFolderMessage())
deleteCommand() {
if (!isPopupVisible(AskPopupView) && this.modalVisibility()) {
showScreenPopup(AskPopupView, [
@ -469,7 +474,6 @@ class ComposePopupView extends AbstractViewPopup {
}
}
@command((self) => self.canBeSentOrSaved())
skipCommand() {
this.bSkipNextHide = true;
@ -486,7 +490,6 @@ class ComposePopupView extends AbstractViewPopup {
this.tryToClosePopup();
}
@command((self) => self.allowContacts)
contactsCommand() {
if (this.allowContacts) {
this.skipCommand();

View file

@ -9,7 +9,7 @@ import PgpStore from 'Stores/User/Pgp';
import { EmailModel } from 'Model/Email';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
const KEY_NAME_SUBSTR = -8,
@ -103,9 +103,15 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
};
this.deletePublickKey = this.deletePublickKey.bind(this);
decorateKoCommands(this, {
doCommand: self => !self.submitRequest() && (self.sign() || self.encrypt()),
selectCommand: 1,
addCommand: 1,
updateCommand: 1,
});
}
@command((self) => !self.submitRequest() && (self.sign() || self.encrypt()))
doCommand() {
let result = true,
privateKey = null,
@ -237,7 +243,6 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
return result;
}
@command()
selectCommand() {
const keyId = this.selectedPrivateKey(),
option = keyId ? this.privateKeysOptions().find(item => item && keyId === item.id) : null;
@ -253,7 +258,6 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
}
}
@command()
addCommand() {
const keyId = this.selectedPublicKey(),
option = keyId ? this.publicKeysOptions().find(item => item && keyId === item.id) : null;
@ -270,7 +274,6 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
}
}
@command()
updateCommand() {
this.encryptKeys.forEach(oKey =>
oKey.removable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.key.id)

View file

@ -26,7 +26,7 @@ import { EmailModel } from 'Model/Email';
import { ContactModel } from 'Model/Contact';
import { ContactPropertyModel, ContactPropertyType } from 'Model/ContactProperty';
import { command, hideScreenPopup } from 'Knoin/Knoin';
import { decorateKoCommands, hideScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
@ -162,21 +162,28 @@ class ContactsPopupView extends AbstractViewPopup {
this.watchDirty(true);
}
});
decorateKoCommands(this, {
newCommand: 1,
deleteCommand: self => 0 < self.contactsCheckedOrSelected().length,
newMessageCommand: self => 0 < self.contactsCheckedOrSelected().length,
clearCommand: 1,
saveCommand: self => !self.viewSaving() && !self.viewReadOnly()
&& (self.contactHasValidName() || self.viewProperties.find(prop => propertyIsMail(prop) && prop.isValid())),
syncCommand: self => !self.contacts.syncing() && !self.contacts.importing()
});
}
@command()
newCommand() {
this.populateViewContact(null);
this.currentContact(null);
}
@command((self) => 0 < self.contactsCheckedOrSelected().length)
deleteCommand() {
this.deleteSelectedContacts();
this.emptySelection(true);
}
@command((self) => 0 < self.contactsCheckedOrSelected().length)
newMessageCommand() {
if (!rl.settings.capa(Capa.Composer)) {
return false;
@ -233,15 +240,10 @@ class ContactsPopupView extends AbstractViewPopup {
return true;
}
@command()
clearCommand() {
this.search('');
}
@command(self =>
!self.viewSaving() && !self.viewReadOnly()
&& (self.contactHasValidName() || self.viewProperties.find(prop => propertyIsMail(prop) && prop.isValid()))
)
saveCommand() {
this.viewSaving(true);
this.viewSaveTrigger(SaveSettingsStep.Animate);
@ -283,7 +285,6 @@ class ContactsPopupView extends AbstractViewPopup {
);
}
@command((self) => !self.contacts.syncing() && !self.contacts.importing())
syncCommand() {
rl.app.contactsSync((result, data) => {
if (StorageResultType.Success !== result || !data || !data.Result) {

View file

@ -6,7 +6,7 @@ import { CapaAdminStore } from 'Stores/Admin/Capa';
import Remote from 'Remote/Admin/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class DomainPopupView extends AbstractViewPopup {
@ -162,9 +162,16 @@ class DomainPopupView extends AbstractViewPopup {
}
}
});
decorateKoCommands(this, {
createOrAddCommand: self => self.canBeSaved(),
testConnectionCommand: self => self.canBeTested(),
whiteListCommand: 1,
backCommand: 1,
sieveCommand: 1
});
}
@command((self) => self.canBeSaved())
createOrAddCommand() {
this.saving(true);
Remote.createOrUpdateDomain(
@ -173,7 +180,6 @@ class DomainPopupView extends AbstractViewPopup {
);
}
@command((self) => self.canBeTested())
testConnectionCommand() {
this.page('main');
@ -189,17 +195,14 @@ class DomainPopupView extends AbstractViewPopup {
);
}
@command()
whiteListCommand() {
this.page('white-list');
}
@command()
backCommand() {
this.page('main');
}
@command()
sieveCommand() {
this.sieveSettings(!this.sieveSettings());
this.clearTesting();

View file

@ -7,7 +7,7 @@ import { DomainAdminStore } from 'Stores/Admin/Domain';
import Remote from 'Remote/Admin/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class DomainAliasPopupView extends AbstractViewPopup {
@ -30,9 +30,12 @@ class DomainAliasPopupView extends AbstractViewPopup {
this.canBeSaved = ko.computed(() => !this.saving() && this.name() && this.alias());
this.onDomainAliasCreateOrSaveResponse = this.onDomainAliasCreateOrSaveResponse.bind(this);
decorateKoCommands(this, {
createCommand: self => self.canBeSaved()
});
}
@command((self) => self.canBeSaved())
createCommand() {
this.saving(true);
Remote.createDomainAlias(this.onDomainAliasCreateOrSaveResponse, this.name(), this.alias());

View file

@ -8,7 +8,7 @@ import { i18n, initOnStartOrLangChange } from 'Common/Translator';
import FolderStore from 'Stores/User/Folder';
import { SieveUserStore } from 'Stores/User/Sieve';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class FilterPopupView extends AbstractViewPopup {
@ -36,9 +36,12 @@ class FilterPopupView extends AbstractViewPopup {
initOnStartOrLangChange(this.populateOptions.bind(this));
SieveUserStore.capa.subscribe(this.populateOptions, this);
decorateKoCommands(this, {
saveFilterCommand: 1
});
}
@command()
saveFilterCommand() {
if (this.filter()) {
if (FilterAction.MoveTo === this.filter().actionType()) {

View file

@ -6,7 +6,7 @@ import MessageStore from 'Stores/User/Message';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class FolderClearPopupView extends AbstractViewPopup {
@ -32,14 +32,15 @@ class FolderClearPopupView extends AbstractViewPopup {
dangerDescHtml: () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { 'FOLDER': this.folderNameForClear() })
});
decorateKoCommands(this, {
clearCommand: self => {
const folder = self.selectedFolder();
return !self.clearingProcess() && null !== folder;
}
});
}
@command((self) => {
const folder = self.selectedFolder(),
isClearing = self.clearingProcess();
return !isClearing && null !== folder;
})
clearCommand() {
const folderToClear = this.selectedFolder();
if (folderToClear) {

View file

@ -9,7 +9,7 @@ import FolderStore from 'Stores/User/Folder';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class FolderCreatePopupView extends AbstractViewPopup {
@ -40,9 +40,12 @@ class FolderCreatePopupView extends AbstractViewPopup {
});
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
decorateKoCommands(this, {
createFolderCommand: self => self.simpleFolderNameValidation(self.folderName())
});
}
@command((self) => self.simpleFolderNameValidation(self.folderName()))
createFolderCommand() {
let parentFolderName = this.selectedParentValue();
if (!parentFolderName && 1 < FolderStore.namespace.length) {

View file

@ -3,7 +3,7 @@ import { getNotification } from 'Common/Translator';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
const reEmail = /^[^@\s]+@[^@\s]+$/;
@ -61,9 +61,11 @@ class IdentityPopupView extends AbstractViewPopup {
this.replyTo.valueHasMutated();
this.bcc.valueHasMutated();
*/
decorateKoCommands(this, {
addOrEditIdentityCommand: self => !self.submitRequest()
});
}
@command((self) => !self.submitRequest())
addOrEditIdentityCommand() {
if (this.signature && this.signature.__fetchEditorValue) {
this.signature.__fetchEditorValue();

View file

@ -3,7 +3,7 @@ import ko from 'ko';
import { pString } from 'Common/Utils';
import { KeyState } from 'Common/Enums';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class MessageOpenPgpPopupView extends AbstractViewPopup {
@ -21,9 +21,12 @@ class MessageOpenPgpPopupView extends AbstractViewPopup {
this.resultCallback = null;
this.sDefaultKeyScope = KeyState.PopupMessageOpenPGP;
decorateKoCommands(this, {
doCommand: self => !self.submitRequest()
});
}
@command((self) => !self.submitRequest())
doCommand() {
this.submitRequest(true);

View file

@ -2,7 +2,7 @@ import { pInt } from 'Common/Utils';
import PgpStore from 'Stores/User/Pgp';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class NewOpenPgpKeyPopupView extends AbstractViewPopup {
@ -23,9 +23,12 @@ class NewOpenPgpKeyPopupView extends AbstractViewPopup {
});
this.email.subscribe(() => this.emailError(false));
decorateKoCommands(this, {
generateOpenPgpKeyCommand: 1
});
}
@command()
generateOpenPgpKeyCommand() {
const userId = {},
openpgpKeyring = PgpStore.openpgpKeyring;

View file

@ -5,7 +5,7 @@ import { getNotification, i18n } from 'Common/Translator';
import Remote from 'Remote/Admin/Fetch';
import { command, isPopupVisible, showScreenPopup } from 'Knoin/Knoin';
import { decorateKoCommands, isPopupVisible, showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { AskPopupView } from 'View/Popup/Ask';
@ -30,9 +30,12 @@ class PluginPopupView extends AbstractViewPopup {
this.sDefaultKeyScope = KeyState.All;
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
decorateKoCommands(this, {
saveCommand: self => self.hasConfiguration()
});
}
@command((self) => self.hasConfiguration())
saveCommand() {
const list = {};
list.Name = this.name();

View file

@ -9,7 +9,7 @@ import Remote from 'Remote/User/Fetch';
import { FilterModel } from 'Model/Filter';
import { SieveUserStore } from 'Stores/User/Sieve';
import { showScreenPopup/*, command*/ } from 'Knoin/Knoin';
import { showScreenPopup/*, decorateKoCommands*/ } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FilterPopupView } from 'View/Popup/Filter';
@ -30,9 +30,13 @@ class SieveScriptPopupView extends AbstractViewPopup {
this.saving = false;
this.filterForDeletion = ko.observable(null).deleteAccessHelper();
/*
decorateKoCommands(this, {
saveScriptCommand: 1
});
*/
}
// @command()
saveScriptCommand() {
let self = this,
script = self.script();

View file

@ -4,7 +4,7 @@ import { HtmlEditor } from 'Common/Html';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { TemplateModel } from 'Model/Template';
@ -34,9 +34,12 @@ class TemplatePopupView extends AbstractViewPopup {
this.name.subscribe(() => this.nameError(false));
this.body.subscribe(() => this.bodyError(false));
decorateKoCommands(this, {
addTemplateCommand: self => !self.submitRequest()
});
}
@command((self) => !self.submitRequest())
addTemplateCommand() {
this.populateBodyFromEditor();

View file

@ -2,7 +2,7 @@ import { StorageResultType } from 'Common/Enums';
import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class TwoFactorTestPopupView extends AbstractViewPopup {
@ -18,9 +18,12 @@ class TwoFactorTestPopupView extends AbstractViewPopup {
});
this.koTestedTrigger = null;
decorateKoCommands(this, {
testCodeCommand: self => self.code() && !self.testing()
});
}
@command((self) => self.code() && !self.testing())
testCodeCommand() {
this.testing(true);
Remote.testTwoFactor((result, data) => {

View file

@ -16,7 +16,7 @@ import * as Local from 'Storage/Client';
import Remote from 'Remote/User/Fetch';
import { command, showScreenPopup } from 'Knoin/Knoin';
import { decorateKoCommands, showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewCenter } from 'Knoin/AbstractViews';
import { Settings } from 'Common/Globals';
@ -113,13 +113,16 @@ class LoginUserView extends AbstractViewCenter {
if (Settings.get('AdditionalLoginError') && !this.submitError()) {
this.submitError(Settings.get('AdditionalLoginError'));
}
decorateKoCommands(this, {
submitCommand: self => !self.submitRequest()
});
}
windowOpenFeatures(wh) {
return `left=200,top=100,width=${wh},height=${wh},menubar=no,status=no,resizable=yes,scrollbars=yes`;
}
@command((self) => !self.submitRequest())
submitCommand() {
this.emailError(false);
this.passwordError(false);

View file

@ -41,7 +41,7 @@ import { ThemeStore } from 'Stores/Theme';
import Remote from 'Remote/User/Fetch';
import { command, showScreenPopup, popupVisibility } from 'Knoin/Knoin';
import { decorateKoCommands, showScreenPopup, popupVisibility } from 'Knoin/Knoin';
import { AbstractViewRight } from 'Knoin/AbstractViews';
import { FolderClearPopupView } from 'View/Popup/FolderClear';
@ -237,23 +237,33 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
MessageStore.messageListEndHash.subscribe((() =>
this.selector.scrollToFocused()
).throttle(50));
decorateKoCommands(this, {
clearCommand: 1,
reloadCommand: 1,
multyForwardCommand: canBeMovedHelper,
deleteWithoutMoveCommand: canBeMovedHelper,
deleteCommand: canBeMovedHelper,
archiveCommand: canBeMovedHelper,
spamCommand: canBeMovedHelper,
notSpamCommand: canBeMovedHelper,
moveCommand: canBeMovedHelper,
moveNewCommand: canBeMovedHelper,
});
}
@command()
clearCommand() {
if (Settings.capa(Capa.DangerousActions)) {
showScreenPopup(FolderClearPopupView, [FolderStore.currentFolder()]);
}
}
@command()
reloadCommand() {
if (!MessageStore.messageListCompleteLoadingThrottleForAnimation() && this.allowReload) {
rl.app.reloadMessageList(false, true);
}
}
@command(canBeMovedHelper)
multyForwardCommand() {
if (Settings.capa(Capa.Composer)) {
showScreenPopup(ComposePopupView, [
@ -263,7 +273,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
}
@command(canBeMovedHelper)
deleteWithoutMoveCommand() {
if (Settings.capa(Capa.DangerousActions)) {
rl.app.deleteMessagesFromFolder(
@ -275,7 +284,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
}
@command(canBeMovedHelper)
deleteCommand() {
rl.app.deleteMessagesFromFolder(
FolderType.Trash,
@ -285,7 +293,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
);
}
@command(canBeMovedHelper)
archiveCommand() {
rl.app.deleteMessagesFromFolder(
FolderType.Archive,
@ -295,7 +302,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
);
}
@command(canBeMovedHelper)
spamCommand() {
rl.app.deleteMessagesFromFolder(
FolderType.Spam,
@ -305,7 +311,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
);
}
@command(canBeMovedHelper)
notSpamCommand() {
rl.app.deleteMessagesFromFolder(
FolderType.NotSpam,
@ -315,10 +320,8 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
);
}
@command(canBeMovedHelper)
moveCommand() {} // eslint-disable-line no-empty-function
moveCommand() {}
@command(canBeMovedHelper)
moveNewCommand(vm, event) {
if (this.newMoveToFolder && this.mobileCheckedStateShow()) {
if (vm && event && event.preventDefault) {

View file

@ -38,7 +38,7 @@ import * as Local from 'Storage/Client';
import Remote from 'Remote/User/Fetch';
import { command, showScreenPopup, createCommand } from 'Knoin/Knoin';
import { decorateKoCommands, showScreenPopup, createCommand } from 'Knoin/Knoin';
import { AbstractViewRight } from 'Knoin/AbstractViews';
import { ComposePopupView } from 'View/Popup/Compose';
@ -266,29 +266,32 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
addEventListener('mailbox.message-view.toggle-full-screen', () => this.toggleFullScreen());
this.attachmentPreview = this.attachmentPreview.bind(this);
decorateKoCommands(this, {
closeMessageCommand: 1,
messageVisibilityCommand: self => self.messageVisibility(),
messageEditCommand: self => self.messageVisibility(),
goUpCommand: self => !self.messageListAndMessageViewLoading(),
goDownCommand: self => !self.messageListAndMessageViewLoading()
});
}
@command()
closeMessageCommand() {
MessageStore.message(null);
}
@command((self) => self.messageVisibility())
messageVisibilityCommand() {} // eslint-disable-line no-empty-function
messageVisibilityCommand() {}
@command((self) => self.messageVisibility())
messageEditCommand() {
this.editMessage();
}
@command((self) => !self.messageListAndMessageViewLoading())
goUpCommand() {
dispatchEvent(new CustomEvent('mailbox.message-list.selector.go-up',
{detail:SettingsStore.usePreviewPane() || !!this.message()} // bForceSelect
));
}
@command((self) => !self.messageListAndMessageViewLoading())
goDownCommand() {
dispatchEvent(new CustomEvent('mailbox.message-list.selector.go-down',
{detail:SettingsStore.usePreviewPane() || !!this.message()} // bForceSelect