UNPKG

can-observation

Version:

Core observable indicators

180 lines (152 loc) 4.65 kB
var Observation = require('can-observation'); var CID = require('can-cid'); var queues = require("can-queues"); var canReflect = require("can-reflect"); var canSymbol = require("can-symbol"); var KeyTree = require("can-key-tree"); var eventQueue = require("can-event-queue/map/map"); var ObservationRecorder = require("can-observation-recorder"); // a simple observable and compute to test // behaviors that require nesting of Observations var simpleObservable = function(value){ var obs = { get: function(){ ObservationRecorder.add(this, "value"); return this.value; }, set: function(value){ var old = this.value; this.value = value; this.dispatch("value",[value, old]); }, value: value }; eventQueue(obs); CID(obs); // keyName => queueName => handlers return obs; }; var simpleCompute = function(getter, name, primaryDepth){ var observation, fn, handlers; function dispatchEvents(newVal, oldVal) { queues.batch.start(); queues.enqueueByQueue(handlers.getNode(["direct"]), fn, [newVal, oldVal], function(handler, context, args){ return {priority: context._primaryDepth}; }, [name+" changed to ",newVal]); var event = {type: "change", batchNum: queues.batch.number()}; queues.enqueueByQueue(handlers.getNode(["event"]), fn, [event,newVal, oldVal], function(handler, context, args){ return {priority: context._primaryDepth}; },[name+" changed to ",newVal]); queues.batch.stop(); } handlers = new KeyTree([Object,Object, Array],{ onFirst: function(){ fn.bound = true; canReflect.onValue(observation, dispatchEvents) observation.onBound(); }, onEmpty: function(){ fn.bound = false; canReflect.offValue(observation, dispatchEvents) } }); fn = function(){ ObservationRecorder.add(fn,"change"); return observation.get(); }; CID(fn, name); fn.updater = function(newVal, oldVal){ }; canReflect.assignSymbols(fn, { "can.onValue": function(key, handler, queueName) { handlers.add(["direct",queueName || "mutate", handler]); }, "can.offValue": function(key, handler, queueName) { handlers.delete(["direct",queueName || "mutate", handler]); } }); canReflect.assign(fn, { "addEventListener": function(key, handler){ handlers.add(["event", "mutate", handler]); }, "removeEventListener": function(key, handler){ handlers.delete(["event", "mutate", handler]); } }); fn.on = fn.addEventListener; fn.off = fn.removeEventListener; observation = new Observation(getter, null, {priority: primaryDepth || 0}); fn.observation = observation; return fn; }; var reflectiveCompute = function(getter, name){ var observation, fn; fn = function(){ ObservationRecorder.add(fn); return observation.get(); }; CID(fn, name); observation = new Observation(getter); canReflect.set(fn, canSymbol.for("can.onValue"), function(handler){ canReflect.onValue( observation, handler ); }); canReflect.set(fn, canSymbol.for("can.offValue"), function(handler){ canReflect.offValue( observation, handler ); }); //canReflect.set(fn, Symbol.for("can.getValue"), observation.get.bind(observation)); return fn; }; var reflectiveValue = function(value){ var handlers = new KeyTree([Object,Array]); var fn = function(newValue){ if(arguments.length) { value = newValue; queues.enqueueByQueue(handlers.getNode([]), fn, [newValue], function(){ return {}; }); } else { ObservationRecorder.add(fn); return value; } }; CID(fn); canReflect.set(fn, canSymbol.for("can.onValue"), function(handler, type){ handlers.add([type|| "mutate", handler]) }); canReflect.set(fn, canSymbol.for("can.offValue"), function(handler, type){ handlers.delete([type|| "mutate", handler]) }); return fn; }; var reflectiveObservable = function(value){ var obs = { get: function(){ ObservationRecorder.add(this, "value"); return this.value; }, set: function(value){ this.value = value; queues.enqueueByQueue(this.handlers.getNode(["value"]), this, [value], function(){ return {}; }); }, value: value, handlers: new KeyTree([Object, Object, Array]) }; canReflect.set(obs, canSymbol.for("can.onKeyValue"), function(eventName, handler, queue){ this.handlers.add([eventName, queue|| "mutate", handler]); }); canReflect.set(obs, canSymbol.for("can.offKeyValue"), function(eventName, handler, queue){ this.handlers.delete([eventName, queue|| "mutate", handler]); }); CID(obs); return obs; }; module.exports = { compute: simpleCompute, observable: simpleObservable, reflectiveCompute: reflectiveCompute, reflectiveValue: reflectiveValue, reflectiveObservable: reflectiveObservable };