avocado-old/packages/entity/trait.js

150 lines
3.3 KiB
JavaScript
Raw Normal View History

2019-03-17 23:45:48 -05:00
import * as I from 'immutable';
2019-03-21 23:13:46 -05:00
import {Vector} from '@avocado/math';
import {Property} from '@avocado/mixins';
2019-03-28 12:56:42 -05:00
import {Resource} from '@avocado/resource';
2019-04-05 22:14:29 -05:00
import {StateSynchronizer} from '@avocado/state';
2019-03-17 23:45:48 -05:00
export class Trait {
constructor(entity, params, state) {
2019-03-17 23:45:48 -05:00
this.entity = entity;
const ctor = this.constructor;
this.params = I.fromJS(ctor.defaultParams()).merge(I.fromJS(params));
this.state = I.fromJS(ctor.defaultState()).merge(I.fromJS(state));
2019-03-17 23:45:48 -05:00
}
destroy() {}
2019-03-17 23:45:48 -05:00
hooks() {
return {};
}
hydrate() {
return Promise.resolve();
}
2019-03-19 11:12:28 -05:00
initialize() {}
2019-03-17 23:45:48 -05:00
label() {
return this.constructor.name;
}
listeners() {
return {};
}
2019-03-20 18:32:54 -05:00
methods() {
return {};
}
2019-04-05 15:16:55 -05:00
patchState(patch) {
2019-04-05 22:14:29 -05:00
for (const step of patch) {
const {op, path, value} = step;
if ('/' === path) {
if (!value.state) {
continue;
}
const undefinedProperties = {};
for (const key in value.state) {
const value = value.state[key];
if (key in this.entity) {
this.entity[key] = value;
}
else {
undefinedProperties[key] = value;
}
}
this.state = this.state.merge(undefinedProperties);
2019-04-05 15:16:55 -05:00
}
else {
2019-04-05 22:14:29 -05:00
const [stepKey, substep] = StateSynchronizer.forwardStep(step);
if ('state' === stepKey) {
const key = substep.path.substr(1);
const undefinedProperties = {};
if (key in this.entity) {
this.entity[key] = substep.value;
}
else {
undefinedProperties[key] = substep.value;
}
this.state = this.state.merge(undefinedProperties);
}
2019-04-05 15:16:55 -05:00
}
}
}
2019-03-17 23:45:48 -05:00
toJSON() {
return {
params: this.params.toJS(),
state: this.state.toJS(),
};
}
static contextType() {
return {};
}
static defaultParams() {
return {};
}
static defaultState() {
return {};
}
static dependencies() {
return [];
}
static type() {
return this.name.toLowerCase();
}
}
2019-03-23 23:24:18 -05:00
export function StateProperty(key, meta = {}) {
2019-03-17 23:45:48 -05:00
return (Superclass) => {
meta.emit = meta.emit || function(...args) {
this.entity.emit(...args);
};
meta.get = meta.get || function(value) {
return this.state.get(key);
};
meta.set = meta.set || function(value) {
this.state = this.state.set(key, value);
};
return Property(key, meta)(Superclass);
2019-03-17 23:45:48 -05:00
}
}
2019-03-21 23:13:46 -05:00
2019-03-23 23:24:18 -05:00
StateProperty.Vector = (vector, x, y, meta = {}) => {
2019-03-21 23:13:46 -05:00
return (Superclass) => {
meta.default = undefined;
meta.emit = meta.emit || function(...args) {
this.entity.emit(...args);
};
meta.get = meta.get || function() {
return [
this.state.get(x),
this.state.get(y),
];
};
meta.set = meta.set || function(vector) {
if (meta.track && meta.emit) {
if (this.state.get(x) !== vector[0]) {
meta.emit.call(this, `${x}Changed`, this.state.get(x), vector[0]);
}
if (this.state.get(y) !== vector[1]) {
meta.emit.call(this, `${y}Changed`, this.state.get(y), vector[1]);
}
}
this.state = this.state.merge({
[x]: vector[0],
[y]: vector[1],
});
};
return Vector.Mixin(vector, x, y, meta)(Superclass);
};
}