diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/serpentity/node_collection.js | 4 | ||||
| -rw-r--r-- | lib/serpentity/observable.js | 38 |
2 files changed, 41 insertions, 1 deletions
diff --git a/lib/serpentity/node_collection.js b/lib/serpentity/node_collection.js index d2aa599..cb2f932 100644 --- a/lib/serpentity/node_collection.js +++ b/lib/serpentity/node_collection.js @@ -1,3 +1,5 @@ +import { makeObservable } from './observable.js'; + /* * Node Collections contain nodes, in order to keep the lists of nodes * that belong to each type. @@ -35,7 +37,7 @@ export class NodeCollection extends EventTarget { node.entity = entity; for (const typeName of typeNames) { - node[typeName] = entity.getComponent(types[typeName]); + node[typeName] = makeObservable(entity.getComponent(types[typeName])); } this.nodes.push(node); diff --git a/lib/serpentity/observable.js b/lib/serpentity/observable.js new file mode 100644 index 0000000..a75377d --- /dev/null +++ b/lib/serpentity/observable.js @@ -0,0 +1,38 @@ +/* + * Observable wrapper. Wraps objects so any property modifications emit + * a change event. Used internally for node collections, which make the + * components observable. + */ +class ObserverHandler extends EventTarget { + #emitChangeEvent({property, to, from}) { + const event = new Event('change'); + event.property = property; + event.to = to; + event.from = from; + this.dispatchEvent(event); + } + + get(target, property) { + if (property in this && typeof this[property] === 'function') { + return this[property].bind(this); + } + + return target[property] + } + + set(target, property, value) { + const oldValue = target[property]; + target[property] = value; + this.#emitChangeEvent({property, to: value, from: oldValue}); + return true; + } +} + +/** + * @param {Object} object the object to observe + * @return {tObserverProxy} the proxied object + */ +export function makeObservable(object) { + + return new Proxy(object, new ObserverHandler()); +}; |