Cleanup calls to Knockout observableArray

Improved Knockout observableArray
This commit is contained in:
djmaze 2021-01-22 12:23:20 +01:00
parent fa5476e486
commit b6f0b634fb
47 changed files with 251 additions and 276 deletions

View file

@ -208,7 +208,7 @@ class ComposePopupView extends AbstractViewNext {
}
}).extend({ notify: 'always' });
this.attachments = ko.observableArray([]);
this.attachments = ko.observableArray();
this.dragAndDropOver = ko.observable(false).extend({ throttle: 1 });
this.dragAndDropVisible = ko.observable(false).extend({ throttle: 1 });
@ -256,17 +256,17 @@ class ComposePopupView extends AbstractViewNext {
return result;
},
attachmentsInProcess: () => this.attachments().filter(item => item && !item.complete()),
attachmentsInReady: () => this.attachments().filter(item => item && item.complete()),
attachmentsInError: () => this.attachments().filter(item => item && item.error()),
attachmentsInProcess: () => this.attachments.filter(item => item && !item.complete()),
attachmentsInReady: () => this.attachments.filter(item => item && item.complete()),
attachmentsInError: () => this.attachments.filter(item => item && item.error()),
attachmentsCount: () => this.attachments().length,
attachmentsInErrorCount: () => this.attachmentsInError().length,
attachmentsInProcessCount: () => this.attachmentsInProcess().length,
attachmentsCount: () => this.attachments.length,
attachmentsInErrorCount: () => this.attachmentsInError.length,
attachmentsInProcessCount: () => this.attachmentsInProcess.length,
isDraftFolderMessage: () => this.draftFolder() && this.draftUid(),
identitiesOptions: () =>
IdentityStore.identities().map(item => ({
IdentityStore.identities.map(item => ({
'item': item,
'optValue': item.id(),
'optText': item.formattedName()
@ -1106,7 +1106,7 @@ class ComposePopupView extends AbstractViewNext {
}
});
} else {
this.attachments().forEach(attachment => {
this.attachments.forEach(attachment => {
if (attachment && attachment.fromMessage) {
attachment
.waiting(false)
@ -1221,7 +1221,7 @@ class ComposePopupView extends AbstractViewNext {
* @returns {?Object}
*/
getAttachmentById(id) {
return this.attachments().find(item => item && id === item.id);
return this.attachments.find(item => item && id === item.id);
}
cancelAttachmentHelper(id, oJua) {
@ -1428,7 +1428,7 @@ class ComposePopupView extends AbstractViewNext {
if (ComposeType.ForwardAsAttachment === type) {
this.addMessageAsAttachment(message);
} else {
message.attachments().forEach(item => {
message.attachments.forEach(item => {
let add = false;
switch (type) {
case ComposeType.Reply:
@ -1464,15 +1464,15 @@ class ComposePopupView extends AbstractViewNext {
*/
isEmptyForm(includeAttachmentInProgress = true) {
const withoutAttachment = includeAttachmentInProgress
? !this.attachments().length
? !this.attachments.length
: !this.attachmentsInReady().length;
return (
!this.to().length &&
!this.cc().length &&
!this.bcc().length &&
!this.replyTo().length &&
!this.subject().length &&
!this.to.length &&
!this.cc.length &&
!this.bcc.length &&
!this.replyTo.length &&
!this.subject.length &&
withoutAttachment &&
(!this.oEditor || !this.oEditor.getData())
);
@ -1528,7 +1528,7 @@ class ComposePopupView extends AbstractViewNext {
* @returns {Array}
*/
getAttachmentsDownloadsForUpload() {
return this.attachments().filter(item => item && !item.tempName()).map(
return this.attachments.filter(item => item && !item.tempName()).map(
item => item.id
);
}

View file

@ -41,10 +41,10 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
submitRequest: false
});
this.encryptKeys = ko.observableArray([]);
this.encryptKeys = ko.observableArray();
this.addComputables({
encryptKeysView: () => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(v => v),
encryptKeysView: () => this.encryptKeys.map(oKey => (oKey ? oKey.key : null)).filter(v => v),
privateKeysOptions: () => {
const opts = PgpStore.openpgpkeysPrivate().map((oKey, iIndex) => {
@ -150,13 +150,10 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
}
if (result && this.encrypt()) {
if (!this.encryptKeys().length) {
this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND'));
result = false;
} else if (this.encryptKeys()) {
if (this.encryptKeys.length) {
aPublicKeys = [];
this.encryptKeys().forEach(oKey => {
this.encryptKeys.forEach(oKey => {
if (oKey && oKey.key) {
aPublicKeys = aPublicKeys.concat(oKey.key.getNativeKeys().flat(Infinity).filter(v => v));
} else if (oKey && oKey.email) {
@ -170,9 +167,12 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
}
});
if (result && (!aPublicKeys.length || this.encryptKeys().length !== aPublicKeys.length)) {
if (result && (!aPublicKeys.length || this.encryptKeys.length !== aPublicKeys.length)) {
result = false;
}
} else {
this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND'));
result = false;
}
}
@ -261,11 +261,10 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
@command()
addCommand() {
const keyId = this.selectedPublicKey(),
keys = this.encryptKeys(),
option = keyId ? this.publicKeysOptions().find(item => item && keyId === item.id) : null;
if (option) {
keys.push({
this.encryptKeys.push({
'empty': !option.key,
'selected': ko.observable(!!option.key),
'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== option.key.id),
@ -273,16 +272,14 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
'hash': option.key.id.substr(KEY_NAME_SUBSTR).toUpperCase(),
'key': option.key
});
this.encryptKeys(keys);
}
}
@command()
updateCommand() {
this.encryptKeys().forEach(oKey => {
oKey.removable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.key.id);
});
this.encryptKeys.forEach(oKey =>
oKey.removable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.key.id)
);
}
deletePublickKey(publicKey) {
@ -390,7 +387,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
}).flat().validUnique(encryptKey => encryptKey.hash)
);
if (this.encryptKeys().length) {
if (this.encryptKeys.length) {
this.encrypt(true);
}
}

View file

@ -73,7 +73,7 @@ class ContactsPopupView extends AbstractViewNext {
this.contacts = ContactStore.contacts;
this.viewProperties = ko.observableArray([]);
this.viewProperties = ko.observableArray();
/*
// Somehow this is broken now when calling addNewProperty
@ -127,17 +127,17 @@ class ContactsPopupView extends AbstractViewNext {
contactsPaginator: computedPaginatorHelper(this.contactsPage, pagecount),
viewPropertiesNames: () => this.viewProperties().filter(propertyIsName),
viewPropertiesNames: () => this.viewProperties.filter(propertyIsName),
viewPropertiesEmails: () => this.viewProperties().filter(propertyIsMail),
viewPropertiesEmails: () => this.viewProperties.filter(propertyIsMail),
viewPropertiesOther: () => this.viewProperties().filter(property => property.isType(ContactPropertyType.Nick)),
viewPropertiesOther: () => this.viewProperties.filter(property => property.isType(ContactPropertyType.Nick)),
viewPropertiesWeb: () => this.viewProperties().filter(property => property.isType(ContactPropertyType.Web)),
viewPropertiesWeb: () => this.viewProperties.filter(property => property.isType(ContactPropertyType.Web)),
viewPropertiesPhones: () => this.viewProperties().filter(property => property.isType(ContactPropertyType.Phone)),
viewPropertiesPhones: () => this.viewProperties.filter(property => property.isType(ContactPropertyType.Phone)),
contactHasValidName: () => !!this.viewProperties().find(prop => propertyIsName(prop) && prop.isValid()),
contactHasValidName: () => !!this.viewProperties.find(prop => propertyIsName(prop) && prop.isValid()),
/*
viewPropertiesEmailsEmptyAndOnFocused: () => this.viewPropertiesEmails().filter(propertyFocused),
viewPropertiesPhonesEmptyAndOnFocused: () => this.viewPropertiesPhones().filter(propertyFocused),
@ -145,7 +145,7 @@ class ContactsPopupView extends AbstractViewNext {
viewPropertiesOtherEmptyAndOnFocused: () => this.viewPropertiesOther().filter(propertyFocused),
*/
contactsCheckedOrSelected: () => {
const checked = this.contacts().filter(item => item.checked && item.checked()),
const checked = this.contacts.filter(item => item.checked && item.checked()),
selected = this.currentContact();
return selected
@ -155,7 +155,7 @@ class ContactsPopupView extends AbstractViewNext {
contactsCheckedOrSelectedUids: () => this.contactsCheckedOrSelected().map(contact => contact.id),
viewHash: () => '' + this.viewProperties().map(property => property.value && property.value()).join('')
viewHash: () => '' + this.viewProperties.map(property => property.value && property.value()).join('')
});
this.search.subscribe(() => this.reloadContactList());
@ -243,7 +243,7 @@ class ContactsPopupView extends AbstractViewNext {
@command(self =>
!self.viewSaving() && !self.viewReadOnly()
&& (self.contactHasValidName() || self.viewProperties().find(prop => propertyIsMail(prop) && prop.isValid()))
&& (self.contactHasValidName() || self.viewProperties.find(prop => propertyIsMail(prop) && prop.isValid()))
)
saveCommand() {
this.viewSaving(true);
@ -282,7 +282,7 @@ class ContactsPopupView extends AbstractViewNext {
},
requestUid,
this.viewID(),
this.viewProperties().map(oItem => oItem.toJSON())
this.viewProperties.map(oItem => oItem.toJSON())
);
}
@ -322,7 +322,7 @@ class ContactsPopupView extends AbstractViewNext {
}
addNewOrFocusProperty(type, typeStr) {
const item = this.viewProperties().find(prop => prop.isType(type));
const item = this.viewProperties.find(prop => prop.isType(type));
if (item) {
item.focused(true);
} else {
@ -393,7 +393,7 @@ class ContactsPopupView extends AbstractViewNext {
contacts = this.contactsCheckedOrSelected();
let currentContact = this.currentContact(),
count = this.contacts().length;
count = this.contacts.length;
if (contacts.length) {
contacts.forEach(contact => {

View file

@ -33,7 +33,7 @@ class FilterPopupView extends AbstractViewNext {
this.selectedFolderValue.subscribe(() => this.filter() && this.filter().actionValueError(false));
['actionTypeOptions','fieldOptions','typeOptions','typeOptionsSize','typeOptionsBody'].forEach(
key => this[key] = ko.observableArray([])
key => this[key] = ko.observableArray()
);
initOnStartOrLangChange(this.populateOptions.bind(this));
@ -80,7 +80,7 @@ class FilterPopupView extends AbstractViewNext {
// this.actionTypeOptions.push({'id': FiltersAction.None,
// 'name': i18n('GLOBAL/NONE')});
const modules = SieveStore.capa();
const modules = SieveStore.capa;
if (modules) {
if (modules.includes('imap4flags')) {
this.allowMarkAsRead(true);

View file

@ -17,11 +17,11 @@ class LanguagesPopupView extends AbstractViewNext {
this.fLang = null;
this.userLanguage = ko.observable('');
this.langs = ko.observableArray([]);
this.langs = ko.observableArray();
this.languages = ko.computed(() => {
const userLanguage = this.userLanguage();
return this.langs().map(language => ({
return this.langs.map(language => ({
key: language,
user: language === userLanguage,
selected: ko.observable(false),
@ -39,9 +39,7 @@ class LanguagesPopupView extends AbstractViewNext {
setLanguageSelection() {
const currentLang = this.fLang ? ko.unwrap(this.fLang) : '';
this.languages().forEach(item => {
item.selected(item.key === currentLang);
});
this.languages.forEach(item => item.selected(item.key === currentLang));
}
onBeforeShow() {

View file

@ -20,7 +20,7 @@ class MessageOpenPgpPopupView extends AbstractViewNext {
password: '',
submitRequest: false
});
this.privateKeys = ko.observableArray([]);
this.privateKeys = ko.observableArray();
this.resultCallback = null;

View file

@ -24,10 +24,10 @@ class PluginPopupView extends AbstractViewNext {
readme: ''
});
this.configures = ko.observableArray([]);
this.configures = ko.observableArray();
this.hasReadme = ko.computed(() => !!this.readme());
this.hasConfiguration = ko.computed(() => 0 < this.configures().length);
this.hasConfiguration = ko.computed(() => 0 < this.configures.length);
this.bDisabeCloseOnEsc = true;
this.sDefaultKeyScope = KeyState.All;
@ -40,7 +40,7 @@ class PluginPopupView extends AbstractViewNext {
const list = {};
list.Name = this.name();
this.configures().forEach(oItem => {
this.configures.forEach(oItem => {
let value = oItem.value();
if (false === value || true === value) {
value = value ? '1' : '0';

View file

@ -141,7 +141,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
read: () => 0 < MessageStore.messageListChecked().length,
write: (value) => {
value = !!value;
MessageStore.messageList().forEach(message => message.checked(value));
MessageStore.messageList.forEach(message => message.checked(value));
}
},
@ -152,10 +152,10 @@ class MessageListMailBoxUserView extends AbstractViewNext {
isIncompleteChecked: () => {
const c = MessageStore.messageListChecked().length;
return c && MessageStore.messageList().length > c;
return c && MessageStore.messageList.length > c;
},
hasMessages: () => 0 < this.messageList().length,
hasMessages: () => 0 < this.messageList.length,
hasCheckedOrSelectedLines: () => 0 < this.messageListCheckedOrSelected().length,
@ -219,7 +219,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
addEventListener('mailbox.message.show', e => {
const sFolder = e.detail.Folder, sUid = e.detail.Uid;
const message = this.messageList().find(
const message = this.messageList.find(
item => item && sFolder === item.folder && sUid === item.uid
);
@ -492,7 +492,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
case MessageSetAction.SetSeen:
folder = getFolderFromCacheList(sFolderFullNameRaw);
if (folder) {
MessageStore.messageList().forEach(message => {
MessageStore.messageList.forEach(message => {
if (message.isUnseen()) {
++cnt;
}
@ -518,7 +518,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
case MessageSetAction.UnsetSeen:
folder = getFolderFromCacheList(sFolderFullNameRaw);
if (folder) {
MessageStore.messageList().forEach(message => {
MessageStore.messageList.forEach(message => {
if (!message.isUnseen()) {
++cnt;
}
@ -675,7 +675,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
!this.messageListSearchDesc() &&
!this.messageListError() &&
!this.messageListEndThreadUid() &&
this.messageList().length &&
this.messageList.length &&
(this.isSpamFolder() || this.isTrashFolder())
);
}
@ -864,7 +864,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
prefetchNextTick() {
if (ifvisible && !this.bPrefetch && !ifvisible.now() && this.viewModelVisible) {
const message = this.messageList().find(
const message = this.messageList.find(
item => item && !hasRequestedMessage(item.folder, item.uid)
);
if (message) {

View file

@ -157,9 +157,9 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
});
this.addComputables({
allowAttachmnetControls: () => this.attachmentsActions().length && Settings.capa(Capa.AttachmentsActions),
allowAttachmnetControls: () => this.attachmentsActions.length && Settings.capa(Capa.AttachmentsActions),
downloadAsZipAllowed: () => this.attachmentsActions().includes('zip') && this.allowAttachmnetControls(),
downloadAsZipAllowed: () => this.attachmentsActions.includes('zip') && this.allowAttachmnetControls(),
lastReplyAction: {
read: this.lastReplyAction_,
@ -206,7 +206,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.addSubscribables({
showAttachmnetControls: v => this.message()
&& this.message().attachments().forEach(item => item && item.checked(!!v)),
&& this.message().attachments.forEach(item => item && item.checked(!!v)),
lastReplyAction_: value => Local.set(ClientSideKeyName.LastReplyAction, value),
@ -380,7 +380,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
attachmentPreview(/*attachment*/) {
/*
if (attachment && attachment.isImage() && !attachment.isLinked && this.message() && this.message().attachments()) {
const items = this.message().attachments().map(item => {
const items = this.message().attachments.map(item => {
if (item && !item.isLinked && item.isImage()) {
if (item === attachment) {
index = listIndex;
@ -712,13 +712,10 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
}
getAttachmentsHashes() {
const atts = this.message() ? this.message().attachments() : [];
return atts.map(item => (item && !item.isLinked && item.checked() ? item.download : '')).filter(v => v);
}
downloadAsZip() {
const hashes = this.getAttachmentsHashes();
const hashes = (this.message() ? this.message().attachments : [])
.map(item => (item && !item.isLinked && item.checked() ? item.download : ''))
.filter(v => v);
if (hashes.length) {
Remote.attachmentsActions('Zip', hashes, this.downloadAsZipLoading)
.then((result) => {