aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/serpentity/node_collection.js4
-rw-r--r--lib/serpentity/observable.js38
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());
+};