UNPKG

relu-core

Version:
296 lines (264 loc) 8.6 kB
var base = require("./base"); var variable = require("./variable"); var restricted = require("./restricted"); module.exports = function rpDelegated(d) { var p = base(); p.constructor = rpDelegated; p.origin = d; d.onChanged(onDelegateChanged); d.onUpdated(onDelegateUpdated); d.onAdded(onDelegateAdded); d.onRemoved(onDelegateRemoved); d.ref(p); var varWritable = { set: function(v) { this.v = v; }, v: false }; var writableRp = null; var currentTargetElementListeners = []; var currentTarget = d._getUndependend(); connect(); varWritable = variable(varWritable.v); p._writable = restricted(varWritable).ref(p); p.onceDisposed(function() { disconnect(); d.removeChangedListener(onDelegateChanged); d.removeUpdatedListener(onDelegateUpdated); d.removeAddedListener(onDelegateAdded); d.removeRemovedListener(onDelegateRemoved); d.unref(p); p._writable.unref(p); }); p.isConst = function() { if(!d.isConst()) return false; if(!currentTarget) return true; if(Array.isArray(currentTarget)) return currentTarget.every(function(item) { return item.isConst(); }); return currentTarget.isConst(); }; p._get = function() { p.depend(); return p._getUndependend(); }; var theArray; if(Array.isArray(currentTarget)) { theArray = currentTarget.map(function(item) { return item._getUndependend(); }); } p._getUndependend = function() { if(!currentTarget) return undefined; if(Array.isArray(currentTarget)) { return theArray; } return currentTarget._getUndependend(); }; p._actionsList = function() { if(!currentTarget) throw new Error("delegated has no target"); if(Array.isArray(currentTarget)) throw new Error("A delegated array is not writable"); return currentTarget._actionsList(); }; p._actionsTarget = function() { if(!currentTarget) throw new Error("delegated has no target"); if(Array.isArray(currentTarget)) return function(idx) { return currentTarget[idx]._actionsTarget() }; return currentTarget._actionsTarget(); }; p._makeAttr = function(name, initial) { return rpDelegated(d.computed(function(x) { return x.attr(name, initial); })); }; var superElement = p._element; p._element = function(x) { if(!currentTarget) throw new Error("delegated has no target"); if(!Array.isArray(currentTarget)) return superElement.call(this, x); return currentTarget[x]; }; var superProperty = p._property; p._property = function(x) { if(!currentTarget) throw new Error("delegated has no target"); if(!Array.isArray(currentTarget)) return superProperty.call(this, x); throw new Error("Cannot get a property of delegated"); }; function disconnect(what, _writableRp, _currentTargetElementListeners) { if(!what) { what = currentTarget; _writableRp = writableRp; writableRp = null; _currentTargetElementListeners = currentTargetElementListeners; } if(Array.isArray(what)) { what.forEach(function(item, idx) { item.removeUpdatedListener(_currentTargetElementListeners[idx].updated); item.removeChangedListener(_currentTargetElementListeners[idx].changed); item.removeAddedListener(_currentTargetElementListeners[idx].added); item.removeRemovedListener(_currentTargetElementListeners[idx].removed); item.removeNestedListener(_currentTargetElementListeners[idx].nested); item.unref(p); }); } else if(what) { if(_writableRp && !_writableRp.isConst()) { _writableRp.removeChangedListener(onWritableChanged); _writableRp.unref(p); _writableRp = null; } what.removeChangedListener(onChanged); what.removeUpdatedListener(onUpdated); what.removeAddedListener(onItemAdded); what.removeRemovedListener(onItemRemoved); what.removeNestedListener(onItemNested); what.unref(p); } } function connect() { if(Array.isArray(currentTarget)) { currentTargetElementListeners = []; currentTarget.forEach(function(item) { var l = { target: item, updated: onElementUpdated.bind(null, item), changed: onElementChanged.bind(null, item), added: onElementAdded.bind(null, item), removed: onElementRemoved.bind(null, item), nested: onElementNested.bind(null, item) }; currentTargetElementListeners.push(l); item.onUpdated(l.updated); item.onChanged(l.changed); item.onAdded(l.added); item.onRemoved(l.removed); item.onNested(l.nested); item.ref(p); }); varWritable.set(false); } else if(currentTarget) { var _writableRp = currentTarget.writable(); if(!_writableRp.isConst()) { _writableRp.onChanged(onWritableChanged); _writableRp.ref(p); writableRp = _writableRp; } varWritable.set(_writableRp._getUndependend()); currentTarget.onChanged(onChanged); currentTarget.onUpdated(onUpdated); currentTarget.onAdded(onItemAdded); currentTarget.onRemoved(onItemRemoved); currentTarget.onNested(onItemNested); currentTarget.ref(p); } else { varWritable.set(false); } } function onDelegateUpdated(newTarget) { if(newTarget === currentTarget) return; var old = p._getUndependend(); var oldTarget = currentTarget; var oldWritableRp = writableRp; var oldCurrentTargetElementListeners = currentTargetElementListeners; currentTarget = newTarget; writableRp = null; connect(); if(oldTarget) disconnect(oldTarget, oldWritableRp, oldCurrentTargetElementListeners); if(Array.isArray(currentTarget)) { theArray = currentTarget.map(function(item) { return item._getUndependend(); }); } var _value = p._getUndependend(); if(_value !== old) { p._updated(_value, old); } } function onDelegateAdded(idx, item) { var l = { target: item, updated: onElementUpdated.bind(null, item), changed: onElementChanged.bind(null, item), added: onElementAdded.bind(null, item), removed: onElementRemoved.bind(null, item), nested: onElementNested.bind(null, item) }; currentTargetElementListeners.splice(idx, 0, l); item.onUpdated(l.updated); item.onChanged(l.changed); item.onAdded(l.added); item.onRemoved(l.removed); item.onNested(l.nested); item.ref(p); var value = item._getUndependend(); theArray.splice(idx, 0, value); p._added(idx, value); } function onDelegateRemoved(idx, item) { var target = currentTargetElementListeners[idx].target; target.removeUpdatedListener(currentTargetElementListeners[idx].updated); target.removeChangedListener(currentTargetElementListeners[idx].changed); target.removeAddedListener(currentTargetElementListeners[idx].added); target.removeRemovedListener(currentTargetElementListeners[idx].removed); target.removeNestedListener(currentTargetElementListeners[idx].nested); currentTargetElementListeners.splice(idx, 1); var value = theArray.splice(idx, 1)[0]; p._removed(idx, value); target.unref(p); } function onDelegateChanged() { p._changed(); } function onWritableChanged() { if(!writableRp) return; varWritable.set(writableRp._getUndependend()); } function onElementUpdated(item, newValue, oldValue) { currentTarget.forEach(function(_item, idx) { if(_item !== item) return; theArray[idx] = newValue; p._nested("updated", [idx], newValue, oldValue); }); } function onElementChanged(item) { currentTarget.forEach(function(_item, idx) { if(_item !== item) return; p._nested("changed", [idx]); }); p._changedAtAtomicEnd(); } function onElementAdded(item, idx2, element) { currentTarget.forEach(function(_item, idx) { if(_item !== item) return; p._nested("added", [idx], idx2, element); }); } function onElementRemoved(item, idx2, element) { currentTarget.forEach(function(_item, idx) { if(_item !== item) return; p._nested("removed", [idx], idx2, element); }); } function onElementNested(item, event, path, arg1, arg2) { currentTarget.forEach(function(_item, idx) { if(_item !== item) return; p._nested(event, [idx].concat(path), arg1, arg2); }); } function onChanged() { p._changedAtAtomicEnd(); } function onUpdated(n, o) { p._updated(n, o); } function onItemAdded(idx, item) { p._added(idx, item); } function onItemRemoved(idx, item) { p._removed(idx, item); } function onItemNested(event, path, arg1, arg2) { p._nested(event, path, arg1, arg2); } return p; };