Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active August 5, 2023 05:01
Show Gist options
  • Save dfkaye/8701a2d416556aab68da7519b2c5429a to your computer and use it in GitHub Desktop.
Save dfkaye/8701a2d416556aab68da7519b2c5429a to your computer and use it in GitHub Desktop.
Control is a constructor with a 'signal' Map containing different 'types' of event callbacks.
// 4 August 2023
// control.signal.js
// Control is a constructor with a 'signal' Map containing different 'types' of
// event callbacks.
// Similar to EventTarget, but that's coming in the next post at
// https://gist.github.com/dfkaye/f773b85fabf661108ed4ff7a2cdfc61d
// Prototype adds decorator API for adding, removing, and dispatching events.
// Dispatches CustomEvents containing `detail` as { data, source } where `data`
// is the param passed to dispatch() and `source` points back to the control
// instance.
// Supports both event and event.handleEvent interfaces.
function Control(data) {
console.log(data);
return Object.assign(Object.create(CP), {
signal: new Map,
data: Object(data)
});
}
var CP = Control.prototype;
CP.addListener = function (name, h) {
if (!this.signal.has(name)) {
this.signal.set(name, new Set);
}
this.signal.get(name).add(h);
}
CP.removeListener = function (name, h) {
if (!this.signal.has(name)) {
return
}
this.signal.get(name).delete(h);
}
CP.dispatch = function (name, data) {
if (!this.signal.has(name)) {
console.warn(`No signal entry of type "${name}"`);
return
}
for (var h of this.signal.get(name)) {
var event = new CustomEvent(name, { detail: { data, source: this } });
if (typeof h == 'function') {
h.call(this, event);
return;
}
if (typeof h.handleEvent == 'function') {
h.handleEvent.call(h, event);
}
}
}
/* test it out */
/* constructors */
Control({name: 'test'});
// Object { name: "test" }
Control(['a', 'b', 'c']);
// Array(3) [ "a", "b", "c" ]
Control(9);
// 9
Control(new Set([1,2,3]));
// Set []
Control(new Map([
['a', 'x']
]));
// Map(0)
/* instance */
var c = Control('x');
/* no 'a' listener yet */
c.dispatch('a', { value: "test"});
// No signal entry of type "a"
/* add an 'a' listener */
c.addListener('a', function (event) {
console.group(`'${event.type}' handler`);
console.log(event.detail.data);
console.log(event.detail.source);
console.groupEnd(`'${event.type}' handler`);
});
c.dispatch('a', { value: "retest"});
// 'a' handler
// Object { value: "retest" }
// Object { signal: Map(1), data: "x" }
/* add another 'a' listener */
c.addListener('a', function (event) {
console.group(`another '${event.type}' handler`);
console.log(event.detail.data);
console.log(event.detail.source);
console.groupEnd(`another '${event.type}' handler`);
});
c.dispatch('a', { value: "again"});
// 'a' handler
// Object { value: "retest" }
// Object { signal: Map(1), data: "x" }
// another 'a' handler
// Object { value: "again" }
// Object { signal: Map(1), data: "x" }
/* use event data and source values together */
var d = Control(12);
d.addListener('add', function (e) {
console.group("inspect");
console.log("send", e.detail.data.value);
console.log("read ", +e.detail.source.data);
console.log("adds up to", e.detail.data.value + e.detail.source.data);
console.groupEnd("inspect");
});
d.dispatch('add', { value: 34});
// inspect
// send 34
// read 12
// adds up to 46
/* extend the prototype with an add utility */
CP.add = function (n) {
this.dispatch("add", { n, plus: this.data, sum: n + this.data })
};
var s = Control(12);
// 12
s.addListener('add', function (e) {
console.group("add");
console.log("n:", e.detail.data.n);
console.log("plus:", e.detail.data.plus);
console.log("sum:", e.detail.data.sum);
console.groupEnd("add");
});
s.add(1000);
// add
// n: 1000
// plus: 12
// sum: 1012
/* support the handleEvent approach */
var h = Control(100);
h.addListener('add', {
handleEvent(e) {
console.group("handleEvent");
console.log("n:", e.detail.data.n);
console.log("plus:", e.detail.data.plus);
console.log("sum:", e.detail.data.sum);
console.log("value from listener:", this.value);
console.log("all together:", e.detail.data.sum + this.value);
console.groupEnd("handleEvent");
},
value: 1234
});
h.add(9876);
// handleEvent
// n: 9876
// plus: Number { 100 }
// sum: 9976
// value from listener: 1234
// all together: 11210
/* handleEvent when handler object is also a function */
var j = Control(9);
var H = function (e) {
console.group("handleEvent attached to a function");
console.assert(e.detail.data.action === "A", "data.action");
console.assert(e.detail.data.value === "V", "data.value");
console.assert(!('value' in this), "should not have this.value");
console.log(e.detail.data.action, e.detail.data.value, H.value);
console.groupEnd("handleEvent attached to a function");
};
H.handleEvent = function (e) {
throw new Error("should not call handleEvent", H);
};
H.value = "H";
j.addListener('what', H);
j.dispatch("what", { action: "A", value: "V" });
// handleEvent attached to a function
// A V H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment