2021-12-01 21:23:37 +08:00
|
|
|
import { isArray, isFunction, addObservablesTo, addComputablesTo, forEachObjectValue, forEachObjectEntry } from 'Common/Utils';
|
2020-07-30 03:49:41 +08:00
|
|
|
|
2020-10-26 19:54:03 +08:00
|
|
|
function dispose(disposable) {
|
2021-03-24 21:22:25 +08:00
|
|
|
if (disposable && isFunction(disposable.dispose)) {
|
2020-07-30 03:49:41 +08:00
|
|
|
disposable.dispose();
|
|
|
|
}
|
|
|
|
}
|
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-20 23:39:00 +08:00
|
|
|
}
|
2020-10-25 18:46:58 +08:00
|
|
|
return newValue;
|
2020-10-20 23:39:00 +08:00
|
|
|
}
|
|
|
|
|
2019-07-05 03:19:24 +08:00
|
|
|
export class AbstractModel {
|
2020-10-19 01:19:45 +08:00
|
|
|
constructor() {
|
2020-10-19 01:46:47 +08:00
|
|
|
/*
|
2020-10-20 23:39:00 +08:00
|
|
|
if (new.target === AbstractModel) {
|
2020-10-23 21:15:54 +08:00
|
|
|
throw new Error("Can't instantiate AbstractModel!");
|
2020-10-19 01:46:47 +08:00
|
|
|
}
|
|
|
|
*/
|
2021-03-16 23:08:01 +08:00
|
|
|
this.subscribables = [];
|
2016-07-07 05:03:30 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 19:54:03 +08:00
|
|
|
addObservables(observables) {
|
2021-03-16 17:59:47 +08:00
|
|
|
addObservablesTo(this, observables);
|
2020-10-25 18:46:58 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 19:54:03 +08:00
|
|
|
addComputables(computables) {
|
2021-03-16 17:59:47 +08:00
|
|
|
addComputablesTo(this, computables);
|
2020-10-25 21:14:14 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 19:54:03 +08:00
|
|
|
addSubscribables(subscribables) {
|
2021-12-01 21:23:37 +08:00
|
|
|
forEachObjectEntry(subscribables, (key, fn) => this.subscribables.push( this[key].subscribe(fn) ) );
|
2016-07-07 05:03:30 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 19:54:03 +08:00
|
|
|
/** Called by delegateRunOnDestroy */
|
2019-07-05 03:19:24 +08:00
|
|
|
onDestroy() {
|
2020-10-30 18:49:05 +08:00
|
|
|
/** dispose ko subscribables */
|
2020-10-26 19:54:03 +08:00
|
|
|
this.subscribables.forEach(dispose);
|
|
|
|
/** clear object entries */
|
2021-12-01 21:23:37 +08:00
|
|
|
// forEachObjectEntry(this, (key, value) => {
|
2021-11-01 18:24:11 +08:00
|
|
|
forEachObjectValue(this, value => {
|
2020-10-26 19:54:03 +08:00
|
|
|
/** clear CollectionModel */
|
|
|
|
let arr = ko.isObservableArray(value) ? value() : value;
|
|
|
|
arr && arr.onDestroy && value.onDestroy();
|
|
|
|
/** destroy ko.observable/ko.computed? */
|
|
|
|
dispose(value);
|
|
|
|
/** clear object value */
|
2020-10-30 18:49:05 +08:00
|
|
|
// this[key] = null; // TODO: issue with Contacts view
|
2020-10-25 18:46:58 +08:00
|
|
|
});
|
2020-10-30 18:49:05 +08:00
|
|
|
// this.subscribables = [];
|
2016-07-07 05:03:30 +08:00
|
|
|
}
|
2020-10-19 01:46:47 +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) {
|
2020-10-20 23:39:00 +08:00
|
|
|
let obj = this.validJson(json) ? new this() : null;
|
2020-10-23 21:15:54 +08:00
|
|
|
obj && obj.revivePropertiesFromJson(json);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
revivePropertiesFromJson(json) {
|
|
|
|
let model = this.constructor;
|
2021-09-03 15:30:53 +08:00
|
|
|
if (!model.validJson(json)) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-01 21:23:37 +08:00
|
|
|
forEachObjectEntry(json, (key, value) => {
|
2021-09-03 15:30:53 +08:00
|
|
|
if ('@' !== key[0]) try {
|
|
|
|
key = key[0].toLowerCase() + key.substr(1);
|
|
|
|
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');
|
2020-10-20 23:39:00 +08:00
|
|
|
}
|
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;
|
|
|
|
// fall through
|
|
|
|
case 'undefined':
|
|
|
|
default:
|
|
|
|
// console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived');
|
2020-10-20 23:39:00 +08:00
|
|
|
}
|
2021-09-03 15:30:53 +08:00
|
|
|
} catch (e) {
|
|
|
|
console.log(model.name + '.' + key);
|
|
|
|
console.error(e);
|
|
|
|
}
|
|
|
|
});
|
2020-10-23 21:15:54 +08:00
|
|
|
return true;
|
2020-10-19 01:46:47 +08:00
|
|
|
}
|
|
|
|
|
2016-07-07 05:03:30 +08:00
|
|
|
}
|