vendor/assets/javascripts/can.observe.attributes.js in canjs-rails-0.1.0 vs vendor/assets/javascripts/can.observe.attributes.js in canjs-rails-1.1.2

- old
+ new

@@ -1,293 +1,154 @@ -(function(can, window, undefined){ +/* +* CanJS - 1.1.2 (2012-11-28) +* http://canjs.us/ +* Copyright (c) 2012 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; + } -can.each([ can.Observe, can.Model ], function(clss){ - // in some cases model might not be defined quite yet. - if(clss === undefined){ - return; - } - - can.extend(clss, { - /** - * @attribute can.Observe.static.attributes - * @parent can.Observe.attributes - * - * `can.Observe.attributes` is a property that contains key/value pair(s) of an attribute's name and its - * respective type for using in [can.Observe.static.convert convert] and [can.Observe.prototype.serialize serialize]. - * - * var Contact = can.Observe({ - * attributes : { - * birthday : 'date', - * age: 'number', - * name: 'string' - * } - * }); - * - */ - attributes : {}, - - /** - * @attribute can.Observe.static.convert - * @parent can.Observe.attributes - * - * You often want to convert from what the observe sends you to a form more useful to JavaScript. - * For example, contacts might be returned from the server with dates that look like: "1982-10-20". - * We can observe to convert it to something closer to `new Date(1982,10,20)`. - * - * Convert comes with the following types: - * - * - __date__ Converts to a JS date. Accepts integers or strings that work with Date.parse - * - __number__ An integer or number that can be passed to parseFloat - * - __boolean__ Converts "false" to false, and puts everything else through Boolean() - * - * The following sets the birthday attribute to "date" and provides a date conversion function: - * - * var Contact = can.Observe({ - * attributes : { - * birthday : 'date' - * }, - * convert : { - * date : function(raw){ - * if(typeof raw == 'string'){ - * //- Extracts dates formated 'YYYY-DD-MM' - * var matches = raw.match(/(\d+)-(\d+)-(\d+)/); - * - * //- Parses to date object and returns - * return new Date(matches[1], - * (+matches[2])-1, - * matches[3]); - * - * }else if(raw instanceof Date){ - * return raw; - * } - * } - * } - * },{}); - * - * var contact = new Contact(); - * - * //- calls convert on attribute set - * contact.attr('birthday', '4-26-2012') - * - * contact.attr('birthday'); //-> Date - * - * ## Assocations and Convert - * - * If you have assocations defined within your model(s), you can use convert to automatically - * call seralize on those models. - * - * can.Model("Contact",{ - * attributes : { - * tasks: "Task.models" - * } - * }, {}); - * - * can.Model("Task",{ - * attributes : { - * due : 'date' - * } - * },{}); - * - * var contact = new Contact({ - * tasks: [ new Task({ - * due: new Date() - * }) ] - * }); - * - * contact.seralize(); - * //-> { tasks: [ { due: 1333219754627 } ] } - * - */ - 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 + 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) { + return Boolean(val === "false" ? 0 : val); + }, + "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; } }, - "number": function( val ) { - return parseFloat(val); - }, - "boolean": function( val ) { - return Boolean(val === "false" ? 0 : val); - }, - "default": function( val, 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); + + serialize: { + "default": function (val, type) { + return isObject(val) && val.serialize ? val.serialize() : val; + }, + "date": function (val) { + return val && val.getTime() } - return typeof construct == "function" ? construct.call(context, val) : val; } - }, - /** - * @attribute can.Observe.static.serialize - * @parent can.Observe.attributes - * - * `can.Observe.static.seralize` is object of name-function pairs that are used to - * serialize attributes. - * - * Similar to [can.Observe.convert], in that the keys of this object correspond to - * the types specified in [can.Observe.attributes]. - * - * By default every attribute will be passed through the 'default' serialization method - * that will return the value if the property holds a primitive value (string, number, ...), - * or it will call the "serialize" method if the property holds an object with the "serialize" method set. - * - * For example, to serialize all dates to ISO format: - * - * var Contact = can.Observe({ - * attributes : { - * birthday : 'date' - * }, - * serialize : { - * date : function(val, type){ - * return new Date(val).toISOString(); - * } - * } - * },{}); - * - * var contact = new Contact({ - * birthday: new Date("Oct 25, 1973") - * }).serialize(); - * //-> { "birthday" : "1973-10-25T05:00:00.000Z" } - * - */ - 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]); + } + }); + }; }); - - // overwrite setup to do this stuff - var oldSetup = clss.setup; - - /** - * @hide - * @attribute can.Observe.static.setup - * @parent can.Observe.attributes - * - * `can.Observe.static.setup` overrides default `can.Observe` setup to provide - * functionality for attributes. - * - */ - clss.setup = function(superClass, stat, proto){ - var self = this; - oldSetup.call(self, superClass, stat, proto); - can.each(["attributes", "validations"], function( name ) { - if (!self[name] || superClass[name] === self[name] ) { - self[name] = {}; - } - }); + var oldSetup = can.Observe.prototype.setup; - can.each(["convert", "serialize"], function( name ) { - if ( superClass[name] != self[name] ) { - self[name] = can.extend({}, superClass[name], self[name]); + 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; }; -}); -/** - * @hide - * @function can.Observe.prototype.convert - * @parent can.Observe.attributes - */ -can.Observe.prototype.__convert = function(prop, value){ - // check if there is a + can.Observe.prototype.__convert = function (prop, value) { + // check if there is a + var Class = this.constructor, + oldVal = this.attr(prop), + type, converter; - var Class = this.constructor, - val, 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, function() {}, type); -}; + if (Class.attributes) { + // the type of the attribute + type = Class.attributes[prop]; + converter = Class.convert[type] || Class.convert['default']; + } -/** - * @function can.Observe.prototype.serialize - * @parent can.Observe.attributes - * - * `can.Observe.prototype.serialize` serializes an object for the object. - * Serialized data is typically used to send back to a server. - * - * You can set the serialization methods similar to the convert methods: - * - * var Contact = can.Observe({ - * attributes : { - * birthday : 'date' - * }, - * serialize : { - * date : function( val, type ){ - * return val.getYear() + - * "-" + (val.getMonth() + 1) + - * "-" + val.getDate(); - * } - * } - * },{}) - * - * var contact = new Contact(); - * contact.attr('birthday', new Date()); - * contact.serialize() - * //-> { birthday: 'YYYY-MM-DD' } - * - * You can also get and serialize an individual property by passing the attribute - * name to the `serialize` function. Building on the above demo, we can serialize - * the `birthday` attribute only. - * - * contact.serialize('birthday') //-> 'YYYY-MM-DD' - * - * @param {Object} attrName (optional) when passed returns only that attribute name - */ -can.Observe.prototype.serialize = function(attrName){ - var where = {}, - Class = this.constructor, - attrs = {}; - - if(attrName != undefined){ - attrs[attrName] = this[attrName]; - } else { - attrs = this.__get(); - } - - can.each(attrs, function( val, name ) { - var type = Class.attributes[name], - converter= Class.serialize[type]; - - // 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 ? + 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) { + var where = {}, + Class = this.constructor, + attrs = {}; + + if (attrName != undefined) { + attrs[attrName] = this[attrName]; + } else { + attrs = this.__get(); + } + + can.each(attrs, function (val, name) { + var type, converter; + + 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) : + converter(val, type) : // or return the val val - }); - - return attrName != undefined ? where[attrName] : where; -}; + }); -})(this.can, this ) + return attrName != undefined ? where[attrName] : where; + }; + +})(can, this); \ No newline at end of file