Replaced tricky delegateRunOnDestroy() with koArrayWithDestroy()

koArrayWithDestroy creates ko.observableArray and calls the desired onDestroy() on entry delete.
This commit is contained in:
the-djmaze 2022-02-17 12:48:57 +01:00
parent f4bc796fb1
commit e324e2f6b6
13 changed files with 32 additions and 55 deletions

View file

@ -1,7 +1,7 @@
import 'External/User/ko';
import { isArray, arrayLength, pString, forEachObjectValue } from 'Common/Utils';
import { delegateRunOnDestroy, mailToHelper, setLayoutResizer } from 'Common/UtilsUser';
import { mailToHelper, setLayoutResizer } from 'Common/UtilsUser';
import {
Notification,
@ -333,8 +333,6 @@ class AppUser extends AbstractApp {
if (isArray(accounts)) {
// AccountUserStore.accounts.forEach(oAccount => counts[oAccount.email] = oAccount.count());
delegateRunOnDestroy(AccountUserStore.accounts());
AccountUserStore.accounts(
accounts.map(
sValue => new AccountModel(sValue/*, counts[sValue]*/)
@ -345,8 +343,6 @@ class AppUser extends AbstractApp {
}
if (isArray(oData.Result.Identities)) {
delegateRunOnDestroy(IdentityUserStore());
IdentityUserStore(
oData.Result.Identities.map(identityData => {
const identity = new IdentityModel(

View file

@ -102,17 +102,6 @@ folderListOptionsBuilder = (
return aResult;
},
/**
* Call the Model/CollectionModel onDestroy() to clear knockout functions/objects
* @param {Object|Array} objectOrObjects
* @returns {void}
*/
delegateRunOnDestroy = (objectOrObjects) => {
objectOrObjects && (isArray(objectOrObjects) ? objectOrObjects : [objectOrObjects]).forEach(
obj => obj.onDestroy && obj.onDestroy()
);
},
/**
* @returns {function}
*/

13
dev/External/ko.js vendored
View file

@ -21,7 +21,18 @@ export const
addSubscribablesTo = (target, subscribables) =>
forEachObjectEntry(subscribables, (key, fn) => target[key].subscribe(fn)),
dispose = disposable => disposable && isFunction(disposable.dispose) && disposable.dispose();
dispose = disposable => disposable && isFunction(disposable.dispose) && disposable.dispose(),
// With this we don't need delegateRunOnDestroy
koArrayWithDestroy = data => {
data = ko.observableArray(data);
data.subscribe(changes =>
changes.forEach(item =>
'deleted' === item.status && null == item.moved && item.value.onDestroy && item.value.onDestroy()
)
, data, 'arrayChange');
return data;
};
ko.bindingHandlers.tooltipErrorTip = {
init: (element, fValueAccessor) => {

View file

@ -1,7 +1,6 @@
import ko from 'ko';
import { koArrayWithDestroy } from 'External/ko';
import { arrayLength, pString } from 'Common/Utils';
import { delegateRunOnDestroy } from 'Common/UtilsUser';
import { i18n } from 'Common/Translator';
import { getFolderFromCacheList } from 'Common/Cache';
@ -65,7 +64,7 @@ export class FilterModel extends AbstractModel {
actionType: FilterAction.MoveTo
});
this.conditions = ko.observableArray();
this.conditions = koArrayWithDestroy();
const fGetRealFolderName = (folderFullName) => {
const folder = getFolderFromCacheList(folderFullName);
@ -211,7 +210,6 @@ export class FilterModel extends AbstractModel {
removeCondition(oConditionToDelete) {
this.conditions.remove(oConditionToDelete);
delegateRunOnDestroy(oConditionToDelete);
}
setRecipients() {

View file

@ -1,8 +1,7 @@
import ko from 'ko';
import { AbstractModel } from 'Knoin/AbstractModel';
import { FilterModel } from 'Model/Filter';
import { arrayLength, pString, b64EncodeJSON } from 'Common/Utils';
import { koArrayWithDestroy } from 'External/ko';
const SIEVE_FILE_NAME = 'rainloop.user';
@ -275,7 +274,7 @@ export class SieveScriptModel extends AbstractModel
hasChanges: false
});
this.filters = ko.observableArray();
this.filters = koArrayWithDestroy();
// this.saving = ko.observable(false).extend({ debounce: 200 });
this.addSubscribables({

View file

@ -1,9 +1,6 @@
import ko from 'ko';
import { getNotification } from 'Common/Translator';
import { forEachObjectValue } from 'Common/Utils';
import { addObservablesTo } from 'External/ko';
import { delegateRunOnDestroy } from 'Common/UtilsUser';
import { SieveUserStore } from 'Stores/User/Sieve';
import Remote from 'Remote/User/Fetch';
@ -76,7 +73,6 @@ export class FiltersUserSettings /*extends AbstractViewSettings*/ {
this.setError((data && data.ErrorMessageAdditional) || getNotification(iError));
} else {
this.scripts.remove(script);
delegateRunOnDestroy(script);
}
},
{name:script.name()}

View file

@ -1,8 +1,7 @@
import ko from 'ko';
import { addObservablesTo } from 'External/ko';
import { addObservablesTo, koArrayWithDestroy } from 'External/ko';
export const AccountUserStore = {
accounts: ko.observableArray(),
accounts: koArrayWithDestroy(),
loading: ko.observable(false).extend({ debounce: 100 }),
getEmailAddresses: () => AccountUserStore.accounts.map(item => item.email)

View file

@ -1,10 +1,10 @@
import ko from 'ko';
import { SettingsGet } from 'Common/Globals';
import { pInt } from 'Common/Utils';
import { addObservablesTo } from 'External/ko';
import { addObservablesTo, koArrayWithDestroy } from 'External/ko';
import Remote from 'Remote/User/Fetch';
export const ContactUserStore = ko.observableArray();
export const ContactUserStore = koArrayWithDestroy();
ContactUserStore.loading = ko.observable(false).extend({ debounce: 200 });
ContactUserStore.importing = ko.observable(false).extend({ debounce: 200 });

View file

@ -1,6 +1,6 @@
import ko from 'ko';
import { koArrayWithDestroy } from 'External/ko';
export const IdentityUserStore = ko.observableArray();
export const IdentityUserStore = koArrayWithDestroy();
IdentityUserStore.getIDS = () => IdentityUserStore.map(item => (item ? item.id() : null))
.filter(value => null !== value);

View file

@ -1,8 +1,8 @@
import ko from 'ko';
import { koArrayWithDestroy } from 'External/ko';
export const SieveUserStore = {
// capabilities
capa: ko.observableArray(),
// Sieve scripts SieveScriptModel
scripts: ko.observableArray()
scripts: koArrayWithDestroy()
}

View file

@ -13,8 +13,9 @@ import {
} from 'Common/EnumsUser';
import { inFocus, pInt, isArray, arrayLength, forEachObjectEntry } from 'Common/Utils';
import { delegateRunOnDestroy, initFullscreen } from 'Common/UtilsUser';
import { initFullscreen } from 'Common/UtilsUser';
import { encodeHtml, HtmlEditor, htmlToPlain } from 'Common/Html';
import { koArrayWithDestroy } from 'External/ko';
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { serverRequest } from 'Common/Links';
@ -237,7 +238,7 @@ class ComposePopupView extends AbstractViewPopup {
this.bcc.focused = ko.observable(false);
this.bcc.focused.subscribe(value => value && (this.sLastFocusedField = 'bcc'));
this.attachments = ko.observableArray();
this.attachments = koArrayWithDestroy();
this.dragAndDropOver = ko.observable(false).extend({ debounce: 1 });
this.dragAndDropVisible = ko.observable(false).extend({ debounce: 1 });
@ -1380,7 +1381,6 @@ class ComposePopupView extends AbstractViewPopup {
const attachment = this.getAttachmentById(id);
if (attachment) {
this.attachments.remove(attachment);
delegateRunOnDestroy(attachment);
oJua && oJua.cancel(id);
}
};
@ -1535,7 +1535,6 @@ class ComposePopupView extends AbstractViewPopup {
this.pgpSign(false);
this.pgpEncrypt(false);
delegateRunOnDestroy(this.attachments());
this.attachments([]);
this.dragAndDropOver(false);

View file

@ -1,4 +1,4 @@
import ko from 'ko';
import { koArrayWithDestroy } from 'External/ko';
import {
SaveSettingsStep,
@ -8,7 +8,7 @@ import {
import { ComposeType } from 'Common/EnumsUser';
import { arrayLength, pInt } from 'Common/Utils';
import { download, delegateRunOnDestroy, computedPaginatorHelper, showMessageComposer } from 'Common/UtilsUser';
import { download, computedPaginatorHelper, showMessageComposer } from 'Common/UtilsUser';
import { Selector } from 'Common/Selector';
import { serverRequestRaw, serverRequest } from 'Common/Links';
@ -66,7 +66,7 @@ class ContactsPopupView extends AbstractViewPopup {
this.contacts = ContactUserStore;
this.viewProperties = ko.observableArray();
this.viewProperties = koArrayWithDestroy();
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
@ -346,10 +346,7 @@ class ContactsPopupView extends AbstractViewPopup {
}
setTimeout(() => {
contacts.forEach(contact => {
ContactUserStore.remove(contact);
delegateRunOnDestroy(contact);
});
contacts.forEach(contact => ContactUserStore.remove(contact));
}, 500);
}
}
@ -373,7 +370,6 @@ class ContactsPopupView extends AbstractViewPopup {
removeProperty(oProp) {
this.viewProperties.remove(oProp);
delegateRunOnDestroy(oProp);
}
/**
@ -397,7 +393,6 @@ class ContactsPopupView extends AbstractViewPopup {
this.viewID(id);
// delegateRunOnDestroy(this.viewProperties());
// this.viewProperties([]);
this.viewProperties(contact.properties);
@ -436,7 +431,6 @@ class ContactsPopupView extends AbstractViewPopup {
this.contactsCount(count);
delegateRunOnDestroy(ContactUserStore());
ContactUserStore(list);
ContactUserStore.loading(false);
@ -516,7 +510,6 @@ class ContactsPopupView extends AbstractViewPopup {
this.search('');
this.contactsCount(0);
delegateRunOnDestroy(ContactUserStore());
ContactUserStore([]);
this.sLastComposeFocusedField = '';

View file

@ -2,7 +2,6 @@ import ko from 'ko';
import { getNotification, i18nToNodes } from 'Common/Translator';
import { addObservablesTo } from 'External/ko';
import { delegateRunOnDestroy } from 'Common/UtilsUser';
import Remote from 'Remote/User/Fetch';
import { FilterModel } from 'Model/Filter';
@ -78,7 +77,6 @@ class SieveScriptPopupView extends AbstractViewPopup {
deleteFilter(filter) {
this.script().filters.remove(filter);
delegateRunOnDestroy(filter);
}
addFilter() {
@ -103,7 +101,6 @@ class SieveScriptPopupView extends AbstractViewPopup {
filters = script.filters(),
index = filters.indexOf(filter);
if (-1 < index) {
delegateRunOnDestroy(filters[index]);
filters[index] = clonedFilter;
script.filters(filters);
}