canjs-rails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,52 @@
1
+ (function(c,n,l){$.extend(c,jQuery,{trigger:function(a,b,d){a.trigger?a.trigger(b,d):$.event.trigger(b,d,a,!0)},addEvent:function(a,b){$([this]).bind(a,b);return this},removeEvent:function(a,b){$([this]).unbind(a,b);return this},buildFragment:function(a,b){var d=$.buildFragment([a],[b]);return d.cacheable?$.clone(d.fragment):d.fragment},$:jQuery});$.each(["bind","unbind","undelegate","delegate"],function(a,b){c[b]=function(){var a=this[b]?this:$([this]);a[b].apply(a,arguments);return this}});$.each("append filter addClass remove data get".split(" "),
2
+ function(a,b){c[b]=function(a){return a[b].apply(a,c.makeArray(arguments).slice(1))}});var pa=$.cleanData;$.cleanData=function(a){$.each(a,function(a,d){c.trigger(d,"destroyed",[],!1)});pa(a)};c.each=function(a,b,d){var c=0,e;if(a)if("number"==typeof a.length&&a.pop){a.attr&&a.attr("length");for(e=a.length;c<e&&!1!==b.call(d||a[c],a[c],c,a);c++);}else for(e in a)if(!1===b.call(d||a[c],a[e],e,a))break;return a};var qa=/==/,ra=/([A-Z]+)([A-Z][a-z])/g,sa=/([a-z\d])([A-Z])/g,ta=/([a-z\d])([A-Z])/g,P=
3
+ /\{([^\}]+)\}/g,s=/"/g,ua=/'/g;c.extend(c,{esc:function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(s,"&#34;").replace(ua,"&#39;")},getObject:function(a,b,d){var a=a?a.split("."):[],f=a.length,e,g=0,h,i,b=c.isArray(b)?b:[b||n];if(!f)return b[0];for(;e=b[g++];){for(i=0;i<f-1&&/^f|^o/.test(typeof e);i++)e=a[i]in e?e[a[i]]:d&&(e[a[i]]={});if(/^f|^o/.test(typeof e)&&(h=a[i]in e?e[a[i]]:d&&(e[a[i]]={}),h!==l))return!1===d&&delete e[a[i]],h}},capitalize:function(a){return a.charAt(0).toUpperCase()+
4
+ a.slice(1)},underscore:function(a){return a.replace(qa,"/").replace(ra,"$1_$2").replace(sa,"$1_$2").replace(ta,"_").toLowerCase()},sub:function(a,b,d){var f=[];f.push(a.replace(P,function(a,g){var h=c.getObject(g,b,d===l?d:!d);return/^f|^o/.test(typeof h)?(f.push(h),""):""+h}));return 1>=f.length?f[0]:f},replacer:P,undHash:/_|-/});var F=0;c.Construct=function(){if(arguments.length)return c.Construct.extend.apply(c.Construct,arguments)};c.extend(c.Construct,{newInstance:function(){var a=this.instance(),
5
+ b;a.setup&&(b=a.setup.apply(a,arguments));a.init&&a.init.apply(a,b||arguments);return a},_inherit:function(a,b,d){c.extend(d||a,a||{})},_overwrite:function(a,b,d,c){a[d]=c},setup:function(a){this.defaults=c.extend(!0,{},a.defaults,this.defaults)},instance:function(){F=1;var a=new this;F=0;return a},extend:function(a,b,d){function f(){if(!F)return this.constructor!==f&&arguments.length?arguments.callee.extend.apply(arguments.callee,arguments):this.constructor.newInstance.apply(this.constructor,arguments)}
6
+ "string"!=typeof a&&(d=b,b=a,a=null);d||(d=b,b=null);var d=d||{},e=this.prototype,g,h,i,j;j=this.instance();c.Construct._inherit(d,e,j);for(g in this)this.hasOwnProperty(g)&&(f[g]=this[g]);c.Construct._inherit(b,this,f);if(a){i=a.split(".");h=i.pop();i=e=c.getObject(i.join("."),n,!0);var o=c.underscore(a.replace(/\./g,"_")),z=c.underscore(h);e[h]=f}c.extend(f,{constructor:f,prototype:j,namespace:i,shortName:h,_shortName:z,fullName:a,_fullName:o});f.prototype.constructor=f;h=[this].concat(c.makeArray(arguments));
7
+ j=f.setup.apply(f,h);f.init&&f.init.apply(f,j||h);return f}});var q=function(a){return a&&"object"===typeof a&&!(a instanceof Date)},G=function(a,b){return c.each(a,function(a){a&&a.unbind&&a.unbind("change"+b)})},H=function(a,b,d){a instanceof u?G([a],d._namespace):a=c.isArray(a)?new u.List(a):new u(a);a.bind("change"+d._namespace,function(f,e){var g=c.makeArray(arguments),f=g.shift();g[0]="*"===b?d.indexOf(a)+"."+g[0]:b+"."+g[0];f.triggeredNS=f.triggeredNS||{};f.triggeredNS[d._namespace]||(f.triggeredNS[d._namespace]=
8
+ !0,c.trigger(d,f,g),c.trigger(d,g[0],g))});return a},Q=0,v=l,R=function(){if(!v)return v=[],!0},p=function(a,b,d){if(!a._init)if(v)v.push([a,{type:b,batchNum:S},d]);else return c.trigger(a,b,d)},S=1,T=function(){var a=v.slice(0);v=l;S++;c.each(a,function(a){c.trigger.apply(c,a)})},C=function(a,b,d){a.each(function(a,e){d[e]=q(a)&&c.isFunction(a[b])?a[b]():a});return d},A=function(a){return function(){return c[a].apply(this,arguments)}},U=A("addEvent"),A=A("removeEvent"),I=function(a){return c.isArray(a)?
9
+ a:(""+a).split(".")},u=c.Construct("can.Observe",{setup:function(){c.Construct.setup.apply(this,arguments)},bind:U,unbind:A,id:"id"},{setup:function(a){this._data={};this._namespace=".observe"+ ++Q;this._init=1;this.attr(a);delete this._init},attr:function(a,b){if(~"ns".indexOf((typeof a).charAt(0))){if(b===l)return u.__reading&&u.__reading(this,a),this._get(a);this._set(a,b);return this}return this._attrs(a,b)},each:function(){return c.each.apply(l,[this.__get()].concat(c.makeArray(arguments)))},
10
+ removeAttr:function(a){var a=I(a),b=a.shift(),d=this._data[b];if(a.length)return d.removeAttr(a);delete this._data[b];b in this.constructor.prototype||delete this[b];p(this,"change",[b,"remove",l,d]);p(this,b,[l,d]);return d},_get:function(a){var a=I(a),b=this.__get(a.shift());return a.length?b?b._get(a):l:b},__get:function(a){return a?this._data[a]:this._data},_set:function(a,b){var d=I(a),c=d.shift(),e=this.__get(c);if(q(e)&&d.length)e._set(d,b);else{if(d.length)throw"can.Observe: Object does not exist";
11
+ this.__convert&&(b=this.__convert(c,b));this.__set(c,b,e)}},__set:function(a,b,c){if(b!==c){var f=this.__get().hasOwnProperty(a)?"set":"add";this.___set(a,q(b)?H(b,a,this):b);p(this,"change",[a,f,b,c]);p(this,a,[b,c]);c&&G([c],this._namespace)}},___set:function(a,b){this._data[a]=b;a in this.constructor.prototype||(this[a]=b)},bind:U,unbind:A,serialize:function(){return C(this,"serialize",{})},_attrs:function(a,b){if(a===l)return C(this,"attr",{});var a=c.extend(!0,{},a),d,f=R(),e=this,g;this.each(function(c,
12
+ d){g=a[d];g===l?b&&e.removeAttr(d):(q(c)&&q(g)?c.attr(g,b):c!=g&&e._set(d,g),delete a[d])});for(d in a)g=a[d],this._set(d,g);f&&T();return this}}),va=[].splice,J=u("can.Observe.List",{setup:function(a,b){this.length=0;this._namespace=".observe"+ ++Q;this._init=1;this.bind("change",c.proxy(this._changes,this));this.push.apply(this,c.makeArray(a||[]));c.extend(this,b);delete this._init},_changes:function(a,b,c,f,e){~b.indexOf(".")||("add"===c?(p(this,c,[f,+b]),p(this,"length",[this.length])):"remove"===
13
+ c?(p(this,c,[e,+b]),p(this,"length",[this.length])):p(this,c,[f,+b]))},__get:function(a){return a?this[a]:this},___set:function(a,b){this[a]=b;+a>=this.length&&(this.length=+a+1)},serialize:function(){return C(this,"serialize",[])},splice:function(a,b){var d=c.makeArray(arguments),f;for(f=2;f<d.length;f++){var e=d[f];q(e)&&(d[f]=H(e,"*",this))}b===l&&(b=d[1]=this.length-a);f=va.apply(this,d);0<b&&(p(this,"change",[""+a,"remove",l,f]),G(f,this._namespace));2<d.length&&p(this,"change",[""+a,"add",d.slice(2),
14
+ f]);return f},_attrs:function(a,b){if(a===l)return C(this,"attr",[]);var a=a.slice(0),c=Math.min(a.length,this.length),f=R(),e;for(e=0;e<c;e++){var g=this[e],h=a[e];q(g)&&q(h)?g.attr(h,b):g!=h&&this._set(e,h)}a.length>this.length?this.push(a.slice(this.length)):a.length<this.length&&b&&this.splice(a.length);f&&T()}});c.each({push:"length",unshift:0},function(a,b){J.prototype[b]=function(){for(var d=arguments[0]&&c.isArray(arguments[0])?arguments[0]:c.makeArray(arguments),f=a?this.length:0,e=0;e<d.length;e++){var g=
15
+ d[e];q(g)&&(d[e]=H(g,"*",this))}e=[][b].apply(this,d);(!this.comparator||!d.length)&&p(this,"change",[""+f,"add",d,l]);return e}});c.each({pop:"length",shift:0},function(a,b){J.prototype[b]=function(){var d=arguments[0]&&c.isArray(arguments[0])?arguments[0]:c.makeArray(arguments),f=a&&this.length?this.length-1:0,d=[][b].apply(this,d);p(this,"change",[""+f,"remove",l,[d]]);d&&d.unbind&&d.unbind("change"+this._namespace);return d}});J.prototype.indexOf=[].indexOf||function(a){return c.inArray(a,this)};
16
+ var wa=function(a,b,d){var f=new c.Deferred;a.then(function(){arguments[0]=b[d](arguments[0]);f.resolve.apply(f,arguments)},function(){f.rejectWith.apply(this,arguments)});return f},xa=0,V=/change.observe\d+/,W=function(a,b,c,f,e){var g;g=[a.serialize()];var h=a.constructor,i;"destroy"==b&&g.shift();"create"!==b&&g.unshift(a[a.constructor.id]);i=h[b].apply(h,g);g=i.pipe(function(c){a[e||b+"d"](c,i);return a});i.abort&&(g.abort=function(){i.abort()});return g.then(c,f)},ya={create:{url:"_shortName",
17
+ type:"post"},update:{data:function(a,b){var b=b||{},d=this.id;b[d]&&b[d]!==a&&(b["new"+c.capitalize(a)]=b[d],delete b[d]);b[d]=a;return b},type:"put"},destroy:{type:"delete",data:function(a){var b={};b[this.id]=a;return b}},findAll:{url:"_shortName"},findOne:{}},X=function(a,b){return function(d){var d=a.data?a.data.apply(this,arguments):d,f=b||this[a.url||"_url"],e=d,g=a.type||"get";if("string"==typeof f){var h=f.split(" "),f={url:h.pop()};h.length&&(f.type=h.pop())}f.data="object"==typeof e&&!c.isArray(e)?
18
+ c.extend(f.data||{},e):e;f.url=c.sub(f.url,f.data,!0);return c.ajax(c.extend({type:g||"post",dataType:"json",success:void 0,error:void 0},f))}};c.Observe("can.Model",{setup:function(a){c.Observe.apply(this,arguments);if(this!==c.Model){var b=this,d=c.proxy(this._clean,b);c.each(ya,function(f,e){c.isFunction(b[e])||(b[e]=X(f,b[e]));if(b["make"+c.capitalize(e)]){var g=b["make"+c.capitalize(e)](b[e]);c.Construct._overwrite(b,a,e,function(){this._super;this._reqs++;return g.apply(this,arguments).then(d,
19
+ d)})}});if(!b.fullName||b.fullName==a.fullName)b.fullName=b._shortName="Model"+ ++xa;this.store={};this._reqs=0;this._url=this._shortName+"/{"+this.id+"}"}},_ajax:X,_clean:function(){this._reqs--;if(!this._reqs)for(var a in this.store)this.store[a]._bindings||delete this.store[a]},models:function(a){if(a){if(a instanceof this.List)return a;var b=this,d=new (b.List||Y),f=c.isArray(a),e=a instanceof Y,e=f?a:e?a.serialize():a.data;c.each(e,function(a){d.push(b.model(a))});f||c.each(a,function(a,b){"data"!==
20
+ b&&(d[b]=a)});return d}},model:function(a){if(a){a instanceof this&&(a=a.serialize());var b=this.store[a[this.id]]?this.store[a[this.id]].attr(a):new this(a);this._reqs&&(this.store[a[this.id]]=b);return b}}},{isNew:function(){var a=this[this.constructor.id];return!(a||0===a)},save:function(a,b){return W(this,this.isNew()?"create":"update",a,b)},destroy:function(a,b){return W(this,"destroy",a,b,"destroyed")},bind:function(a){V.test(a)||(this._bindings||(this.constructor.store[this[this.constructor.id]]=
21
+ this,this._bindings=0),this._bindings++);return c.Observe.prototype.bind.apply(this,arguments)},unbind:function(a){V.test(a)||(this._bindings--,this._bindings||delete this.constructor.store[this[this.constructor.id]]);return c.Observe.prototype.unbind.apply(this,arguments)},___set:function(a,b){c.Observe.prototype.___set.call(this,a,b);a===this.constructor.id&&this._bindings&&(this.constructor.store[this[this.constructor.id]]=this)}});c.each({makeFindAll:"models",makeFindOne:"model"},function(a,b){c.Model[b]=
22
+ function(b){return function(c,e,g){return wa(b.call(this,c),this,a).then(e,g)}}});c.each(["created","updated","destroyed"],function(a){c.Model.prototype[a]=function(b){var d=this.constructor;b&&"object"==typeof b&&this.attr(b.attr?b.attr():b);c.trigger(this,a);c.trigger(this,"change",a);c.trigger(d,a,this)}});var Y=c.Observe.List("can.Model.List",{setup:function(){c.Observe.List.prototype.setup.apply(this,arguments);var a=this;this.bind("change",function(b,c){/\w+\.destroyed/.test(c)&&a.splice(a.indexOf(b.target),
23
+ 1)})}}),za=/^\d+$/,Aa=/([^\[\]]+)|(\[\])/g,Ba=/([^?#]*)(#.*)?$/,Z=function(a){return decodeURIComponent(a.replace(/\+/g," "))};c.extend(c,{deparam:function(a){var b={},d;a&&Ba.test(a)&&(a=a.split("&"),c.each(a,function(a){var a=a.split("="),c=Z(a.shift()),g=Z(a.join("="));current=b;for(var a=c.match(Aa),c=0,h=a.length-1;c<h;c++)current[a[c]]||(current[a[c]]=za.test(a[c+1])||"[]"==a[c+1]?[]:{}),current=current[a[c]];d=a.pop();"[]"==d?current.push(g):current[d]=g}));return b}});var aa=/\:([\w\.]+)/g,
24
+ ba=/^(?:&[^=]+=[^&]*)+/,Ca=function(a){var b=[];c.each(a,function(a,f){b.push(("className"===f?"class":f)+'="'+("href"===f?a:c.esc(a))+'"')});return b.join(" ")},ca=function(a,b){var c=0,f=0,e={},g;for(g in a.defaults)a.defaults[g]===b[g]&&(e[g]=1,c++);for(;f<a.names.length;f++){if(!b.hasOwnProperty(a.names[f]))return-1;e[a.names[f]]||c++}return c},da=!0,K=n.location,w=c.each,t=c.extend;c.route=function(a,b){var b=b||{},d=[],f=a.replace(aa,function(c,f,h){d.push(f);return"([^\\"+(a.substr(h+c.length,
25
+ 1)||"&")+"]"+(b[f]?"*":"+")+")"});c.route.routes[a]={test:RegExp("^"+f+"($|&)"),route:a,names:d,defaults:b,length:a.split("/").length};return c.route};t(c.route,{param:function(a,b){var d,f=0,e,g=a.route,h=0;delete a.route;w(a,function(){h++});w(c.route.routes,function(c){e=ca(c,a);e>f&&(d=c,f=e);if(e>=h)return!1});c.route.routes[g]&&ca(c.route.routes[g],a)===f&&(d=c.route.routes[g]);if(d){var i=t({},a),g=d.route.replace(aa,function(c,b){delete i[b];return a[b]===d.defaults[b]?"":encodeURIComponent(a[b])}),
26
+ j;w(d.defaults,function(a,b){i[b]===a&&delete i[b]});j=c.param(i);b&&c.route.attr("route",d.route);return g+(j?"&"+j:"")}return c.isEmptyObject(a)?"":"&"+c.param(a)},deparam:function(a){var b={length:-1};w(c.route.routes,function(c){c.test.test(a)&&c.length>b.length&&(b=c)});if(-1<b.length){var d=a.match(b.test),f=d.shift(),e=(f=a.substr(f.length-("&"===d[d.length-1]?1:0)))&&ba.test(f)?c.deparam(f.slice(1)):{},e=t(!0,{},b.defaults,e);w(d,function(a,c){a&&"&"!==a&&(e[b.names[c]]=decodeURIComponent(a))});
27
+ e.route=b.route;return e}"&"!==a.charAt(0)&&(a="&"+a);return ba.test(a)?c.deparam(a.slice(1)):{}},data:new c.Observe({}),routes:{},ready:function(a){!1===a&&(da=a);(!0===a||!0===da)&&ea();return c.route},url:function(a,b){b&&(a=t({},L,a));return"#!"+c.route.param(a)},link:function(a,b,d,f){return"<a "+Ca(t({href:c.route.url(b,f)},d))+">"+a+"</a>"},current:function(a){return K.hash=="#!"+c.route.param(a)}});w("bind unbind delegate undelegate attr removeAttr".split(" "),function(a){c.route[a]=function(){return c.route.data[a].apply(c.route.data,
28
+ arguments)}});var fa,L,ea=function(){var a=K.href.split(/#!?/)[1]||"";L=c.route.deparam(a);(!M||a!==ga)&&c.route.attr(L,!0)},ga,M;c.bind.call(n,"hashchange",ea);c.route.bind("change",function(){M=1;clearTimeout(fa);fa=setTimeout(function(){M=0;var a=c.route.data.serialize();K.hash="#!"+(ga=c.route.param(a,!0))},1)});c.bind.call(document,"ready",c.route.ready);(function(){var a=function(a,b,d){c.bind.call(a,b,d);return function(){c.unbind.call(a,b,d)}},b=c.isFunction,d=c.extend,f=c.each,e=[].slice,
29
+ g=/\{([^\}]+)\}/g,h=c.getObject("$.event.special")||{},i=function(a,b,d,f){c.delegate.call(a,b,d,f);return function(){c.undelegate.call(a,b,d,f)}},j=function(a,d){var f="string"==typeof d?a[d]:d;b(f)||(f=a[f]);return function(){a.called=d;return f.apply(a,[this.nodeName?c.$(this):this].concat(e.call(arguments,0)))}},o;c.Construct("can.Control",{setup:function(){c.Construct.setup.apply(this,arguments);if(this!==c.Control){var a;this.actions={};for(a in this.prototype)this._isAction(a)&&(this.actions[a]=
30
+ this._action(a))}},_isAction:function(a){var c=this.prototype[a],d=typeof c;return"constructor"!==a&&("function"==d||"string"==d&&b(this.prototype[c]))&&!(!h[a]&&!z[a]&&!/[^\w]/.test(a))},_action:function(a,b){g.lastIndex=0;if(b||!g.test(a)){var d=b?c.sub(a,[b,n]):a,f=c.isArray(d),e=(f?d[1]:d).match(/^(?:(.*?)\s)?([\w\.\:>]+)$/);return{processor:z[e[2]]||o,parts:e,delegate:f?d[0]:l}}},processors:{},defaults:{}},{setup:function(a,b){var f=this.constructor,e=f.pluginName||f._fullName;this.element=c.$(a);
31
+ e&&"can_control"!==e&&this.element.addClass(e);(e=c.data(this.element,"controls"))||c.data(this.element,"controls",e=[]);e.push(this);this.options=d({},f.defaults,b);this.on();return[this.element,this.options]},on:function(b,d,f,e){if(!b){this.off();var b=this.constructor,d=this._bindings,f=b.actions,e=this.element,g=j(this,"destroy"),h,o;for(h in f)f.hasOwnProperty(h)&&(o=f[h]||b._action(h,this.options),d.push(o.processor(o.delegate||e,o.parts[2],o.parts[1],h,this)));c.bind.call(e,"destroyed",g);
32
+ d.push(function(a){c.unbind.call(a,"destroyed",g)});return d.length}"string"==typeof b&&(e=f,f=d,d=b,b=this.element);"string"==typeof e&&(e=j(this,e));this._bindings.push(d?i(b,c.trim(d),f,e):a(b,f,e));return this._bindings.length},off:function(){var a=this.element[0];f(this._bindings||[],function(b){b(a)});this._bindings=[]},destroy:function(){var a=this.constructor,a=a.pluginName||a._fullName;this.off();a&&"can_control"!==a&&this.element.removeClass(a);a=c.data(this.element,"controls");a.splice(c.inArray(this,
33
+ a),1);c.trigger(this,"destroyed");this.element=null}});var z=c.Control.processors;o=function(b,d,f,e,g){e=j(g,e);return f?i(b,c.trim(f),d,e):a(b,d,e)};f("change click contextmenu dblclick keydown keyup keypress mousedown mousemove mouseout mouseover mouseup reset resize scroll select submit focusin focusout mouseenter mouseleave".split(" "),function(a){z[a]=o})})();c.Control.processors.route=function(a,b,d,f,e){c.route(d||"");var g,h=function(a){if(c.route.attr("route")===(d||"")&&(a.batchNum===l||
34
+ a.batchNum!==g))if(g=a.batchNum,a=c.route.attr(),delete a.route,c.isFunction(e[f]))e[f](a);else e[e[f]](a)};c.route.bind("change",h);return function(){c.route.unbind("change",h)}};var D=c.isFunction,Da=c.makeArray,ha=1,k=c.view=function(a,b,d,f){a=k.render(a,b,d,f);return c.isDeferred(a)?a.pipe(function(a){return k.frag(a)}):k.frag(a)};c.extend(k,{frag:function(a,b){return k.hookup(k.fragment(a),b)},fragment:function(a){a=c.buildFragment(a,document.body);a.childNodes.length||a.appendChild(document.createTextNode(""));
35
+ return a},toId:function(a){return c.map(a.toString().split(/\/|\./g),function(a){if(a)return a}).join("_")},hookup:function(a,b){var d=[],f,e,g,h=0;for(c.each(a.childNodes?c.makeArray(a.childNodes):a,function(a){1===a.nodeType&&(d.push(a),d.push.apply(d,c.makeArray(a.getElementsByTagName("*"))))});g=d[h++];)if(g.getAttribute&&(f=g.getAttribute("data-view-id"))&&(e=k.hookups[f]))e(g,b,f),delete k.hookups[f],g.removeAttribute("data-view-id");return a},hookups:{},hook:function(a){k.hookups[++ha]=a;return" data-view-id='"+
36
+ ha+"'"},cached:{},cache:!0,register:function(a){this.types["."+a.suffix]=a},types:{},ext:".ejs",registerScript:function(){},preload:function(){},render:function(a,b,d,f){D(d)&&(f=d,d=l);var e=Ea(b);if(e.length){var g=new c.Deferred;e.push(ia(a,!0));c.when.apply(c,e).then(function(a){var e=Da(arguments),h=e.pop();if(c.isDeferred(b))b=ja(a);else for(var l in b)c.isDeferred(b[l])&&(b[l]=ja(e.shift()));e=h(b,d);g.resolve(e);f&&f(e)});return g}var h,e=D(f),g=ia(a,e);e?(h=g,g.then(function(a){f(a(b,d))})):
37
+ g.then(function(a){h=a(b,d)});return h}});c.isDeferred=function(a){return a&&D(a.then)&&D(a.pipe)};var ka=function(a,b){if(!a.length)throw"can.view: No template or empty template:"+b;},ia=function(a,b){var d=a.match(/\.[\w\d]+$/),f,e,g,h=function(a){var a=f.renderer(g,a),b=new c.Deferred;b.resolve(a);k.cache&&(k.cached[g]=b);return b};a.match(/^#/)&&(a=a.substr(1));if(e=document.getElementById(a))d="."+e.type.match(/\/(x\-)?(.+)/)[2];!d&&!k.cached[a]&&(a+=d=k.ext);c.isArray(d)&&(d=d[0]);g=c.view.toId(a);
38
+ if(a.match(/^\/\//))var i=a.substr(2),a=!n.steal?"/"+i:steal.root.mapJoin(i);f=k.types[d];if(k.cached[g])return k.cached[g];if(e)return h(e.innerHTML);var j=new c.Deferred;c.ajax({async:b,url:a,dataType:"text",error:function(b){ka("",a);j.reject(b)},success:function(b){ka(b,a);j.resolve(f.renderer(g,b));k.cache&&(k.cached[g]=j)}});return j},Ea=function(a){var b=[];if(c.isDeferred(a))return[a];for(var d in a)c.isDeferred(a[d])&&b.push(a[d]);return b},ja=function(a){return c.isArray(a)&&"success"===
39
+ a[1]?a[0]:a};n.steal&&steal.type("view js",function(a,b){var d=c.view.types["."+a.type],f=c.view.toId(a.rootSrc);a.text="steal('"+(d.plugin||"can/view/"+a.type)+"').then(function($){can.view.preload('"+f+"',"+a.text+");\n})";b()});c.extend(c.view,{register:function(a){this.types["."+a.suffix]=a;n.steal&&steal.type(a.suffix+" view js",function(a,d){var f=c.view.types["."+a.type],e=c.view.toId(a.rootSrc+"");a.text=f.script(e,a.text);d()});c.view[a.suffix]=function(b,c){k.preload(b,a.renderer(b,c))}},
40
+ registerScript:function(a,b,c){return"can.view.preload('"+b+"',"+k.types["."+a].script(b,c)+");"},preload:function(a,b){c.view.cached[a]=(new c.Deferred).resolve(function(a,c){return b.call(a,a,c)})}});var Fa=function(a,b){var d;c.Observe&&(d=c.Observe.__reading,c.Observe.__reading=function(a,b){f.push({obj:a,attr:b})});var f=[],e=a.call(b);c.Observe&&(c.Observe.__reading=d);return{value:e,observed:f}},la=function(a,b,d){var f={},e=!0,g={value:l,teardown:function(){for(var a in f){var b=f[a];b.observe.obj.unbind(b.observe.attr,
41
+ h);delete f[a]}}},h=function(){var a=g.value,b=i();g.value=b;b!==a&&d(b,a)},i=function(){var d=Fa(a,b),g=d.observed,d=d.value;e=!e;c.each(g,function(a){f[a.obj._namespace+"|"+a.attr]?f[a.obj._namespace+"|"+a.attr].matched=e:(f[a.obj._namespace+"|"+a.attr]={matched:e,observe:a},a.obj.bind(a.attr,h))});for(var i in f)g=f[i],g.matched!==e&&(g.observe.obj.unbind(g.observe.attr,h),delete f[i]);return d};g.value=i();g.isListening=!c.isEmptyObject(f);return g};c.compute=function(a,b){if(a.isComputed)return a;
42
+ var d,f=0,e,g=!0;"function"===typeof a?e=function(c){return c===l?d?d.value:a.call(b||this):a.apply(b||this,arguments)}:(e=function(b){if(b===l)return a;var d=a;a=b;d!==b&&c.trigger(e,"change",[b,d]);return b},g=!1);e.isComputed=!0;e.bind=function(h,i){c.addEvent.apply(e,arguments);f===0&&g&&(d=la(a,b||this,function(a,b){c.trigger(e,"change",[a,b])}));f++};e.unbind=function(a,b){c.removeEvent.apply(e,arguments);f--;f===0&&g&&d.teardown()};return e};c.compute.binder=la;var Ga=function(a){eval(a)},
43
+ t=c.extend,ma=/\s*\(([\$\w]+)\)\s*->([^\n]*)/,na=/([^\s]+)=$/,Ha=/(\r|\n)+/g,Ia=/__!!__/g,Ja={"":"span",table:"tr",tr:"td",ol:"li",ul:"li",tbody:"tr",thead:"tr",tfoot:"tr"},B={"class":"className"},oa=c.each(["checked","disabled","readonly","required"],function(a){B[a]=a}),N=function(a,b,d){B[b]?a[B[b]]=-1<c.inArray(b,oa)?!0:d:a.setAttribute(b,d)},Ka=function(a){return"string"==typeof a||"number"==typeof a?c.esc(a):O(a)},O=function(a){if("string"==typeof a)return a;if(!a&&0!=a)return"";var b=a.hookup&&
44
+ function(b,c){a.hookup.call(a,b,c)}||"function"==typeof a&&a;return b?(x.push(b),""):""+a},m=function(a){if(this.constructor!=m){var b=new m(a);return function(a,c){return b.render(a,c)}}"function"==typeof a?this.template={fn:a}:(t(this,a),this.template=La(this.text,this.name))};c.EJS=m;m.prototype.render=function(a,b){a=a||{};return this.template.fn.call(a,a,new m.Helpers(a,b||{}))};t(m,{txt:function(a,b,d,f,e){var g=c.compute.binder(e,f,function(a,b){o(a,b)});if(!g.isListening)return(a||0!==d?Ka:
45
+ O)(g.value);var h,i=function(a){c.bind.call(a,"destroyed",g.teardown);h=a},j=function(a){a||(g.teardown(),c.unbind.call(h,"destroyed",g.teardown))},b=Ja[b]||"span",o;if(0==d)return"<"+b+c.view.hook(a?function(a,b){o=function(a){d.nodeValue=""+a;j(d.parentNode)};var c=b&&11===a.parentNode.nodeType?b:a.parentNode,d=document.createTextNode(g.value);c.insertBefore(d,a);c.removeChild(a);i(c)}:function(a,b){o=function(a){e[0].parentNode&&(e=d(a,e));j(e[0].parentNode)};var b=b&&11===a.parentNode.nodeType?
46
+ b:a.parentNode,d=function(a,d){var e=c.view.frag(a,b),f=c.map(e.childNodes,function(a){return a}),g=d[d.length-1];g.nextSibling?g.parentNode.insertBefore(e,g.nextSibling):g.parentNode.appendChild(e);c.remove(c.$(d));return f},e=d(g.value,[a]);i(b)})+"></"+b+">";if(1===d){var k=g.value.replace(/['"]/g,"").split("=")[0];x.push(function(a){o=function(b){var b=(b||"").replace(/['"]/g,"").split("="),d=b[0];if(d!=k&&k){var e=k;-1<c.inArray(e,oa)?a[e]=!1:a.removeAttribute(e)}d&&(N(a,d,b[1]),k=d)};i(a)});
47
+ return g.value}x.push(function(a){o=function(){N(a,d,h.render())};var b=c.$(a),e;(e=c.data(b,"hooks"))||c.data(b,"hooks",e={});var f=B[d]?a[B[d]]:a.getAttribute(d),b=f.split("__!!__"),h;e[d]?e[d].bindings.push(g):e[d]={render:function(){var a=0;return f.replace(Ia,function(){return O(h.bindings[a++].value)})},bindings:[g],batchNum:l};h=e[d];b.splice(1,0,g.value);N(a,d,b.join(""));i(a)});return"__!!__"},pending:function(){if(x.length){var a=x.slice(0);x=[];return c.view.hook(function(b){c.each(a,function(a){a(b)})})}return""}});
48
+ var Ma=RegExp("(<%%|%%>|<%==|<%=|<%#|<%|%>|<|>|\"|')","g"),y=null,E=s=null,x=[],La=function(a,b){var c=[],f=0,a=a.replace(Ha,"\n");a.replace(Ma,function(b,e,g){g>f&&c.push(a.substring(f,g));c.push(e);f=g+e.length});f<a.length&&c.push(a.substr(f));var e="",g=["var ___v1ew = [];"],h=function(a,b){g.push("___v1ew.push(",'"',a.split("\\").join("\\\\").split("\n").join("\\n").split('"').join('\\"').split("\t").join("\\t"),'"'+(b||"")+");")},i=[],j,k=null,p=!1,m="",n=[],q=0,r;for(y=s=E=null;(r=c[q++])!==
49
+ l;){if(null===k)switch(r){case "<%":case "<%=":case "<%==":p=1;case "<%#":k=r;e.length&&h(e);e="";break;case "<%%":e+="<%";break;case "<":0!==c[q].indexOf("!--")&&(y=1,p=0);e+=r;break;case ">":y=0;p?(h(e,',can.EJS.pending(),">"'),e=""):e+=r;"/"==j.substr(-1)&&(n.pop(),m=n[n.length-1]);break;case "'":case '"':y&&(s&&s===r?s=null:null===s&&(s=r,E=j));default:"<"===j&&(m=r.split(" ")[0],0===m.indexOf("/")&&n.pop()===m.substr(1)?m=n[n.length-1]||m.substr(1):n.push(m)),e+=r}else switch(r){case "%>":switch(k){case "<%":j=
50
+ --e.split("{").length- --e.split("}").length;1==j?(g.push("___v1ew.push(","can.EJS.txt(0,'"+m+"',"+(s?"'"+E.match(na)[1]+"'":y?1:0)+",this,function(){","var ___v1ew = [];",e),i.push({before:"",after:"return ___v1ew.join('')}));\n"})):(f=i.length&&-1==j?i.pop():{after:";"},f.before&&g.push(f.before),g.push(e,";",f.after));break;case "<%=":case "<%==":(j=--e.split("{").length- --e.split("}").length)&&i.push({before:"return ___v1ew.join('')",after:"}));"}),ma.test(e)&&(e=e.match(ma),e="function(__){var "+
51
+ e[1]+"=can.$(__);"+e[2]+"}"),g.push("___v1ew.push(","can.EJS.txt("+("<%="===k?1:0)+",'"+m+"',"+(s?"'"+E.match(na)[1]+"'":y?1:0)+",this,function(){ return ",e,j?"var ___v1ew = [];":"}));")}k=null;e="";break;case "<%%":e+="<%";break;default:e+=r}j=r}e.length&&h(e);g.push(";");h={out:"with(_VIEW) { with (_CONTEXT) {"+g.join("")+" return ___v1ew.join('')}}"};Ga.call(h,"this.fn = (function(_CONTEXT,_VIEW){"+h.out+"});\r\n//@ sourceURL="+b+".js");return h};m.Helpers=function(a,b){this._data=a;this._extras=
52
+ b;t(this,b)};m.Helpers.prototype={list:function(a,b){c.each(a,function(c,f){b(c,f,a)})}};c.view.register({suffix:"ejs",script:function(a,b){return"can.EJS(function(_CONTEXT,_VIEW) { "+(new m({text:b,name:a})).template.out+" })"},renderer:function(a,b){return m({text:b,name:a})}});"function"===typeof define&&define.amd?define("can",[],function(){return c}):n.can=c})(can={},this);
@@ -0,0 +1,293 @@
1
+ (function(can, window, undefined){
2
+
3
+ can.each([ can.Observe, can.Model ], function(clss){
4
+ // in some cases model might not be defined quite yet.
5
+ if(clss === undefined){
6
+ return;
7
+ }
8
+
9
+ can.extend(clss, {
10
+ /**
11
+ * @attribute can.Observe.static.attributes
12
+ * @parent can.Observe.attributes
13
+ *
14
+ * `can.Observe.attributes` is a property that contains key/value pair(s) of an attribute's name and its
15
+ * respective type for using in [can.Observe.static.convert convert] and [can.Observe.prototype.serialize serialize].
16
+ *
17
+ * var Contact = can.Observe({
18
+ * attributes : {
19
+ * birthday : 'date',
20
+ * age: 'number',
21
+ * name: 'string'
22
+ * }
23
+ * });
24
+ *
25
+ */
26
+ attributes : {},
27
+
28
+ /**
29
+ * @attribute can.Observe.static.convert
30
+ * @parent can.Observe.attributes
31
+ *
32
+ * You often want to convert from what the observe sends you to a form more useful to JavaScript.
33
+ * For example, contacts might be returned from the server with dates that look like: "1982-10-20".
34
+ * We can observe to convert it to something closer to `new Date(1982,10,20)`.
35
+ *
36
+ * Convert comes with the following types:
37
+ *
38
+ * - __date__ Converts to a JS date. Accepts integers or strings that work with Date.parse
39
+ * - __number__ An integer or number that can be passed to parseFloat
40
+ * - __boolean__ Converts "false" to false, and puts everything else through Boolean()
41
+ *
42
+ * The following sets the birthday attribute to "date" and provides a date conversion function:
43
+ *
44
+ * var Contact = can.Observe({
45
+ * attributes : {
46
+ * birthday : 'date'
47
+ * },
48
+ * convert : {
49
+ * date : function(raw){
50
+ * if(typeof raw == 'string'){
51
+ * //- Extracts dates formated 'YYYY-DD-MM'
52
+ * var matches = raw.match(/(\d+)-(\d+)-(\d+)/);
53
+ *
54
+ * //- Parses to date object and returns
55
+ * return new Date(matches[1],
56
+ * (+matches[2])-1,
57
+ * matches[3]);
58
+ *
59
+ * }else if(raw instanceof Date){
60
+ * return raw;
61
+ * }
62
+ * }
63
+ * }
64
+ * },{});
65
+ *
66
+ * var contact = new Contact();
67
+ *
68
+ * //- calls convert on attribute set
69
+ * contact.attr('birthday', '4-26-2012')
70
+ *
71
+ * contact.attr('birthday'); //-> Date
72
+ *
73
+ * ## Assocations and Convert
74
+ *
75
+ * If you have assocations defined within your model(s), you can use convert to automatically
76
+ * call seralize on those models.
77
+ *
78
+ * can.Model("Contact",{
79
+ * attributes : {
80
+ * tasks: "Task.models"
81
+ * }
82
+ * }, {});
83
+ *
84
+ * can.Model("Task",{
85
+ * attributes : {
86
+ * due : 'date'
87
+ * }
88
+ * },{});
89
+ *
90
+ * var contact = new Contact({
91
+ * tasks: [ new Task({
92
+ * due: new Date()
93
+ * }) ]
94
+ * });
95
+ *
96
+ * contact.seralize();
97
+ * //-> { tasks: [ { due: 1333219754627 } ] }
98
+ *
99
+ */
100
+ convert: {
101
+ "date": function( str ) {
102
+ var type = typeof str;
103
+ if ( type === "string" ) {
104
+ return isNaN(Date.parse(str)) ? null : Date.parse(str)
105
+ } else if ( type === 'number' ) {
106
+ return new Date(str)
107
+ } else {
108
+ return str
109
+ }
110
+ },
111
+ "number": function( val ) {
112
+ return parseFloat(val);
113
+ },
114
+ "boolean": function( val ) {
115
+ return Boolean(val === "false" ? 0 : val);
116
+ },
117
+ "default": function( val, error, type ) {
118
+ var construct = can.getObject(type),
119
+ context = window,
120
+ realType;
121
+ // if type has a . we need to look it up
122
+ if ( type.indexOf(".") >= 0 ) {
123
+ // get everything before the last .
124
+ realType = type.substring(0, type.lastIndexOf("."));
125
+ // get the object before the last .
126
+ context = can.getObject(realType);
127
+ }
128
+ return typeof construct == "function" ? construct.call(context, val) : val;
129
+ }
130
+ },
131
+ /**
132
+ * @attribute can.Observe.static.serialize
133
+ * @parent can.Observe.attributes
134
+ *
135
+ * `can.Observe.static.seralize` is object of name-function pairs that are used to
136
+ * serialize attributes.
137
+ *
138
+ * Similar to [can.Observe.convert], in that the keys of this object correspond to
139
+ * the types specified in [can.Observe.attributes].
140
+ *
141
+ * By default every attribute will be passed through the 'default' serialization method
142
+ * that will return the value if the property holds a primitive value (string, number, ...),
143
+ * or it will call the "serialize" method if the property holds an object with the "serialize" method set.
144
+ *
145
+ * For example, to serialize all dates to ISO format:
146
+ *
147
+ * var Contact = can.Observe({
148
+ * attributes : {
149
+ * birthday : 'date'
150
+ * },
151
+ * serialize : {
152
+ * date : function(val, type){
153
+ * return new Date(val).toISOString();
154
+ * }
155
+ * }
156
+ * },{});
157
+ *
158
+ * var contact = new Contact({
159
+ * birthday: new Date("Oct 25, 1973")
160
+ * }).serialize();
161
+ * //-> { "birthday" : "1973-10-25T05:00:00.000Z" }
162
+ *
163
+ */
164
+ serialize: {
165
+ "default": function( val, type ) {
166
+ return isObject(val) && val.serialize ? val.serialize() : val;
167
+ },
168
+ "date": function( val ) {
169
+ return val && val.getTime()
170
+ }
171
+ }
172
+ });
173
+
174
+ // overwrite setup to do this stuff
175
+ var oldSetup = clss.setup;
176
+
177
+ /**
178
+ * @hide
179
+ * @attribute can.Observe.static.setup
180
+ * @parent can.Observe.attributes
181
+ *
182
+ * `can.Observe.static.setup` overrides default `can.Observe` setup to provide
183
+ * functionality for attributes.
184
+ *
185
+ */
186
+ clss.setup = function(superClass, stat, proto){
187
+ var self = this;
188
+ oldSetup.call(self, superClass, stat, proto);
189
+
190
+ can.each(["attributes", "validations"], function( name ) {
191
+ if (!self[name] || superClass[name] === self[name] ) {
192
+ self[name] = {};
193
+ }
194
+ });
195
+
196
+ can.each(["convert", "serialize"], function( name ) {
197
+ if ( superClass[name] != self[name] ) {
198
+ self[name] = can.extend({}, superClass[name], self[name]);
199
+ }
200
+ });
201
+ };
202
+ });
203
+
204
+ /**
205
+ * @hide
206
+ * @function can.Observe.prototype.convert
207
+ * @parent can.Observe.attributes
208
+ */
209
+ can.Observe.prototype.__convert = function(prop, value){
210
+ // check if there is a
211
+
212
+ var Class = this.constructor,
213
+ val, type, converter;
214
+
215
+ if(Class.attributes){
216
+ // the type of the attribute
217
+ type = Class.attributes[prop];
218
+ converter = Class.convert[type] || Class.convert['default'];
219
+ }
220
+
221
+ return value === null || !type ?
222
+ // just use the value
223
+ value :
224
+ // otherwise, pass to the converter
225
+ converter.call(Class, value, function() {}, type);
226
+ };
227
+
228
+ /**
229
+ * @function can.Observe.prototype.serialize
230
+ * @parent can.Observe.attributes
231
+ *
232
+ * `can.Observe.prototype.serialize` serializes an object for the object.
233
+ * Serialized data is typically used to send back to a server.
234
+ *
235
+ * You can set the serialization methods similar to the convert methods:
236
+ *
237
+ * var Contact = can.Observe({
238
+ * attributes : {
239
+ * birthday : 'date'
240
+ * },
241
+ * serialize : {
242
+ * date : function( val, type ){
243
+ * return val.getYear() +
244
+ * "-" + (val.getMonth() + 1) +
245
+ * "-" + val.getDate();
246
+ * }
247
+ * }
248
+ * },{})
249
+ *
250
+ * var contact = new Contact();
251
+ * contact.attr('birthday', new Date());
252
+ * contact.serialize()
253
+ * //-> { birthday: 'YYYY-MM-DD' }
254
+ *
255
+ * You can also get and serialize an individual property by passing the attribute
256
+ * name to the `serialize` function. Building on the above demo, we can serialize
257
+ * the `birthday` attribute only.
258
+ *
259
+ * contact.serialize('birthday') //-> 'YYYY-MM-DD'
260
+ *
261
+ * @param {Object} attrName (optional) when passed returns only that attribute name
262
+ */
263
+ can.Observe.prototype.serialize = function(attrName){
264
+ var where = {},
265
+ Class = this.constructor,
266
+ attrs = {};
267
+
268
+ if(attrName != undefined){
269
+ attrs[attrName] = this[attrName];
270
+ } else {
271
+ attrs = this.__get();
272
+ }
273
+
274
+ can.each(attrs, function( val, name ) {
275
+ var type = Class.attributes[name],
276
+ converter= Class.serialize[type];
277
+
278
+ // if the value is an object, and has a attrs or serialize function
279
+ where[name] = val && typeof val.serialize == 'function' ?
280
+ // call attrs or serialize to get the original data back
281
+ val.serialize() :
282
+ // otherwise if we have a converter
283
+ converter ?
284
+ // use the converter
285
+ converter(val, type) :
286
+ // or return the val
287
+ val
288
+ });
289
+
290
+ return attrName != undefined ? where[attrName] : where;
291
+ };
292
+
293
+ })(this.can, this )
@@ -0,0 +1,368 @@
1
+ (function(can, window, undefined){
2
+
3
+ var isArray = can.isArray,
4
+ // essentially returns an object that has all the must have comparisons ...
5
+ // must haves, do not return true when provided undefined
6
+ cleanSet = function(obj, compares){
7
+ var copy = can.extend({}, obj);
8
+ for(var prop in copy) {
9
+ var compare = compares[prop] === undefined ? compares["*"] : compares[prop];
10
+ if( same(copy[prop], undefined, compare ) ) {
11
+ delete copy[prop]
12
+ }
13
+ }
14
+ return copy;
15
+ },
16
+ propCount = function(obj){
17
+ var count = 0;
18
+ for(var prop in obj) count++;
19
+ return count;
20
+ };
21
+
22
+ /**
23
+ * @class can.Object
24
+ * @parent can.util
25
+ *
26
+ * Object contains several helper methods that
27
+ * help compare objects.
28
+ *
29
+ * ## same
30
+ *
31
+ * Returns true if two objects are similar.
32
+ *
33
+ * can.Object.same({foo: "bar"} , {bar: "foo"}) //-> false
34
+ *
35
+ * ## subset
36
+ *
37
+ * Returns true if an object is a set of another set.
38
+ *
39
+ * can.Object.subset({}, {foo: "bar"} ) //-> true
40
+ *
41
+ * ## subsets
42
+ *
43
+ * Returns the subsets of an object
44
+ *
45
+ * can.Object.subsets({userId: 20},
46
+ * [
47
+ * {userId: 20, limit: 30},
48
+ * {userId: 5},
49
+ * {}
50
+ * ])
51
+ * //-> [{userId: 20, limit: 30}]
52
+ */
53
+ can.Object = {};
54
+
55
+ /**
56
+ * @function same
57
+ * Returns if two objects are the same. It takes an optional compares object that
58
+ * can be used to make comparisons.
59
+ *
60
+ * This function does not work with objects that create circular references.
61
+ *
62
+ * ## Examples
63
+ *
64
+ * can.Object.same({name: "Justin"},
65
+ * {name: "JUSTIN"}) //-> false
66
+ *
67
+ * // ignore the name property
68
+ * can.Object.same({name: "Brian"},
69
+ * {name: "JUSTIN"},
70
+ * {name: null}) //-> true
71
+ *
72
+ * // ignore case
73
+ * can.Object.same({name: "Justin"},
74
+ * {name: "JUSTIN"},
75
+ * {name: "i"}) //-> true
76
+ *
77
+ * // deep rule
78
+ * can.Object.same({ person : { name: "Justin" } },
79
+ * { person : { name: "JUSTIN" } },
80
+ * { person : { name: "i" } }) //-> true
81
+ *
82
+ * // supplied compare function
83
+ * can.Object.same({age: "Thirty"},
84
+ * {age: 30},
85
+ * {age: function( a, b ){
86
+ * if( a == "Thirty" ) {
87
+ * a = 30
88
+ * }
89
+ * if( b == "Thirty" ) {
90
+ * b = 30
91
+ * }
92
+ * return a === b;
93
+ * }}) //-> true
94
+ *
95
+ * @param {Object} a an object to compare
96
+ * @param {Object} b an object to compare
97
+ * @param {Object} [compares] an object that indicates how to
98
+ * compare specific properties.
99
+ * Typically this is a name / value pair
100
+ *
101
+ * can.Object.same({name: "Justin"},{name: "JUSTIN"},{name: "i"})
102
+ *
103
+ * There are two compare functions that you can specify with a string:
104
+ *
105
+ * - 'i' - ignores case
106
+ * - null - ignores this property
107
+ *
108
+ * @param {Object} [deep] used internally
109
+ */
110
+ var same = can.Object.same = function(a, b, compares, aParent, bParent, deep){
111
+ var aType = typeof a,
112
+ aArray = isArray(a),
113
+ comparesType = typeof compares,
114
+ compare;
115
+
116
+ if(comparesType == 'string' || compares === null ){
117
+ compares = compareMethods[compares];
118
+ comparesType = 'function'
119
+ }
120
+ if(comparesType == 'function'){
121
+ return compares(a, b, aParent, bParent)
122
+ }
123
+ compares = compares || {};
124
+
125
+ if(a instanceof Date){
126
+ return a === b;
127
+ }
128
+ if(deep === -1){
129
+ return aType === 'object' || a === b;
130
+ }
131
+ if(aType !== typeof b || aArray !== isArray(b)){
132
+ return false;
133
+ }
134
+ if(a === b){
135
+ return true;
136
+ }
137
+ if(aArray){
138
+ if(a.length !== b.length){
139
+ return false;
140
+ }
141
+ for(var i =0; i < a.length; i ++){
142
+ compare = compares[i] === undefined ? compares["*"] : compares[i]
143
+ if(!same(a[i],b[i], a, b, compare )){
144
+ return false;
145
+ }
146
+ };
147
+ return true;
148
+ } else if(aType === "object" || aType === 'function'){
149
+ var bCopy = can.extend({}, b);
150
+ for(var prop in a){
151
+ compare = compares[prop] === undefined ? compares["*"] : compares[prop];
152
+ if(! same( a[prop], b[prop], compare , a, b, deep === false ? -1 : undefined )){
153
+ return false;
154
+ }
155
+ delete bCopy[prop];
156
+ }
157
+ // go through bCopy props ... if there is no compare .. return false
158
+ for(prop in bCopy){
159
+ if( compares[prop] === undefined ||
160
+ ! same( undefined, b[prop], compares[prop] , a, b, deep === false ? -1 : undefined )){
161
+ return false;
162
+ }
163
+ }
164
+ return true;
165
+ }
166
+ return false;
167
+ };
168
+
169
+ /**
170
+ * @function subsets
171
+ * Returns the sets in 'sets' that are a subset of checkSet
172
+ * @param {Object} checkSet
173
+ * @param {Object} sets
174
+ */
175
+ can.Object.subsets = function(checkSet, sets, compares){
176
+ var len = sets.length,
177
+ subsets = [],
178
+ checkPropCount = propCount(checkSet),
179
+ setLength;
180
+
181
+ for(var i =0; i < len; i++){
182
+ //check this subset
183
+ var set = sets[i];
184
+ if( can.Object.subset(checkSet, set, compares) ){
185
+ subsets.push(set)
186
+ }
187
+ }
188
+ return subsets;
189
+ };
190
+ /**
191
+ * @function subset
192
+ * Compares if checkSet is a subset of set
193
+ * @param {Object} checkSet
194
+ * @param {Object} set
195
+ * @param {Object} [compares]
196
+ * @param {Object} [checkPropCount]
197
+ */
198
+ can.Object.subset = function(subset, set, compares){
199
+ // go through set {type: 'folder'} and make sure every property
200
+ // is in subset {type: 'folder', parentId :5}
201
+ // then make sure that set has fewer properties
202
+ // make sure we are only checking 'important' properties
203
+ // in subset (ones that have to have a value)
204
+
205
+ var setPropCount =0,
206
+ compares = compares || {};
207
+
208
+ for(var prop in set){
209
+
210
+ if(! same(subset[prop], set[prop], compares[prop], subset, set ) ){
211
+ return false;
212
+ }
213
+ }
214
+ return true;
215
+ }
216
+
217
+
218
+ var compareMethods = {
219
+ "null" : function(){
220
+ return true;
221
+ },
222
+ i : function(a, b){
223
+ return (""+a).toLowerCase() == (""+b).toLowerCase()
224
+ }
225
+ }
226
+
227
+
228
+ ;
229
+
230
+ var flatProps = function(a){
231
+ var obj = {};
232
+ for(var prop in a){
233
+ if(typeof a[prop] !== 'object' || a[prop] === null || a[prop] instanceof Date){
234
+ obj[prop] = a[prop]
235
+ }
236
+ }
237
+ return obj;
238
+ };
239
+
240
+ can.extend(can.Observe.prototype, {
241
+
242
+ /**
243
+ * @function can.Observe.prototype.backup
244
+ * @plugin can/observe/backup
245
+ * @parent can.Observe.backup
246
+ *
247
+ * `observe.backup()` backs up a [can.Observe] instance, so it can be restored later
248
+ * by calling [can.Observe.prototype.restore] or checked if it
249
+ * has changed with [can.Observe.prototype.isDirty]:
250
+ *
251
+ * var recipe = new can.Observe({
252
+ * name : 'Pancakes',
253
+ * ingredients : [{
254
+ * name : "eggs",
255
+ * amount : '1'
256
+ * }, {
257
+ * name : "flour",
258
+ * amount : '1 cup'
259
+ * }, {
260
+ * name : "milk",
261
+ * amount : '1 1/4 cup'
262
+ * }]
263
+ * });
264
+ *
265
+ * recipe.backup();
266
+ *
267
+ * @return {can.Observe} The observe instance
268
+ */
269
+ backup: function() {
270
+ this._backupStore = this._attrs();
271
+ return this;
272
+ },
273
+
274
+ /**
275
+ * @function can.Observe.prototype.isDirty
276
+ * @plugin can/observe/backup
277
+ * @parent can.Observe.backup
278
+ *
279
+ * `observe.isDirty([checkAssociations])` returns if the observe has changed since the last
280
+ * [can.Observe.prototype.backup] call. If there is no backup it will return false. If you pass
281
+ * true, _isDirty_ also checks if any child properties or [can.Model] associations have changed.
282
+ *
283
+ * var recipe = new can.Observe({
284
+ * name : 'Pancakes',
285
+ * ingredients : [{
286
+ * name : "eggs",
287
+ * amount : '1'
288
+ * }, {
289
+ * name : "flour",
290
+ * amount : '1 cup'
291
+ * }, {
292
+ * name : "milk",
293
+ * amount : '1 1/4 cup'
294
+ * }]
295
+ * });
296
+ *
297
+ * recipe.backup();
298
+ * // Change the attribute of a nested property
299
+ * recipe.attr('ingredients.0.amount', '2');
300
+ * recipe.isDirty() // -> false
301
+ * recipe.isDirty(true) // -> true
302
+ * recipe.attr('name', 'Eggcakes');
303
+ * recipe.isDirty() // -> true
304
+ *
305
+ * @param {Boolean} [checkAssociations] Whether nested objects should be checked or
306
+ * not. Defaults to false.
307
+ * @return {Boolean} true if there are changes,
308
+ * false if not or there is no backup
309
+ */
310
+ isDirty: function(checkAssociations) {
311
+ return this._backupStore &&
312
+ !can.Object.same(this._attrs(),
313
+ this._backupStore,
314
+ undefined,
315
+ undefined,
316
+ undefined,
317
+ !!checkAssociations);
318
+ },
319
+
320
+ /**
321
+ * @function can.Observe.prototype.restore
322
+ * @parent can.Observe.backup
323
+ *
324
+ * `observe.restore([restoreAssociations])` restores the observe to the state of the last time
325
+ * [can.Observe.prototype.backup] was called if [can.Observe.prototype.isDirty]
326
+ * returns true. If you pass true, _restore_ will also check and restore all nested properties
327
+ * and [can.Model] associations.
328
+ *
329
+ * var recipe = new can.Observe({
330
+ * name : 'Pancakes',
331
+ * ingredients : [{
332
+ * name : "eggs",
333
+ * amount : '1'
334
+ * }, {
335
+ * name : "flour",
336
+ * amount : '1 cup'
337
+ * }, {
338
+ * name : "milk",
339
+ * amount : '1 1/4 cup'
340
+ * }]});
341
+ *
342
+ * recipe.backup();
343
+ *
344
+ * // Change the attribute of a nested observe
345
+ * recipe.attr('ingredients.0.amount', '2');
346
+ * recipe.attr('name', 'Eggcakes');
347
+ * recipe.attr('name') // -> Eggcakes
348
+ * recipe.attr('ingredients.0.amount') // -> 2
349
+ * recipe.restore(true);
350
+ * recipe.attr('name') // -> Pancakes
351
+ * recipe.attr('ingredients.0.amount') // -> 1
352
+ *
353
+ * @param {Boolean} [restoreAssociations] Whether nested objects should also
354
+ * be restored or not. Defaults to false.
355
+ * @return {can.Observe} The observe instance
356
+ */
357
+ restore: function(restoreAssociations) {
358
+ var props = restoreAssociations ? this._backupStore : flatProps(this._backupStore)
359
+
360
+ if(this.isDirty(restoreAssociations)){
361
+ this._attrs(props);
362
+ }
363
+
364
+ return this;
365
+ }
366
+
367
+ })
368
+ })(this.can, this )