Last active
August 5, 2023 05:01
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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