Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Created November 29, 2023 23:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfkaye/548622151971122110bf4047ae3ac432 to your computer and use it in GitHub Desktop.
Save dfkaye/548622151971122110bf4047ae3ac432 to your computer and use it in GitHub Desktop.
onpropertychange signal v.8 -- trying to simplify the prototype stack
// 26 September 2023
// onpropertychange signal v.8
// cont'd from https://gist.github.com/dfkaye/3affad4c43e363a84ac4320eae375129
// Going back to v.1 prototype enhancement/pollution, (see
// https://gist.github.com/dfkaye/619c5f31080fce2cd383ac966e132311), trying to
// simplify the prototype stack.
// The signals and delegate properties are assigned on the target using the
// Object.defineProperty API (which I guess I like), but the notify, on, off
// parts I'm not so sure about. signal(handler) means use this one handler to
// report changes, on(prop) should report changes to that prop only, and
// off(prop) should stop watching that prop.
// Unfortunately, we still have yet to figure out how to get Array.push() to
// report changes to an index and/or the array length, making this solution yet
// another hand-waving exercise...
// EventTarget.prototype.signal = function (h) {
Object.prototype.signal = function (h) {
function map(t, f) {
return function () { return f.apply(t, [...arguments]); };
}
var target = this;
(typeof h == "function")
|| (h = function (e) {
return target instanceof EventTarget
? target.dispatchEvent(e)
: (new EventTarget).dispatchEvent(e);
});
Object.assign(target, {
notify: h,
off: target.off || function(property) {
target.signals.delete(property);
return target.proxy;
},
on: target.on || function(property) {
target.signals.add(property);
return target.proxy;
}
});
var { signals, delegate } = target;
!('signals' in target) && (
signals = new Set,
Object.defineProperty(target, "signals", {
value: signals
})
);
!('delegate' in target) && (
delegate = {},
Object.defineProperty(target, "delegate", {
value: delegate
})
);
var handler = {
get(target, key) {
var { delegate } = target;
if (typeof delegate[key] == "function") {
return delegate[key];
}
var value = Reflect.get(target, key);
return typeof value == "function"
? delegate[key] = map(target, value)
: value;
},
set(target, key, value) {
var previous = Reflect.get(target, key);
if (previous === value) {
return true;
}
Reflect.set(target, key, value);
var { delegate } = target;
if (typeof value == "function" && key in delegate) {
delegate[key] = null;
}
if (!(target.signals.has(key))) {
return true;
}
var event = new CustomEvent("signal", {
detail: { propertyName: key, value, previous }
});
for (var [name, value] of Object.entries(event.detail)) {
Object.defineProperty(event, name, {
value,
enumerable: true
});
}
Object.defineProperty(event, 'target', {
value: target,
enumerable: true
});
target.notify(event);
return true;
// return target.dispatchEvent(event);
}
};
return new Proxy(this, handler);
}
/* test it out */
function f(e) {
console.log("f")
console.log(e);
}
function h(e) {
console.log(e.target.outerHTML);
console.warn(e.propertyName);
e.propertyName = null;
delete e.propertyName;
console.log(e.propertyName);
}
var input = document.createElement('input').signal(h);
//input.signal( f );
input.setAttribute("value", "some value")
input.on('name');
input.setAttribute("name", "test");
//input.addEventListener("signal", h);
input.name = " ... ";
input.name = "abc";
input.name = "DEF";
input.on('value');
//input.addEventListener("signal", h);
input.value = "ZYX";
input.value = "wvu";
input.value = " ... ";
input.on("id");
input.setAttribute("id", "color: red;");
var array = ['a', 'b', 'c'].signal( f );
//array.signal( h );
array.on('length');
// works
array.length = 5;
// doesn't work
array.push('d');
array.join(", ");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment