diff --git a/dev/App/User.js b/dev/App/User.js index b46f9a23e..3fefd7b79 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -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( diff --git a/dev/Common/UtilsUser.js b/dev/Common/UtilsUser.js index 492f3cb07..d9fd01e98 100644 --- a/dev/Common/UtilsUser.js +++ b/dev/Common/UtilsUser.js @@ -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} */ diff --git a/dev/External/ko.js b/dev/External/ko.js index 133c03013..4a247e7b2 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -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) => { diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js index 242c3223b..defaeac09 100644 --- a/dev/Model/Filter.js +++ b/dev/Model/Filter.js @@ -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() { diff --git a/dev/Model/SieveScript.js b/dev/Model/SieveScript.js index 7db1e79f1..3d0a4e09a 100644 --- a/dev/Model/SieveScript.js +++ b/dev/Model/SieveScript.js @@ -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({ diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js index 1c4756d84..52f97543a 100644 --- a/dev/Settings/User/Filters.js +++ b/dev/Settings/User/Filters.js @@ -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()} diff --git a/dev/Stores/User/Account.js b/dev/Stores/User/Account.js index 3ebf33c74..4dc389326 100644 --- a/dev/Stores/User/Account.js +++ b/dev/Stores/User/Account.js @@ -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) diff --git a/dev/Stores/User/Contact.js b/dev/Stores/User/Contact.js index ad42fd925..e2e19f8f5 100644 --- a/dev/Stores/User/Contact.js +++ b/dev/Stores/User/Contact.js @@ -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 }); diff --git a/dev/Stores/User/Identity.js b/dev/Stores/User/Identity.js index 4e0f3cbf1..cc4794718 100644 --- a/dev/Stores/User/Identity.js +++ b/dev/Stores/User/Identity.js @@ -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); diff --git a/dev/Stores/User/Sieve.js b/dev/Stores/User/Sieve.js index 0c9d50d71..9272c2ebf 100644 --- a/dev/Stores/User/Sieve.js +++ b/dev/Stores/User/Sieve.js @@ -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() } diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 05832e299..088f3bb49 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -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); diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js index e80fc8f4e..364cf8c15 100644 --- a/dev/View/Popup/Contacts.js +++ b/dev/View/Popup/Contacts.js @@ -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 = ''; diff --git a/dev/View/Popup/SieveScript.js b/dev/View/Popup/SieveScript.js index e67cc404d..bc66642ec 100644 --- a/dev/View/Popup/SieveScript.js +++ b/dev/View/Popup/SieveScript.js @@ -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); }