Skip to content

Instantly share code, notes, and snippets.

@imjoshdean
Created November 20, 2014 21:56
Show Gist options
  • Select an option

  • Save imjoshdean/92e1126f9988f1e605fd to your computer and use it in GitHub Desktop.

Select an option

Save imjoshdean/92e1126f9988f1e605fd to your computer and use it in GitHub Desktop.
/*!
* CanJS - 2.1.3
* http://canjs.us/
* Copyright (c) 2014 Bitovi
* Mon, 25 Aug 2014 21:51:38 GMT
* Licensed MIT
* Includes: can/map/define
* Download from: http://canjs.com
*/
(function(undefined) {
// ## map/define/define.js
var __m1 = (function(can) {
can.Map.helpers.define = function(Map) {
var define = Map.prototype.define;
Map.defaultGenerators = {};
for (var prop in define) {
if ("value" in define[prop]) {
if (typeof define[prop].value === "function") {
Map.defaultGenerators[prop] = define[prop].value;
} else {
Map.defaults[prop] = define[prop].value;
}
}
if (typeof define[prop].Value === "function") {
(function(Constructor) {
Map.defaultGenerators[prop] = function() {
return new Constructor();
};
})(define[prop].Value);
}
}
};
var oldSetupDefaults = can.Map.prototype._setupDefaults;
can.Map.prototype._setupDefaults = function() {
var defaults = oldSetupDefaults.call(this),
Map = this.constructor;
for (var prop in Map.defaultGenerators) {
defaults[prop] = Map.defaultGenerators[prop].call(this);
}
return defaults;
};
var proto = can.Map.prototype,
oldSet = proto.__set;
proto.__set = function(prop, value, current, success, error) {
// check if there's a setter
var errorCallback = function(errors) {
var stub = error && error.call(self, errors);
// if 'validations' is on the page it will trigger
// the error itself and we dont want to trigger
// the event twice. :)
if (stub !== false) {
can.trigger(self, 'error', [
prop,
errors
], true);
}
return false;
},
self = this,
define = this.define && this.define[prop],
setter = define && define.set,
getter = define && define.get;
// if we have a setter
if (setter) {
// call the setter, if returned value is undefined,
// this means the setter is async so we
// do not call update property and return right away
can.batch.start();
var setterCalled = false,
setValue = setter.call(this, value, function(value) {
oldSet.call(self, prop, value, current, success, errorCallback);
setterCalled = true;
}, errorCallback);
if (getter) {
// if there's a getter we do nothing
can.batch.stop();
return;
}
// if it took a setter and returned nothing, don't set the value
else if (setValue === undefined && !setterCalled && setter.length >= 2) {
can.batch.stop();
return;
} else {
if (!setterCalled) {
oldSet.call(self, prop,
// if no arguments, we are side-effects only
setter.length === 0 && setValue === undefined ? value : setValue,
current,
success,
errorCallback);
}
can.batch.stop();
return this;
}
} else {
oldSet.call(self, prop, value, current, success, errorCallback);
}
return this;
};
var converters = {
'date': function(str) {
var type = typeof str;
if (type === 'string') {
str = Date.parse(str);
return isNaN(str) ? null : new Date(str);
} else if (type === 'number') {
return new Date(str);
} else {
return str;
}
},
'number': function(val) {
return +(val);
},
'boolean': function(val) {
if (val === 'false' || val === '0' || !val) {
return false;
}
return true;
},
'*': function(val) {
return val;
},
'string': function(val) {
return '' + val;
}
};
// the old type sets up bubbling
var oldType = proto.__type;
proto.__type = function(value, prop) {
var def = this.define && this.define[prop],
type = def && def.type,
Type = def && def.Type,
newValue = value;
if (typeof type === "string") {
type = converters[type];
}
if (type || Type) {
// If there's a type, convert it.
if (type) {
newValue = type.call(this, newValue, prop);
}
// If there's a Type create a new instance of it
if (Type && !(newValue instanceof Type)) {
newValue = new Type(newValue);
}
// If the newValue is a Map, we need to hook it up
return newValue;
}
// If we pass in a object with define
else if(can.isPlainObject(newValue) && newValue.define) {
newValue = can.Map.extend(newValue);
newValue = new newValue();
}
return oldType.call(this, newValue, prop);
};
var oldRemove = proto._remove;
proto._remove = function(prop, current) {
var remove = this.define && this.define[prop] && this.define[prop].remove,
res;
if (remove) {
can.batch.start();
res = remove.call(this, current);
if (res === false) {
can.batch.stop();
return;
} else {
res = oldRemove.call(this, prop, current);
can.batch.stop();
return res;
}
}
return oldRemove.call(this, prop, current);
};
var oldSetupComputes = proto._setupComputes;
proto._setupComputes = function(defaultsValues) {
oldSetupComputes.apply(this, arguments);
for (var attr in this.define) {
var def = this.define[attr],
get = def.get;
if (get) {
this[attr] = can.compute.async(defaultsValues[attr], get, this);
this._computedBindings[attr] = {
count: 0
};
}
}
};
// Overwrite the invidual property serializer b/c we will overwrite it.
var oldSingleSerialize = can.Map.helpers._serialize;
can.Map.helpers._serialize = function(map, name, val) {
return serializeProp(map, name, val);
};
// If the map has a define serializer for the given attr, run it.
var serializeProp = function(map, attr, val) {
var serializer = map.define && map.define[attr] && map.define[attr].serialize;
if (serializer === undefined) {
return oldSingleSerialize.apply(this, arguments);
} else if (serializer !== false) {
return typeof serializer === "function" ? serializer.call(map, val, attr) : oldSingleSerialize.apply(this, arguments);
}
};
// Overwrite serialize to add in any missing define serialized properties.
var oldSerialize = proto.serialize;
proto.serialize = function(property) {
var serialized = oldSerialize.apply(this, arguments);
if (property) {
return serialized;
}
// add in properties not already serialized
var serializer,
val;
// Go through each property.
for (var attr in this.define) {
// if it's not already defined
if (!(attr in serialized)) {
// check there is a serializer so we aren't doing extra work on serializer:false
serializer = this.define && this.define[attr] && this.define[attr].serialize;
if (serializer) {
val = serializeProp(this, attr, this.attr(attr));
if (val !== undefined) {
serialized[attr] = val;
}
}
}
}
return serialized;
};
return can.Map;
})(window.can, undefined);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment