steal('can/util', 'can/util/object/isplain', function(can){
var mapHelpers = {Helper functions that are primarily used to serialize
a map, or track the maps created from plain JavaScript objects.
can.Map handles cycles in objects nicely!
steal('can/util', 'can/util/object/isplain', function(can){
var mapHelpers = { attrParts: function (attr, keepKey) {Keep key intact
if (keepKey ) {
return [attr];
}Split key on ‘.’
return typeof attr === "object" ? attr : ("" + attr)
.split(".");
}, canMakeObserve: function (obj) {
return obj && !can.isPromise(obj) && (can.isArray(obj) || can.isPlainObject(obj) );
},Serializes a Map or Map.List by recursively calling the how
method on any child objects. This is able to handle
cycles.
map - the map or list to serialize.
how - the method to call recursively.
where - the target Object or Array that becomes the serialized result.
serialize: (function(){A temporary mapping of map cids to the serialized result.
var serializeMap = null;
return function (map, how, where) {
var cid = can.cid(map),
firstSerialize = false;If there isn’t an existing serializeMap, this means
this is the initial non-recursive call to this function.
We mark this as the first call, and then setup the serializeMap.
The serialize map is further devided into how because
.serialize might call .attr.
if(!serializeMap) {
firstSerialize = true;
serializeMap = {
attr: {},
serialize: {}
};
}
serializeMap[how][cid] = where;Go through each property.
map.each(function (val, name) {If the value is an object, and has an attr or serialize function.
var result,
isObservable = can.isMapLike(val),
serialized = isObservable && serializeMap[how][can.cid(val)];
if( serialized ) {
result = serialized;
} else {special attr or serializer
if(map["___"+how]) {
result = map["___"+how](name, val);
} else {
result = mapHelpers.getValue(map, name, val, how);
}
}this is probably removable
if(result !== undefined){
where[name] = result;
}
});
if(firstSerialize) {
serializeMap = null;
}
return where;
};
})(), getValue: function(map, name, val, how){
if( can.isMapLike(val) ) {
return val[how]();
} else {
return val;
}
}, define: null,Adds a compute so it will control the behavior of an attribute. Each computedAttrs object has:
compute - the compute that will be read and updated.count - the number of bindings to this individual property.
This is used to know when to bind handler to the compute.handler - a function that when bound to compute forwards all
events to map. addComputedAttr: function(map, attrName, compute){
map._computedAttrs[attrName] = {
compute: compute,
count: 0,
handler: function (ev, newVal, oldVal) {
map._triggerChange(attrName, "set", newVal, oldVal, ev.batchNum);
}
};
},Tracks map instances created from JS objects.
This should be called whenever an instance is created for a particular object.
This may return a teardown function that should be called after all instances
might be created.
While creating map instances from plain ole JS objects (POJOs), it’s possible that the same JS object exists as two different properties and we want only one map instance created for one JS object.
var obj = {name: "I am everywhere"}
var map = new can.Map({obj1: obj, obj2: obj});
ok( map.attr("obj1") === map.attr("obj2") )
This works by temporarily adding a cid to any found POJO object
and storing it in a temporary Object that maps those cids to
the POJO and the instance created for it.
The teardown function removes those temporary cids and
clears the map for memory safety.
addToMap: function addToMap(obj, instance) {
var teardown;Setup a fresh mapping if madeMap is missing.
if (!madeMap) {
teardown = teardownMap;
madeMap = {};
}Record if Object has a _cid before adding one.
var hasCid = obj._cid;
var cid = can.cid(obj);Only update if there already isn’t one already.
if (!madeMap[cid]) {
madeMap[cid] = {
obj: obj,
instance: instance,
added: !hasCid
};
}
return teardown;
},Returns the map instance already created for this object obj or
undefined if nothing has been already created.
getMapFromObject: function (obj) {
return madeMap && madeMap[obj._cid] && madeMap[obj._cid].instance;
},
twoLevelDeepExtend: function (destination, source) {
for (var prop in source) {
destination[prop] = destination[prop] || {};
can.simpleExtend(destination[prop], source[prop]);
}
}
};A temporary map of Maps that have been made from plain JS objects.
{POJO_CID: {obj: POJO, instance: MAP, added: Boolean}}
var madeMap = null; var teardownMap = function () {
for (var cid in madeMap) {
if (madeMap[cid].added) {
delete madeMap[cid].obj._cid;
}
}
madeMap = null;
};
return mapHelpers;
});