snappymail/dev/Knoin/AbstractModel.js

120 lines
3.1 KiB
JavaScript
Raw Normal View History

2022-02-17 16:36:29 +08:00
import { isArray, forEachObjectValue, forEachObjectEntry } from 'Common/Utils';
import { dispose, addObservablesTo, addComputablesTo } from 'External/ko';
2016-07-07 05:03:30 +08:00
2020-10-25 18:46:58 +08:00
function typeCast(curValue, newValue) {
2021-09-03 15:30:53 +08:00
if (null != curValue) {
switch (typeof curValue)
{
case 'boolean': return 0 != newValue && !!newValue;
case 'number': return isFinite(newValue) ? parseFloat(newValue) : 0;
case 'string': return null != newValue ? '' + newValue : '';
case 'object':
if (curValue.constructor.reviveFromJson) {
return curValue.constructor.reviveFromJson(newValue);
}
if (isArray(curValue) && !isArray(newValue))
return [];
2020-10-23 21:15:54 +08:00
}
}
2020-10-25 18:46:58 +08:00
return newValue;
}
2019-07-05 03:19:24 +08:00
export class AbstractModel {
2020-10-19 01:19:45 +08:00
constructor() {
/*
if (new.target === AbstractModel) {
2020-10-23 21:15:54 +08:00
throw new Error("Can't instantiate AbstractModel!");
}
*/
2022-02-17 16:36:29 +08:00
this.disposables = [];
2016-07-07 05:03:30 +08:00
}
addObservables(observables) {
addObservablesTo(this, observables);
2020-10-25 18:46:58 +08:00
}
addComputables(computables) {
addComputablesTo(this, computables);
2020-10-25 21:14:14 +08:00
}
addSubscribables(subscribables) {
2022-02-17 16:36:29 +08:00
// addSubscribablesTo(this, subscribables);
forEachObjectEntry(subscribables, (key, fn) => this.disposables.push( this[key].subscribe(fn) ) );
2016-07-07 05:03:30 +08:00
}
/** Called by delegateRunOnDestroy */
2019-07-05 03:19:24 +08:00
onDestroy() {
/** dispose ko subscribables */
2022-02-17 16:36:29 +08:00
this.disposables.forEach(dispose);
/** clear object entries */
// forEachObjectEntry(this, (key, value) => {
forEachObjectValue(this, value => {
/** clear CollectionModel */
2022-09-02 17:52:07 +08:00
(ko.isObservableArray(value) ? value() : value)?.onDestroy?.();
/** destroy ko.observable/ko.computed? */
2022-02-17 16:36:29 +08:00
// dispose(value);
/** clear object value */
// this[key] = null; // TODO: issue with Contacts view
2020-10-25 18:46:58 +08:00
});
2022-02-17 16:36:29 +08:00
// this.disposables = [];
2016-07-07 05:03:30 +08:00
}
/**
* @static
* @param {FetchJson} json
* @returns {boolean}
*/
static validJson(json) {
return !!(json && ('Object/'+this.name.replace('Model', '') === json['@Object']));
}
/**
* @static
* @param {FetchJson} json
* @returns {*Model}
*/
static reviveFromJson(json) {
let obj = this.validJson(json) ? new this() : null;
2022-09-02 17:52:07 +08:00
obj?.revivePropertiesFromJson(json);
2020-10-23 21:15:54 +08:00
return obj;
}
revivePropertiesFromJson(json) {
2023-01-25 16:41:15 +08:00
const model = this.constructor,
valid = model.validJson(json);
valid && forEachObjectEntry(json, (key, value) => {
2021-09-03 15:30:53 +08:00
if ('@' !== key[0]) try {
// key = key[0].toLowerCase() + key.slice(1);
2021-09-03 15:30:53 +08:00
switch (typeof this[key])
{
case 'function':
if (ko.isObservable(this[key])) {
this[key](typeCast(this[key](), value));
// console.log('Observable ' + (typeof this[key]()) + ' ' + (model.name) + '.' + key + ' revived');
}
2021-09-03 15:30:53 +08:00
// else console.log(model.name + '.' + key + ' is a function');
break;
case 'boolean':
case 'number':
case 'object':
case 'string':
this[key] = typeCast(this[key], value);
break;
case 'undefined':
2023-01-25 16:41:15 +08:00
console.log(`Undefined ${model.name}.${key} set`);
2022-11-27 23:05:44 +08:00
this[key] = value;
2023-01-25 16:41:15 +08:00
break;
// default:
// console.log((typeof this[key])+` ${model.name}.${key} not revived`);
2021-09-03 15:30:53 +08:00
// console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived');
}
2021-09-03 15:30:53 +08:00
} catch (e) {
console.log(model.name + '.' + key);
console.error(e);
}
});
2023-01-25 16:41:15 +08:00
return valid;
}
2016-07-07 05:03:30 +08:00
}