Created
March 26, 2013 14:34
-
-
Save daffl/5245799 to your computer and use it in GitHub Desktop.
Attributes plugin with recursive call fix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* CanJS - 1.1.5 (2013-03-26) | |
* http://canjs.us/ | |
* Copyright (c) 2013 Bitovi | |
* Licensed MIT | |
*/ | |
(function (can, window, undefined) { | |
// ## can/observe/attributes/attributes.js | |
can.each([can.Observe, can.Model], function (clss) { | |
// in some cases model might not be defined quite yet. | |
if (clss === undefined) { | |
return; | |
} | |
var isObject = function (obj) { | |
return typeof obj === 'object' && obj !== null && obj; | |
}; | |
can.extend(clss, { | |
attributes: {}, | |
convert: { | |
"date": function (str) { | |
var type = typeof str; | |
if (type === "string") { | |
return isNaN(Date.parse(str)) ? null : Date.parse(str) | |
} else if (type === 'number') { | |
return new Date(str) | |
} else { | |
return str | |
} | |
}, | |
"number": function (val) { | |
return parseFloat(val); | |
}, | |
"boolean": function (val) { | |
if (val === 'false' || val === '0' || !val) { | |
return false; | |
} | |
return true; | |
}, | |
"default": function (val, oldVal, error, type) { | |
var construct = can.getObject(type), | |
context = window, | |
realType; | |
// if type has a . we need to look it up | |
if (type.indexOf(".") >= 0) { | |
// get everything before the last . | |
realType = type.substring(0, type.lastIndexOf(".")); | |
// get the object before the last . | |
context = can.getObject(realType); | |
} | |
return typeof construct == "function" ? construct.call(context, val, oldVal) : val; | |
} | |
}, | |
serialize: { | |
"default": function (val, type) { | |
return isObject(val) && val.serialize ? val.serialize() : val; | |
}, | |
"date": function (val) { | |
return val && val.getTime() | |
} | |
} | |
}); | |
// overwrite setup to do this stuff | |
var oldSetup = clss.setup; | |
clss.setup = function (superClass, stat, proto) { | |
var self = this; | |
oldSetup.call(self, superClass, stat, proto); | |
can.each(["attributes"], function (name) { | |
if (!self[name] || superClass[name] === self[name]) { | |
self[name] = {}; | |
} | |
}); | |
can.each(["convert", "serialize"], function (name) { | |
if (superClass[name] != self[name]) { | |
self[name] = can.extend({}, superClass[name], self[name]); | |
} | |
}); | |
}; | |
}); | |
var oldSetup = can.Observe.prototype.setup; | |
can.Observe.prototype.setup = function (obj) { | |
var diff = {}; | |
oldSetup.call(this, obj); | |
can.each(this.constructor.defaults, function (value, key) { | |
if (!this.hasOwnProperty(key)) { | |
diff[key] = value; | |
} | |
}, this); | |
this._init = 1; | |
this.attr(diff); | |
delete this._init; | |
}; | |
can.Observe.prototype.__convert = function (prop, value) { | |
// check if there is a | |
var Class = this.constructor, | |
oldVal = this.attr(prop), | |
type, converter; | |
if (Class.attributes) { | |
// the type of the attribute | |
type = Class.attributes[prop]; | |
converter = Class.convert[type] || Class.convert['default']; | |
} | |
return value === null || !type ? | |
// just use the value | |
value : | |
// otherwise, pass to the converter | |
converter.call(Class, value, oldVal, function () {}, type); | |
}; | |
can.Observe.prototype.serialize = function (attrName, stack) { | |
var where = {}, | |
Class = this.constructor, | |
attrs = {}; | |
stack = can.isArray(stack) ? stack : []; | |
stack.push(this._cid); | |
if (attrName !== undefined) { | |
attrs[attrName] = this[attrName]; | |
} else { | |
attrs = this.__get(); | |
} | |
can.each(attrs, function (val, name) { | |
var type, converter; | |
if (val instanceof can.Observe) { | |
where[name] = stack.indexOf(val._cid) !== -1 ? val.serialize(undefined, stack) : undefined; | |
} else { | |
type = Class.attributes ? Class.attributes[name] : 0; | |
converter = Class.serialize ? Class.serialize[type] : 0; | |
// if the value is an object, and has a attrs or serialize function | |
where[name] = val && typeof val.serialize == 'function' ? | |
// call attrs or serialize to get the original data back | |
val.serialize() : | |
// otherwise if we have a converter | |
converter ? | |
// use the converter | |
converter(val, type) : | |
// or return the val | |
val; | |
} | |
}); | |
return attrName != undefined ? where[attrName] : where; | |
}; | |
})(can, this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment