78 lines
2.7 KiB
JavaScript
78 lines
2.7 KiB
JavaScript
// src/observer.js
|
|
let _activeBinding = null;
|
|
let _noWriteBack = null;
|
|
|
|
export const getActiveBinding = () => _activeBinding;
|
|
export const setActiveBinding = (val) => _activeBinding = val;
|
|
export const getNoWriteBack = () => _noWriteBack;
|
|
export const setNoWriteBack = (val) => _noWriteBack = val;
|
|
|
|
const _notifiers = new Set();
|
|
export const onNotifyUpdate = (fn) => _notifiers.add(fn);
|
|
|
|
export function NewState(defaults = {}, getter = null, setter = null) {
|
|
const _defaults = {};
|
|
const _stateMappings = new Map();
|
|
const _watchers = new Map();
|
|
|
|
const _watchFunc = (k, cb) => {
|
|
if (!_watchers.has(k)) _watchers.set(k, new Set());
|
|
!cb ? _watchers.get(k).clear() : _watchers.get(k).add(cb);
|
|
return () => _watchers.get(k).delete(cb);
|
|
};
|
|
|
|
const _unwatchFunc = (k, cb) => {
|
|
if (_watchers.has(k)) _watchers.get(k).delete(cb);
|
|
};
|
|
|
|
const __getter = getter || (k => _defaults[k]);
|
|
const __setter = setter || ((k, v) => _defaults[k] = v);
|
|
Object.assign(_defaults, defaults);
|
|
|
|
return new Proxy(_defaults, {
|
|
get(target, key) {
|
|
if (key === '__watch') return _watchFunc;
|
|
if (key === '__unwatch') return _unwatchFunc;
|
|
if (key === '__isProxy') return true;
|
|
|
|
if (_activeBinding) {
|
|
if (!_stateMappings.has(key)) _stateMappings.set(key, new Set());
|
|
_stateMappings.get(key).add(_activeBinding);
|
|
if (!_activeBinding.node._states) _activeBinding.node._states = new Set();
|
|
_activeBinding.node._states.add(_stateMappings);
|
|
}
|
|
return __getter(key);
|
|
},
|
|
set(target, key, value) {
|
|
if (__getter(key) !== value) {
|
|
__setter(key, value);
|
|
}
|
|
if (_watchers.has(key)) {
|
|
_watchers.get(key).forEach(cb => {
|
|
const r = cb(value);
|
|
if (r !== undefined) {
|
|
value = r;
|
|
target[key] = value;
|
|
}
|
|
});
|
|
}
|
|
if (_watchers.has(null)) {
|
|
_watchers.get(null).forEach(cb => cb(value));
|
|
}
|
|
if (_stateMappings.has(key)) {
|
|
const bindings = _stateMappings.get(key);
|
|
for (const binding of bindings) {
|
|
if (!binding.node.isConnected) {
|
|
bindings.delete(binding);
|
|
continue;
|
|
}
|
|
if (_noWriteBack !== binding.node) {
|
|
_notifiers.forEach(fn => fn(binding));
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
}
|