Jump To …

can.observe.attributes.js

/*!
* CanJS - 1.1.4 (2013-02-05)
* 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;
    }

    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) {
    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) :

or return the val

      val
    });

    return attrName != undefined ? where[attrName] : where;
  };

})(can, this);