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.
- data/.gitignore +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/Rakefile +2 -0
- data/canjs-rails.gemspec +23 -0
- data/lib/canjs-rails.rb +1 -0
- data/lib/canjs/rails.rb +7 -0
- data/lib/canjs/rails/engine.rb +6 -0
- data/lib/canjs/rails/version.rb +6 -0
- data/vendor/assets/javascripts/can.construct.proxy.js +60 -0
- data/vendor/assets/javascripts/can.construct.super.js +44 -0
- data/vendor/assets/javascripts/can.control.plugin.js +245 -0
- data/vendor/assets/javascripts/can.control.view.js +88 -0
- data/vendor/assets/javascripts/can.fixture.js +1020 -0
- data/vendor/assets/javascripts/can.jquery.js +2995 -0
- data/vendor/assets/javascripts/can.jquery.min.js +52 -0
- data/vendor/assets/javascripts/can.observe.attributes.js +293 -0
- data/vendor/assets/javascripts/can.observe.backup.js +368 -0
- data/vendor/assets/javascripts/can.observe.delegate.js +359 -0
- data/vendor/assets/javascripts/can.observe.setter.js +58 -0
- data/vendor/assets/javascripts/can.observe.validations.js +374 -0
- data/vendor/assets/javascripts/can.view.modifiers.js +292 -0
- data/vendor/assets/javascripts/download_canjs.sh +15 -0
- metadata +108 -0
@@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(s,""").replace(ua,"'")},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 )
|